Fork me on GitHub

分页

  1. 分页的优点
    • 只查询一页,不用查询所有页!有利于提高效率.

2. 分页数据

  1. 页面的数据都是由 Servlet 传递过来的. Servlet 需要给页面提供
  2. 当前页: pageCode, 简写 pc
    • 如果页面没有传递当前页码, 那么 Servlet 默认是第一页, 否则,以页面传递的为准!
  3. 总页数: totalPages, 简写 tp
    • tp = 总记录数/每页记录数;
    • 总记录数: totalRecord, tr. 由 DAO 来获取, SELECT COUNT(*) FROM t_customer;
    • 每页记录数: 也称为业务数据或系统数据, 由我们自己来定义, 此处为 10 行;
  4. 当前页数据: beanList
  5. url : 用于保存查询条件

3. 数据传递

  • 我们需要把这些分页数据封装到一个 javaBean 中, 它就叫 PageBean.
public class PageBean<T>{
    private int pc;  // 当前页码,page Code
    //private int tp;  总页数, total page, 通过计算得到
    private int tr;  // 总记录数, total record
    private int ps;  // 每页记录数, page size
    private List<T> beanList;  //当前页的记录, T 是为了方便将来复用
    private String url; // 表示 url 后面的条件!

    public int getPc(){
        return pc;
    }
    public void setPc(int pc){
        this.pc = pc;
    }

    // tp 是计算出来的
    public void getTp(){
        int tp = tr/ps;
        // 如果有余数, 总页数+1
        return tr/ps==0 ? tp : tp+1;
    }

    public int getTr(){
        return tr;
    }
    public void setTr(int tr){
        this.tr = tr;    
    }

    public int getPs(){
        return ps;
    }
    public void setPs(int ps){
        this.ps = ps;
    }

    public List<T> getBeanList(){
        return beanList;
    }
    public void setBeanList(List<T> beanList){
        this.beanList = beanList;
    }

    public String getUrl(){
        return url;
    }
    public void setTr(String url){
        this.url = url;
    }

}

4. 分页数据在各层的处理

  1. 页面: 显示分页相关的链接们!
    • 页面需要给 Servlet 传递当前页码
  2. Servlet: 创建 PageBean 对象, 给 PageBean 所有的属性赋值, 然后传递给页面.
    • Servlet 需要给 DAO 传递当前页码,以及每页记录数.
  3. Service: 中转站
  4. DAO
    • 获取总记录数 tr: SELECT COUNT(*) t_customer;
    • 获取当前页数据 BeanList: SELECT * FROM t_customer LIMIT x,y; limit 方言
      其中, x 表示从第几行开始查询, y 表示查询多少行.
