zoukankan      html  css  js  c++  java
  • 网页分页功能的实现

    最近在学习JavaWeb的时候,用到了分页功能,现在进行一个记录,以备不时之需

    第一步:先完成PageBean的编写

    就是对当前页数,每页显示的记录数,总记录数,总页数,分页显示的信息进行封装。作为通用的分页功能的实现,这里用到了泛型

    import java.util.List;
    
    /**
     * 分页封装
     *
     */
    public class PageBean<T> {
        
        private int currPage;//当前页数
        
        private int pageSize;//每页显示记录数
        
        private int totalCount;//总记录数
        
        private int totalPage;//总页数
        
        private List<T> list;//每页显示的信息 
    
        public int getCurrPage() {
            return currPage;
        }
    
        public void setCurrPage(int currPage) {
            this.currPage = currPage;
        }
    
        public int getPageSize() {
            return pageSize;
        }
    
        public void setPageSize(int pageSize) {
            this.pageSize = pageSize;
        }
    
        public int getTotalCount() {
            return totalCount;
        }
    
        public void setTotalCount(int totalCount) {
            this.totalCount = totalCount;
        }
    
        public int getTotalPage() {
            return totalPage;
        }
    
        public void setTotalPage(int totalPage) {
            this.totalPage = totalPage;
        }
    
        public List<T> getList() {
            return list;
        }
    
        public void setList(List<T> list) {
            this.list = list;
        }
    
    }

    第二步:在Action类中编写一个分页方法

    Action中通过调用业务层Service类的分页方法,Employee就是具体的信息Bean,之前泛型的使用就在于此,在不同项目中使用不同的信息Bean可以完成多种类信息的分页,employeeService就是具体的业务层Service,Service中我们也有一个叫findAll的方法。这里的currPage生成其set/get方法,等用户点击了页面及具体的页数,Struts2会获得具体的页数,然后将currPage传给Service

        // 分页(当前页)这里等于1是为了使第一页为默认页
        private int currPage = 1;
        public int getCurrPage() {
            return currPage;
        }
    
        public void setCurrPage(int currPage) {
            this.currPage = currPage;
        }
       /**
         * 分页查询
         */
        public String findAll() {
            PageBean<Employee> pageBean = employeeService.findAll(currPage);
            ActionContext.getContext().getValueStack().push(pageBean);
            return "findAll";
        }

    第三步:编写Service中的分页方法

    先生成一个PageBean对象(注意泛型),之后开始封装这个Bean。pageSize(每页显示的记录数)这里设置为3,就是每页显示3条记录,totalCount(总记录数)通过Dao中的findCount()方法来查到,totalPage(总页数)=totalCount(总记录数)/pageSize(每页大小),Math.ceil可以获得一个double的近似值(大于等于),之后我们通过Double包装类的intValue再转成int型,begin(每一页的开头的序号),list的数据也通过Dao的findPage(int,int)方法获得

    public PageBean<Employee> findAll(int currPage) {
            PageBean<Employee> pageBean = new PageBean<>();
            // 封装pageBean
            pageBean.setCurrPage(currPage);
            int pageSize = 3;
            pageBean.setPageSize(pageSize);
            int totalCount = employeeDao.findCount();
            pageBean.setTotalCount(totalCount);
            Double totalPage = Math.ceil((double) totalCount / pageSize);
            pageBean.setTotalPage(totalPage.intValue());
            int begin = (currPage - 1) * pageSize;
            List<Employee> list = employeeDao.findPage(begin, pageSize);
            pageBean.setList(list);
            return pageBean;
        }

    第四步:编写Dao中的方法

    这之前在Service中使用的findCount()和findPage(int,int),值得注意的就是findCount()中的hql语句使用count(*),还有就是findPage(int,int)中使用了org.hibernate.criterion.DetachedCriteria类,查询时不是用find方法,而是findByCriteria来查询

       /**
         * 查询总记录数
         */
        public int findCount() {
            String hql="select count(*) from Employee";
            List<Long> list = (List<Long>) hibernateTemplate.find(hql);
            if(list.size()>0){
                return list.get(0).intValue();
            }
            return 0;
        }
    
    
        /**
         * 分页信息
         */
        public List<Employee> findPage(int begin, int pageSize) {
            DetachedCriteria criteria=DetachedCriteria.forClass(Employee.class);
            List<Employee> list = (List<Employee>) hibernateTemplate.findByCriteria(criteria, begin, pageSize);
            return list;
        }

    基本上通过以上四步就完成了分页功能逻辑代码的编写,接下来就是对视图层页面的编写

    下面是个分页的简单显示,处于首页时,只显示下一页和尾页,处于尾页时,只显示首页和上一页,其他页就都显示。这里使用的Struts2的标签库,所以不要忘了要加上

    <%@ taglib uri="/struts-tags" prefix="s" %>

    为什么我们可以直接currPage,totalPage等属性?是因为我们之前将PageBean对象放入了值栈中

    <table border="0" cellspacing="0" cellpadding="0"  width="900px">
    <tr>
    <td align="right">
       <span><s:property value="currPage"/>/<s:property value="totalPage"/></span>&nbsp;&nbsp;
       <span>总记录数:<s:property value="totalCount"/>/每页显示:<s:property value="pageSize"/></span>&nbsp;&nbsp;
       <span>
       <s:if test="currPage!=1">
           <a href="department_findAll.action?currPage=1">[首页]</a>&nbsp;&nbsp;
           <a href="department_findAll.action?currPage=<s:property value="currPage-1"/>">[上一页]</a>&nbsp;&nbsp;
       </s:if>  
       <s:if test="currPage!=totalPage">
           <a href="department_findAll.action?currPage=<s:property value="currPage+1"/>">[下一页]</a>&nbsp;&nbsp;
           <a href="department_findAll.action?currPage=<s:property value="totalPage"/>">[尾页]</a>&nbsp;&nbsp;
       </s:if>  
       </span>
    </td>
    </tr>
    </table>

    效果图:

    可以使用了struts2的<s:iterator>标签来进行迭代显示数据,这里给个参考

    <s:iterator value="list" var="d">
    <tr>
    <td align="center"><s:property value="#d.dname"/></td>
    <td align="center"><a href="">编辑</a></td>
    <td align="center"><a href="">删除</a></td>
    </tr>
    </s:iterator>

     注意:一定要在Struts.xml文件中配置转跳到我们编写的action上(在这里是department_findAll.action),不然打开要分页的页面时,不会进行分页操作,只有你选择了页数才会分页

    后记

    我在使用的过程中发现,要使用分页功能的地方不少,在某些地方,使用上面的会出错:例如对条件查询之后的结果进行分页,第一页很OK,但是你点击下一页/某一页的时候会出现查询条件的丢失问题,再进行的查询结果分页是没有条件的,就会出错

    解决办法(我使用Servlet+JDBC实现的,原理是一样的):

    在我们的POJO中添加一个url属性,表示查询条件,因为POST方式条件是放在请求头中的,很不方便,所以再进行条件查询的的表单使用GET方式:

    <form action="<c:url value='/customerServlet'/>" method="get">

    我们需要获得这个url(包括项目名+Servlet名+条件),获得这个url封装到POJO中

    改进后的PageBean:

    import java.util.List;
    
    public class PageBean<T> {
        //当前页
        private int currPage;
        //每页记录数
        private int pageSize;
        //总记录数
        private int totalCount;
        //数据集合
        private List<T> list;
        //url表示条件查询的条件(GET方式)
        private String url;
    
        public int getCurrPage() {
            return currPage;
        }
    
        public void setCurrPage(int currPage) {
            this.currPage = currPage;
        }
    
        public int getPageSize() {
            return pageSize;
        }
    
        public void setPageSize(int pageSize) {
            this.pageSize = pageSize;
        }
    
        public int getTotalCount() {
            return totalCount;
        }
    
        public void setTotalCount(int totalCount) {
            this.totalCount = totalCount;
        }
    
        //设置总页数(计算得出)
        public int getTotalPage() {
            Double totalPage=Math.ceil((double)totalCount/pageSize);
            return totalPage.intValue();
        }
    
        public List<T> getList() {
            return list;
        }
    
        public void setList(List<T> list) {
            this.list = list;
        }
    
        public String getUrl() {
            return url;
        }
        
        public void setUrl(String url) {
            this.url = url;
        }
    }

    控制层要添加的方法(encoding()方法根据情况添加):

        /**
         * 得到包含查询的条件URL
         */
        private String getURL(HttpServletRequest request){
            String contextPath=request.getContextPath();  //项目名
            String servletPath=request.getServletPath();  //servlet路径,即/*Servlet   建议使用request.getRequestURI()获得一个包含项目名+Servlet的路径
            String queryString=request.getQueryString();  //?后面的参数
            //判断参数中是否带当前页(currPage)
            if(queryString.contains("&currPage=")){
                int index=queryString.lastIndexOf("&currPage=");
                queryString=queryString.substring(0, index);
            }
            return contextPath+servletPath+"?"+queryString;
        }
        
        /**
         *对(这里是4个条件)条件进行编码(GET方式防止中文乱码,POST方式已经在BaseServlet中配置) 
         * @throws UnsupportedEncodingException 
         *
         */
        private Customer encoding(Customer customer) throws UnsupportedEncodingException{
            String cname=customer.getCname();
            String gender=customer.getGender();
            String cellPhone=customer.getCellphone();
            String email=customer.getEmail();
            if(cname!=null&&!cname.isEmpty()){
               // cname=new String(cname.getBytes("ISO-8859-1"),"UTF-8");    //tomcat8之前tomcat默认字符编码使用是ISO-8859-1
                cname=new String(cname.getBytes(),"UTF-8");         
                customer.setCname(cname);
            }
            if(gender!=null&&!gender.isEmpty()){
                //gender=new String(gender.getBytes("ISO-8859-1"),"UTF-8");  
                gender=new String(gender.getBytes("ISO-8859-1"),"UTF-8");
                customer.setCname(gender);
            }
            if(cellPhone!=null&&!cellPhone.isEmpty()){
                //cellPhone=new String(cellPhone.getBytes("ISO-8859-1"),"UTF-8");
                cellPhone=new String(cellPhone.getBytes(),"UTF-8");
                customer.setCname(cellPhone);
            }
            if(email!=null&&!email.isEmpty()){
                //email=new String(email.getBytes("ISO-8859-1"),"UTF-8");
                email=new String(email.getBytes(),"UTF-8");
                customer.setCname(email);
            }
            return customer;
        } 

    这个geturl()方法就是获得url的方法,我用来表示当前页的变量使用的是currPage,根据实际情况更换。encoding()方法是处理get方式获得的条件中文乱码问题,如果项目使用tomcat8之后的服务器就不用转码了。注意:现在是所有的查询的方法的需要使用geturl()方法,并将返回值封装到POJO中。使用request.getRequestURI()方法也可以获得Struts2中Action的地址。使用框架开发应该就不用考虑encoding()这个编码方法,只需要处理geturl()方法了

    多条件查询的Servlet方法:

        /**
         * 多条件查询
         */
        public String query(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //获得查询条件
            Customer customer=CommonUtils.toBean(request.getParameterMap(), Customer.class);
            //处理GET请求的编码格式
            //customer = encoding(customer);              因为我的tomcat是8.5,所以就不转码了
            //处理PageBean
            int pageSize=10;         //每页记录数为10
            int currPage=getCurrentPage(request);
            int begin=(currPage-1)*pageSize;         //计算每页的开头
            PageBean<Customer> pageBean=customerService.query(customer,begin,pageSize);
            //封装当前页和每页记录数
            pageBean.setCurrPage(currPage);
            pageBean.setPageSize(pageSize);
            //封装url
            pageBean.setUrl(getURL(request));
            //将pageBean保存request
            request.setAttribute("pb", pageBean);
            return "f:/list.jsp";
        }

    注意:因为这种方式的页码算是使用的超连接,所以currPage可能会被恶意输入,需要验证一下,这里粘一个使用正则验证是否是数字的方法(其实不仅仅要验证是否为数字,还应该验证当前页不要大于总页数,也不要小于1):

        /**
         * 使用正则验证输入的是否为数字
         * @param string
         * @return
         */
        public static boolean isNum(String string) {
            Pattern pattern=Pattern.compile("[1-9]{1}\\d*");
            Matcher matcher = pattern.matcher(string);
            return matcher.matches();
        }

    Dao中多条件查询:

    /**
         * 多条件查询
         * 
         */
        public PageBean<Customer> query(Customer customer, int begin, int pageSize) {
            try {
                PageBean<Customer> pageBean=new PageBean<Customer>();
                
                /**
                 * 根据条件查询出总记录数
                 * 拼sql语句
                 */
                StringBuilder cntSql=new StringBuilder("select count(*) from t_customer");
                StringBuilder whereSql=new StringBuilder(" where 1=1");
                List<Object> params=new ArrayList<Object>();
                
                String cname=customer.getCname();
                if(cname!=null&&!cname.trim().isEmpty()){
                    whereSql.append(" and cname like ?");
                    params.add("%"+cname+"%");
                }
                
                String gender=customer.getGender();if(gender!=null&&!gender.trim().isEmpty()){
                    whereSql.append(" and gender=?");
                    params.add(gender);
                }
                
                String phone=customer.getCellphone();
                if(phone!=null&&!phone.trim().isEmpty()){
                    whereSql.append(" and cellphone like ?");
                    params.add("%"+phone+"%");
                }
                
                String email=customer.getEmail();
                if(email!=null&&!email.trim().isEmpty()){
                    whereSql.append(" and email like ?");
                    params.add("%"+email+"%");
                }
                //运行sql
                Number count=(Number) qr.query(cntSql.append(whereSql).toString(), new ScalarHandler(),params.toArray());
                pageBean.setTotalCount(count.intValue());
    
                
                /**
                 * 根据条件查询出每页数据
                 */
                StringBuilder listSql=new StringBuilder("select * from t_customer");
                //limit子句分页
                StringBuilder limitSql=new StringBuilder(" order by cname limit ?,?");
                //添加这两个参数
                params.add(begin);
                params.add(pageSize);
                //运行sql
                List<Customer> beanList=qr.query(listSql.append(whereSql).append(limitSql).toString(), 
                        new BeanListHandler<Customer>(Customer.class),
                        params.toArray());
                pageBean.setList(beanList);
                return pageBean;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

    我还是使用的是拼接sql的方式,与众不同的是分页中使用的count语句limit语句都是带where条件的

     在页面中也需要进行相应的修改(我这里使用的是JSTL):

    第${pb.currPage }页/共${pb.totalPage }页
    <c:if test="${pb.currPage>1 }">
    <a href="${pb.url }&currPage=1">首页</a>
    <a href="${pb.url }&currPage=${pb.currPage-1 }">上一页</a>
    </c:if>

    <c:if test="${pb.currPage<pb.totalPage }"> <a href="${pb.url }&currPage=${pb.currPage+1 }">下一页</a> <a href="${pb.url }&currPage=${pb.totalPage }">尾页</a> </c:if>

    pb就是我放在request中的pageBean的名字,注意url需要我们从pageBean的url中取出,页面只关心当前页,不去关心路径到底是什么

    一个页码的实现

    可能说一个页码又什么好实现的,直接把所有页数写出来,都加上超链接不就好了,但是观察百度等有页码的网站,你会发现页面是会随着页数变换的,比如说:先显示10页,但是当你点击第7页的时候,第1页应该隐藏,第11页应该出现,只有出现11页我们才能点击,这就是要实现的功能

    <%-- 页码 --%>
    <c:choose>
    <%-- 总页数小于等于10页,把所有页显示 --%>
      <c:when test="${pb.totalPage<=10 }">
        <c:set var="begin" value="1"/>
        <c:set var="end" value="${pb.totalPage }"/>
      </c:when>
      <c:otherwise>
        <%--总页数>10,计算begin和end  --%>
        <c:set var="begin" value="${pb.currPage-5 }"/>
        <c:set var="end" value="${pb.currPage+4 }"/>
        <%--处理头溢出  --%>
        <c:if test="${begin<1 }">
          <c:set var="begin" value="1"/>
          <c:set var="end" value="10"/>
        </c:if>
        <%-- 处理尾溢出 --%>
        <c:if test="${end>pb.totalPage }">
          <c:set var="begin" value="${pb.totalPage-9 }"/>
          <c:set var="end" value="${pb.totalPage }"/>
        </c:if>
      </c:otherwise>
    </c:choose>
    <c:forEach begin="${begin }" end="${end }" var="i">
      <c:choose>
       <c:when test="${i eq pb.currPage }">
         [${i }]
       </c:when>
       <c:otherwise>
         <a href="${pb.url }&currPage=${i }">[${i }]</a>
       </c:otherwise>
      </c:choose>
    </c:forEach>

    这是一个显示10页,点击第7页后,1页消失11页出现,点击8页后,2页消失12页出现,以此类推

    效果图(这是我把页码放在上一页和下一页之间的效果):

  • 相关阅读:
    Junit单元测试
    win7的6个网络命令
    WOJ1024 (POJ1985+POJ2631) Exploration 树/BFS
    WOJ1022 Competition of Programming 贪心 WOJ1023 Division dp
    woj1019 Curriculum Schedule 输入输出 woj1020 Adjacent Difference 排序
    woj1018(HDU4384)KING KONG 循环群
    woj1016 cherry blossom woj1017 Billiard ball 几何
    woj1013 Barcelet 字符串 woj1014 Doraemon's Flashlight 几何
    woj1012 Thingk and Count DP好题
    woj1010 alternate sum 数学 woj1011 Finding Teamates 数学
  • 原文地址:https://www.cnblogs.com/lz2017/p/6660109.html
Copyright © 2011-2022 走看看