web应用实现简单的分页功能

  在web应用中展示查询结果一般都需要使用分页功能,使用分页我们可以每次只查出当前页的数据,从而减小每次请求的数据量。mysql可以使用limit方言,oracle可以使用rownum来实现与limit相同的效果。如果数据总量不是特别大的话也可以将所有结果全部查出来,然后对结果进行截取,这种情况下一般使用ArrayList来接受结果集,保证取出的顺序和存入的数据一致。

  分页的时候有几个关键的属性需要在servlet、service、dao层中进行传输,其中需要从前端页面传入的属性包括当前页码、每页记录条数以及查询条件参数,需要从dao层返回的属性有总记录条数、当前页的数据(总页数可计算得出)。所以一般讲这些关键属性都封装在javaBean中,用javaBean来接收和传递分页的关键参数。

1、查询全部结果进行分页

public class PageBean<T> {
    private int pc;//当前页码
    //private int tp;//总页数
    private int tr;//总条数
    private int ps;//每页条数
    private List<T> pageList;//当前页的数据
    private String url;//请求的url和参数
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public int getTp(){ //获取总页数,总页数不设置属性的原因是只能从查询的结果中进行计算获取总页数
        int tp = tr /ps;
        return tr%ps==0 ? tp : tp+1;
    }
    public int getPc() {
        return pc;
    }
    public void setPc(int pc) {
        this.pc = pc;
    }
    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> getPageList() {
        return pageList;
    }
    public void setPageList(List<T> pageList) {
        this.pageList = pageList;
    }
}

这里也封装了一个url属性,这个属性是在复用显示分页结果的页面时会用到。因为我们的结果展示页面可能会被多个查询发放使用,所以在结果页面的请求url必须是动态的,url中还必须带上查询的条件,因为第一次分页查询的时候可能会有一些过滤条件,在我们通过点击“下一页”之类的超链接时也需要将初始查询参数带上。

首页:

<html>
  <head>
  </head>
  <body style="text-align: center;">
    <h1>分页示例</h1>
    <a href="<c:url value='/CustomerServlet?method=findAll'/>" >查询人员</a>  
    <a href="<c:url value='/query.jsp'/>">带条件的分页</a>  
  </body>
</html>

servlet:

    public String findAll(HttpServletRequest request,HttpServletResponse response) throws Exception {
        int pc = getPc(request);
        int ps = ConfigUtil.getPc();
        String url = getUrl(request);
        PageBean<Customer> page = customerService.findAll(pc,ps);
        page.setUrl(url);
        System.out.println(url);
        request.setAttribute("pb", page);
        return "/list.jsp";
    }
    public int getPc(HttpServletRequest request){
        String pc = request.getParameter("pc");
        return pc==null|| pc.trim().isEmpty()?1:Integer.parseInt(pc);
    }
    public String getUrl(HttpServletRequest request){
        String url = request.getRequestURI();
        String params = request.getQueryString();
        if(params.indexOf("&pc")!=-1){//url中所有初始参数保留,除了需要跳转的页码数,每次请求时都不同,这里因为我们的应用pc总是最后一个参数,所以可以直接截取掉pc参数
            params = params.substring(0, params.indexOf("&pc"));
        }
        return url+"?"+params;
    }

这里ConfigUtil.getPc()是从配置文件中获取每页的条数。也有许多web应用在前端页面上可以改变每页的记录条数,那么就要将这里ps改成从request中获取。

public class ConfigUtil {
    private static Properties prop = null;
    static {
        /*
         * 加载配置文件
         * 只在JdbcUtils类被加载时执行一次
         */
        InputStream in = ConfigUtil.class.getClassLoader().getResourceAsStream("com//leo//customer//config//config.properties");
         prop = new Properties();
        try {
            prop.load(in);
        } catch (IOException e) {
            throw new RuntimeException();
        }
    }
    public static int getPs(){
        return Integer.parseInt(prop.getProperty("pagesize")) ;
    }
}

service:

package com.leo.customer.service;

import java.sql.SQLException;
import java.util.List;

import com.leo.customer.dao.CustomerDao;
import com.leo.customer.domain.Customer;
import com.leo.customer.domain.PageBean;
import com.leo.customer.jdbc.JdbcUtils;

public class CustomerService {
    private CustomerDao dao = new CustomerDao();
    //分页查询全部
    public  PageBean<Customer> findAll(int pc ,int ps) throws SQLException{
        return dao.findAll(pc,ps);
    }

}