// CustomerServlet
    // 查询所有
    public String findAll(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException{

            // 使用 getPc 方法, 得到 pc
            int pc = getPc(request);

            // 给定 ps 的值, 每页10行
            int ps = 10;

            // 传递 pc, ps 给 service, 得到 PageBean
            PageBean<Customer> pb = customerService.findAll(pc,ps);

            // 保存到 request 域
            request.setAttribute("pb",pb);

            // 转发到 list.jsp
            return "f:/list.jsp";
    }

    // 从 request 域得到的 pc 为字符串, 需要转换成 int 类型
    private int getPc(HttpServletRequest request){
        String value = request.getParameter("pc");

        // 如果 pc 参数不存在, 说明 pc=1;
        // 如果 pc 参数存在, 转换成 int 类型
        if(value == null || value.trim().isEmpty()){
            return 1;
        }

        return Interger.parseInt(value);
    }

// CustomerService
    public PageBean<Customer> findAll(int pc, int ps){
        return customerDao.findAll(pc,ps);
    }

// CustomerDao
    public PageBean<Customer> findAll(int pc, int ps){
        try{

            PageBean<Customer> pb = new PageBean<Customer>();

            // 设置 pb 的 pc 和 ps的值
            pb.setPc(pc);
            pb.setPs(ps);

            // 得到 tr
            String sql = "SELECT COUNT(*) FROM t_customer";

            Number num = (Number)qr.query(sql, new ScalarHandler());

            int tr = num.intValue();
            pb.setTr(tr);

            // 得到 BeanList
            sql = "SELECT * FROM t_customer order by cname LIMIT ?,?";

            List<Customer> beanList = qr.query(sql,
                            new BeanListHandler<Customer>(Customer.class),
                            (pc-1)*ps,ps);

            pb.setBeanList(beanList);
            return pb;
        }catch(SQLException e){
            throw new RuntimeException(e);
        }
    }

// list.jsp
    <body>
        <h3 align="center">客户列表</h3>
        <table border="1" width="70" align="center">
            <tr>
                <th>姓名</th>
                <th>性别</th>
                <th>生日</th>
                <th>手机</th>
                <th>邮箱</th>
                <th>邮箱</th>
                <th>操作</th>
            </tr>

            <c:forEach items="${pb.beanList }" var = "cstm">
            <tr>
                <td>${cstm.cname }</td>
                <td>${cstm.gender }</td>
                <td>${cstm.birthday }</td>
                <td>${cstm.cellphone }</td>
                <td>${cstm.email }</td>
                <td>${cstm.description }</td>
                <td>
           <a href="<c:url value='/CustomerServlet?method=preEdit&cid=${cstm.cid }'/>">编辑</a>
            <a href="<c:url value='/CustomerServlet?method=delete&cid=${cstm.cid }'/>">删除</a>
                </td>
            </tr>
            </c:froEach>
        </table>
        <br/>

        <%--给出分页相关的链接 --%>
        <center>
            第${pb.pc}页/共${pb.tp}页
            <a href="<c:url value='/CustomerSevlet?method=findAll&pc=1'/>">首页</a>
            <c:if test="${pb.pc > 1}">
            <a href="<c:url value='/CustomerServlet?method=findAll?pc=${pb.pc-1}'/>">上一页</a>
            </c:if>
            <c:if test="${pb.pc < pb.tp}">
            <a href="<c:url value='/CustomerServlet?method=findAll?pc=${pb.pc+1}'/>">下一页</a>
            </c:if>
            <a href="<c:url value='/CustomerServlet?method=findAll?pc=${pb.tp}'/>">尾页</a>
        </center>
    </body>

5. 分页的页码列表

5.1 需要关注的参数
  • 最多显示多少个页码, 定为 10 页;
  • 当前页, 在页码列表中的位置, 即居中显示, 定位 6;
5.2 如何来确定页码列表
  • 需要当前页码, begin, end 三样数据.
5.3 计算公式
  • 如果总页数 <= 10(列表长度), 那么 begin = 1, end = 总页数;
  • 使用公式计算: begin = pc -5, end = pc + 4;
  • 头溢出: 当 begin < 1 时, 让 begin = 1;
  • 尾溢出: 当 end > ${tp} 时, 让 end = ${tp};
// list.jsp
    <body>

        <br/>
        <center>
            第${pb.pc}页/共${pb.tp}页
            <a href="<c:url value='/CustomerSevlet?method=findAll&pc=1'/>">首页</a>
            <c:if test="${pb.pc > 1}">
            <a href="<c:url value='/CustomerServlet?method=findAll?pc=${pb.pc-1}'/>">上一页</a>
            </c:if>

            <%-- 计算 begin 和 end --%>
            <c:choose>
                <%-- 如果总页数不足 10 页, 那么把所有的页数都显示出来! --%>
                <c:when test="${pb.tp <= 10}">
                    <c:set var="begin" value="1"/>
                    <c:set var="end" value="${pb.tp}"/>
                </c:when>
                <c:otherwise>
                    <%-- 当总页数 > 10 时, 通过公式计算出 begin 和 end --%>
                    <c:set var = "begin" value="${pb.pc - 5}"/>
                    <c:set var = "end" value="{pb.pc + 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.tp}">
                        <c:set var="begin" value="${pb.tp-9}"/>
                        <c:set var="end" value="${pb.tp }"/>
                    </c:if>
                </c:otherwise>
            </c:choose>

            <%-- 循环遍历页码列表 --%>
            <c:forEach var="i" begin="${begin}" end="${end}">
                <c:choose>
                    <c:when test="${i eq pb.pc}">
                        [${i }]
                    </c:when>
                    <c:otherwise>
                        <a href="<c:url value='/CustomerServlet?method=findAll&pc=${i}'/>">[${i}]</a>
                    </c:otherwise>
                </c:choose>
            </c:forEach>

            <c:if test="${pb.pc < pb.tp}">
            <a href="<c:url value='/CustomerServlet?method=findAll?pc=${pb.pc+1}'/>">下一页</a>
            </c:if>
            <a href="<c:url value='/CustomerServlet?method=findAll?pc=${pb.tp}'/>">尾页</a>            
        </center>
    </body>

6. 在超链接中保留参数

  • 当使用多条件查询时, 在点击第 2 页时, 这个第 2 页超链接没有条件了, 所以会丢失条件,
    我们需要在页码上的所有链接都要保留条件!!
  • 要保留的条件以一个字符串的形式保存到 PageBean 的 url 中, 这个操作交给 Servlet 处理.
// CutomerServlet
    public String query(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException{

        // 把条件封装到 Customer 对象中
        Customer criteria = CommonUtils.toBean(request.getParameterMap(),Customer.class);

        // 得到 pc
        int pc = getPc(request);

        int ps = 10;

        // 使用 pc, ps 以及条件对象, 调用 service 方法得到 PageBean
        PageBean<Customer> pb = customerService.query(criteria, pc, ps);

        // 保存 url 到 pb
        pb.setUrl(gerUrl(request));

        // 保存到 request 域
        request.setAttribute("pb",pb);

        // 转发到 list.jsp
        return "f:/list.jsp";
    }

    // 截取 url
    //  request 域中的 url :  /项目名/Servlet 路径?参数字符串
    // 请求方式更改为 get 请求
    private String getUrl(HttpServletRequest request){
            String contextPath = request.getContextPath();
            String servletPath = request.getServletPath();
            String queryString = request.getQueryString();

            // 判断是否存在 pc, 存在的话, 需要去掉
            if(queryString.contains("&pc=")){
                int index = queryString.lastIndexOf("&pc=");
                queryString = queryString.substring(0,index);
            }

            return contextPath + servletPath +"?"+ queryString;
    }


// CustomerService
    public PageBean<Customer> query(Customer criteria, int pc, int ps){
        return customerDao.query(criteria, pc, ps);
    }

// customerDao
    public PageBean<Customer> query(Customer criteria, int pc, int ps){

        // 创建 pageBean 对象
        PageBean<Customer> pb = new PageBean<Customer>();

        // 设置 pc 和 ps
        pb.setPc(pc);
        pb.setPs(ps);

        // 得到 tr

        // 查询 tr 的 sql 语句前缀
        StringBuilder cntSql = new StringBuilder("SELECT COUNT(*) FROM t_customer");
        StringBuilder whereSql = new StringBuilder(" WHERE 1=1");

        // 创建一个 ArrayList, 用来装载参数
        List<Object> params = new ArrayList<Object>();

        String cname = criteria.getCanem();
        if(cname != null && !cname.trim().isEmpty()){
            whereSql.append(" AND cname like ?");
            params.add("%" + cname + "%");
        }

        String gender = criteria.getGender();
        if(gender != null && !gender.trim().isEmpty()){
            whereSql.append(" AND gender=?");
            params.add(gender);
        }

        String cellphone = criteria.getCellphone();
        if(cellphone != null && !cellphone.trim().isEmpty()){
            whereSql.append(" AND cellphone like ?");
            params.add("%" + cellphone + "%");
        }

        String email = criteria.getEmail();
        if(email != null && !email.trim().isEmpty()){
            whereSql.append(" AND email like ?");
            params.add("%"+ email + "%");
        }

        Number num = (Number)qr.query(cntSql.append(whereSql).toString(),
                                new ScalarHandler(),params.toArray());
        int tr = num.intValue();
        pb.setTr(tr);

        // 得到 beanList
        StringBuilder sql = new StringBuilder("SELECT * FROM t_customer");
        StringBuilder limitSql = new StringBuilder(" LIMIT ?,?");
        params.add((pc-1)*ps);
        params.add(ps);

        List<Customer> beanList =
                             qr.query(sql.append(whereSql).append(limitSql).toString(),
                            new BeanListHandler<Customer>(Customer.class), 
                            params.toArray());

        pb.setBeanList(beanList);

        return pb;
    }

// list.jsp
    <body>
        <center>
            第${pb.pc}页/共${pb.tp}页
            <a href="${pb.url }&pc=1">首页</a>
            <c:if test="${pb.pc > 1}">
            <a href="${pb.url }&pc=${pb.pc-1}">上一页</a>
            </c:if>
            <c:if test="${pb.pc < pb.tp}">
            <a href="${pb.url}&pc=${pb.pc+1}">下一页</a>
            </c:if>
            <a href="${pb.url }&pc=${pb.tp}">尾页</a>
        </center>        
    </body>

参考资料:

posted @ 2017-10-06 22:10  小a的软件思考  阅读(269)  评论(0编辑  收藏  举报