dao:

package com.leo.customer.dao;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.dbutils.handlers.ScalarHandler;

import com.leo.customer.domain.Customer;
import com.leo.customer.domain.PageBean;
import com.leo.customer.jdbc.TxQueryRunner;
import com.leo.customer.util.BeanHandler;
import com.leo.customer.util.BeanListHandler;

public class CustomerDao {
    private TxQueryRunner qr = new TxQueryRunner();
    
    //分页查询全部
    public PageBean<Customer> findAll(int pc,int ps) throws SQLException{
        PageBean<Customer> pb = new PageBean<Customer>();
        pb.setPc(pc);
        pb.setPs(ps);
        String sql = "select count(1) from t_customer";
        Number n = (Number) qr.query(sql, new ScalarHandler());
        pb.setTr(n.intValue());
        sql = "select * from t_customer order by cid limit ?,?";
        Object[] params = {(pc-1)*ps,ps};
        List<Customer> list = qr.query(sql, new BeanListHandler<Customer>(Customer.class), params);
        pb.setPageList(list);
        return pb;
    }
}

这里TxQueryRunner是QueryRunner的扩展类,结合JdbcUtil类做的事务处理,这里因为是查询操作,所以可以不用关注事务。dao层中调用TxQueryRunner的方法代码为

public <T> T query(String sql, ResultSetHandler<T> rsh) throws SQLException {
        Connection con = JdbcUtils.getConnection();
        T result = super.query(con, sql, rsh);
        JdbcUtils.releaseConnection(con);
        return result;
    }
public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params)
            throws SQLException {
        Connection con = JdbcUtils.getConnection();
        T result = super.query(con, sql, rsh, params);
        JdbcUtils.releaseConnection(con);
        return result;
    }

如果不需要进行事务处理,这里完全可以使用QueryRunner来进行查询。

查询显示页面:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>客户列表</title>
    
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>
  
  <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="${requestScope.pb.pageList}" 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:forEach>
</table>
<br/>
<c:choose>
    <c:when test="${pb.tp<=10 }">
            <c:set var="begin" value="1"></c:set>
            <c:set var="end" value="${pb.tp }"></c:set>
    </c:when>
    <c:otherwise>
            <c:set var="begin" value="${pb.pc-5}"></c:set>
            <c:set var="end" value="${pb.pc+4}"></c:set>
            <c:if test="${begin <1 }">
                <c:set var ="begin" value="1"></c:set>
                <c:set var = "end" value="10"></c:set>
            </c:if>
            <c:if test="${end >pb.pc }">
                <c:set var ="begin" value="${ pb.tp-9}"></c:set>
                <c:set var = "end" value="${pb.tp }"></c:set>
            </c:if>
        <c:if test=""></c:if>
    </c:otherwise>
</c:choose>
<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:forEach var="i"  begin="${begin }" end="${end }">
        <c:choose>
            <c:when test="${i eq pb.pc }">
                <span style="color:red">[${ i}]</span>
            </c:when>
            <c:otherwise>
                <a href="${pb.url}&pc=${ i}">[${ i}]</a>
            </c:otherwise>
        </c:choose>
    </c:forEach>
    <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>
    <span></span>
    <input type="text" id="topc" name="topc" style="width:30px" onblur="toPage()">
    <input type="hidden" id="tp"    value="${pb.tp }" >
    <input type="hidden" id="url"  value="${pb.url }" >
    <span></span>
    <a onclick="fnToPage()" href="#">跳转</a>
</center>
  </body>
  <script type="text/javascript">
          function toPage(){
              var topage = document.getElementById("topc").value;
              var tp = document.getElementById("tp").value;
              if(topage>tp || topage < 1){
                  alert("页码有误,请输入1到"+tp+"之间的整数");
              }
          }
          function fnToPage(){
              var topage = document.getElementById("topc").value;
              var url = document.getElementById("url").value;
              if(topage==""||topage==null){
                  alert("请输入要跳转的页面");
                  return;
              }
              href = url+"&pc="+topage;
              window.location = href;
          }
  </script>
</html>

最终效果:

2、根据条件查询进行分页

  从首页进入到query.jsp:

  

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>高级搜索</title>
    
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->
  </head>
  
  <body>
<h3 align="center">高级搜索</h3>
<form action="<c:url value='/CustomerServlet'/>" method="get">
    <input type="hidden" name="method" value="query"/>
<table border="0" align="center" width="40%" style="margin-left: 100px;">
    <tr>
        <td width="100px">客户名称</td>
        <td width="40%">
            <input type="text" name="cname"/>
        </td>
    </tr>
    <tr>
        <td>客户性别</td>
        <td>
            <select name="gender">
                <option value="">==请选择性别==</option>
                <option value="男"></option>
                <option value="女"></option>
            </select>
        </td>
    </tr>
    <tr>
        <td>手机</td>
        <td>
            <input type="text" name="cellphone" />
        </td>
        <td>
            <label id="cellphoneError" class="error" >&nbsp;${ cellphoneError}</label>
        </td>        
    </tr>
    <tr>
        <td>邮箱</td>
        <td>
            <input type="text" name="email" value="${email}"/>
        </td>
        <td>
            <label id="emailError" class="error">&nbsp;${ emailError}</label>
        </td>    
    </tr>
    <tr>
        <td>&nbsp;</td>
        <td>
            <input type="submit" value="搜索"/>
            <input type="reset" value="重置"/>
        </td>
        <td>&nbsp;</td>
    </tr>
</table>
</form>
  </body>
</html>

输入条件进行过滤查询。这里为了简单起见使用了get方法进行提交,因为我们要将查询的url(包含参数)保存到request中,使用get方法我们在servlet中可以直接使用getQueryString来获取查询参数字符串,如果使用post需要手动拼接。

在servlet中编写query方法:

public String query(HttpServletRequest request,HttpServletResponse response) throws SQLException{
        String cname = request.getParameter("cname");
        String gender = request.getParameter("gender");
        String cellphone = request.getParameter("cellphone");
        String email = request.getParameter("email");
        if(cellphone!=null &&cellphone.length()>15){
            
            request.setAttribute("cellphoneError", "手机号过长");
            return "/query.jsp";
        }
        if(email!=null && email!=""){
            if(email.length()>40||email.indexOf("@")<0){
                request.setAttribute("emailError", "邮箱格式错误");
                request.setAttribute("email", email);
                return "/query.jsp";
            }
        } 
        int pc = getPc(request);
        int ps = ConfigUtil.getPs();
        String url = getUrl(request);
        System.out.println(url);
        PageBean<Customer> page = customerService.query(cname,gender,cellphone,email,pc,ps);
        page.setUrl(url);
        request.setAttribute("pb", page);
         return "/list.jsp";
    }

service:

public PageBean<Customer> query(String cname,String gender,String cellphone,String email,int pc,int ps) throws SQLException{
        return dao.query(cname,gender,cellphone,email,pc,ps);
    }

dao:

public PageBean<Customer> query(String cname,String gender,String cellphone,String email,int pc,int ps) throws SQLException{
        String sql = "select * from t_customer where 1=1  ";
        List params = new ArrayList();
        if(cname.length()>0){
            sql += "and cname = ?  ";
            params.add(cname);
        }
        if(gender.length()>0){
            sql += "and gender = ? ";
            params.add(gender);
        }
        if(cellphone.length()>0){
            sql += "and cellphone = ? ";
            params.add(cellphone);
        }
        if(email.length()>0){
            sql += "and email = ? ";
            params.add(email);
        }
        PageBean<Customer> page = new PageBean<Customer>();
        page.setPc(pc);
        page.setPs(ps);
        List<Customer> list = qr.query(sql,  new BeanListHandler<Customer>(Customer.class),params.toArray());
        if(list==null)
            list = new ArrayList<Customer>();
        page.setTr(list.size());
        int toindex = pc*ps;
        if(toindex>list.size()){
            toindex = list.size();
        }
        page.setPageList(list.subList((pc-1)*ps, toindex));
        return  page;
    }

这里没有使用mysql的limit方言,而是直接根据页码和每页记录数对结果集进行截取处理。

getUrl方法确保了即使我们在页面上点击下一页或者跳转某一页,我们的请求url中的参数始终不变,初始化查询性别为男,在页面上不论如何点击页码跳转,url中都会有性别参数为男。唯一变化的参数是请求跳转的页码,所以在getUrl方法中将参数pc截取掉了。

查询性别为男的人员:

 至此,简单的分页功能已经实现了。

 项目源代码下载:http://download.csdn.net/detail/qq_32403887/9844098

posted @ 2017-05-16 22:31  封尘寒剑  阅读(4758)  评论(0编辑  收藏  举报