-
分页基本概述
-
什么是分页查询?
- 将数据按页分配,每一页显示固定数量的数据
-
为什么使用分页查询?
- 利于页面布局,且显示的效率高!!
-
两种分页实现方式:
-
物理分页:
- 使用数据库的分页功能,一次只查询一页数据;
-
逻辑分页:
- 一次查出全部数据,然后由程序控制取出需要的数据;
-
物理分页:
-
什么是分页查询?
-
分页关键点
- 分页SQL语句;
- 后台处理: dao/service/servlet/JSP
-
物理分页的功能设计
-
PageCustomer分页对象:
- pageIndex(从1开始)
- pageSize(每页多少条数据)
- totalSize(总共多少条)
- totalPage(总共多少页)
- List<Customer>(这页的数据)
-
点击第2页连接,把pageIndex=2发送给Servlet
- Servlet调用service
- service执行分页业务,调用dao
- dao进行数据库分页操作,返回Page分页对象
-
PageCustomer分页对象:
-
实现步骤
-
环境准备
-
引入jar文件及引入配置文件
- 数据库驱动包
- C3P0连接池jar文件 及 配置文件
-
DbUtis组件:
- 公用类: JdbcUtils.java
-
引入jar文件及引入配置文件
- 先设计:PageBean.java
- Dao接口设计/实现: 2个方法
- Service/servlet
- JSP
-
环境准备
-
示例1
- 表示分页的domain
public classPageCustomer{ private intpageIndex;//第几页 private intpageSize;//每页的数据 private inttotalSize;//一共有多少数据 private inttotalPage;//一共多少页 privateList<Customer>customerList;//查询页的数据 publicPageCustomer(intpageIndex,intpageSize) { if(pageIndex< 1) { this.pageIndex=1; }else{ this.pageIndex=pageIndex; } if(pageSize< 1) { this.pageSize=1; }else{ this.pageSize=pageSize; } } //get,set略 } |
- 分页Servlet
public class PageCustomerServletextends HttpServlet{ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ this.doPost(request, response); }
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ response.setContentType("text/html");
try{ int pageIndex= 1;//当前第几页 int pageSize= 10;//每页的数据 String pageIndexStr= request.getParameter("pageIndex"); String pageSizeStr= request.getParameter("pageSize"); //为了程序健壮性和容错性,如果 request.getParameter("pageIndex"); //没有查到数据,那么还有默认值int pageIndex = 1; //如果查到了数据,就直接用查到的数据,替代默认值 try{ pageIndex= Integer.parseInt(pageIndexStr); pageSize= Integer.parseInt(pageSizeStr); }catch(Exception e) {
}
//以当前页和每页的数据构造出一个分页类 PageCustomer pageCustomer=new PageCustomer(pageIndex, pageSize); //以这个分页类为参数,传递给DAO,获取这个页数的数据集合 ObjectFactory.getCustomerService().page(pageCustomer); //将页数,和该页的数据个数传递给JSP request.setAttribute("pageCustomer", pageCustomer); //将存放有该页面的人员信息集合,传递给JSP端 request.setAttribute("customerList",pageCustomer.getCustomerList()); //数据查询完毕之后,就跳转到分页显示页面 request.getRequestDispatcher("pageCustomer.jsp").forward(request,response); }catch(Exception e) { response.getWriter().print("分页查询出错:"+ e.getMessage()); } } } |
- 工厂类,快速获取Service对象
public class ObjectFactory{ private static DataSource dataSource; private static CustomerService customerService; private static CustomerDao customerDao; static{ dataSource=new ComboPooledDataSource(); customerService=new CustomerService(); customerDao=new CustomerDaoImpl(); } public static DataSource getDataSource() { return dataSource; } public static CustomerService getCustomerService() { return customerService; } public static CustomerDao getCustomerDao() { return customerDao; } } |
- 后台Service
public class CustomerService{ /** *将Servlet传递来的有关于分页查询的数据传递给DAO * *@param pageCustomer */ public void page(PageCustomer pageCustomer)throws Exception{ ObjectFactory.getCustomerDao().page(pageCustomer); } } |
- 接口DAO
public interface CustomerDao{ void page(PageCustomer pageCustomer)throws SQLException; } |
- 实现DAO的实现类
public class CustomerDaoImplimplements CustomerDao{ /** *根据Servlet传递来的分页数据,在数据库中进行分页查找 */ public void page(PageCustomer pageCustomer)throws SQLException{ //mysql的分页语法:select * from customer limit begin,size; //先执行分页语句查询,获取当前页,和该页有多少数据 int begin=(pageCustomer.getPageIndex()- 1)* pageCustomer.getPageSize()+ 1; QueryRunner run=new QueryRunner(ObjectFactory.getDataSource());
List<Customer> customer= run.query("select * from customer limit ?,?" ,new BeanListHandler<Customer>(Customer.class) ,begin ,pageCustomer.getPageSize());
pageCustomer.setCustomerList(customer);
//使用聚合函数查看一共有多少数据 long totalSize= run.query("select count(*) from customer",new ScalarHandler<Long>()); pageCustomer.setTotalSize((int) totalSize);
/*根据全部的数据来分页.用当前全部数据(totalSize)乘以每页数据(PageSize),来获取需要分多少页 但是除法会舍去余数,所以我们加上一个9,比如我们有99条数据,应该是分10,前9页是每页10条,最后一页是9条 加上一个9就是108条数据,其中9条是空的。这样除以10(也就是每页10条数据),就分了10,舍去了余数8,也就得到了最后一页只有9个数据的效果,每页20条数据就减去19。也就是说,我们的总数据需要加上(PageSize-1)条数据。这里只能加9,结果加8,如果总数据的余数是1,则凑不够一页。如果加10,又多了一页空白页*/ int totalPage=( pageCustomer.getTotalSize() + pageCustomer.getPageSize() - 1) / pageCustomer.getPageSize();
pageCustomer.setTotalPage(totalPage); } } |
- 实例分页JSP
<div> <ahref="PageCustomerServlet?pageIndex=1&pageSize=10">首页</a> <!--分页条,如果当前页数不为1的话才会显示上一页的选项 --> <c:iftest="${pageCustomer.pageIndex!=1}"> <ahref="PageCustomerServlet?pageIndex=${pageCustomer.pageIndex-1 }&pageSize=10">上一页</a> </c:if> <%//根据分页类对分页条动态添加一个页数链接 PageCustomer pageCustomer=(PageCustomer)request.getAttribute("pageCustomer");//获得分页类 int pageIndex=pageCustomer.getPageIndex();//获得当前页 int begin=pageIndex-3;//当前页减去一个数字,就是当前页前面的页数 if(begin<1){//如果前面的页数小于1,就让它等于1 begin=1; } int end=pageIndex+2; if(end>pageCustomer.getTotalPage()){ end=pageCustomer.getTotalPage(); } //根据开始页和结束页来循环动态添加页数 for(int i=begin;i<=end;i++){ //如果循环到的页数与当前页相等,说明用户正在当前页,就直接输出一个数组,而不是链接 if(i==pageIndex){ out.print(i); }else{ %> <ahref="PageCustomerServlet?pageIndex=<%= i%>&pageSize=10"><%= i%></a> <% } } %> <c:iftest="${pageCustomer.pageIndex!=pageCustomer.totalPage}"> <ahref="PageCustomerServlet?pageIndex=${pageCustomer.pageIndex+1 }&pageSize=10">下一页</a> </c:if> <ahref="PageCustomerServlet?pageIndex=${pageCustomer.totalPage }&pageSize=10">尾页</a> </div> </div> |
-
示例2
- 工具类
/** *工具类 * 1.初始化C3P0连接池 * 2.创建DbUtils核心工具类对象 */ public class JdbcUtils{ /** * 1.初始化C3P0连接池 */ private static DataSource dataSource; static{ dataSource=new ComboPooledDataSource(); } /** * 2.创建DbUtils核心工具类对象 */ public static QueryRunner getQueryRuner(){ //创建QueryRunner对象,传入连接池对象 //在创建QueryRunner对象的时候,如果传入了数据源对象; //那么在使用QueryRunner对象方法的时候,就不需要传入连接对象; //会自动从数据源中获取连接(不用关闭连接) returnnew QueryRunner(dataSource); } } |
- 封装分页的参数
/** *封装分页的参数 */ public class PageBean<T>{ private int currentPage= 1;//当前页,默认显示第一页 private int pageCount= 4;//每页显示的行数(查询返回的行数),默认每页显示4行 private int totalCount;//总记录数 private int totalPage;//总页数 =总记录数 / 每页显示的行数 (+ 1) private List<T> pageData;//分页查询到的数据 //返回总页数 public int getTotalPage() { if(totalCount% pageCount == 0) { totalPage= totalCount/ pageCount; }else{ totalPage= totalCount/ pageCount + 1; } return totalPage; } //get,set,构造函数略 } |
- domain类
/** * 1.实体类设计 (因为用了DbUtils组件,属性要与数据库中字段一致) */ public class Employee{ private int empId;//员工id private String empName;//员工名称 private int dept_id;//部门id //get,set略 } |
- dao
//2.数据访问层,接口设计 public interface IEmployeeDao{ /** *分页查询数据 */ public void getAll(PageBean<Employee> pb); /** *查询总记录数 */ public int getTotalCount(); } |
- dao实现类
/** * 2.数据访问层实现 */ public class EmployeeDaoimplements IEmployeeDao{ @Override public void getAll(PageBean<Employee> pb) { //2.查询总记录数;设置到pb对象中 int totalCount=this.getTotalCount(); pb.setTotalCount(totalCount); /* *问题: jsp页面,如果当前页为首页,再点击上一页报错! *如果当前页为末页,再点下一页显示有问题! *解决: * 1.如果当前页 <= 0;当前页设置当前页为1; * 2.如果当前页 >最大页数;当前页设置为最大页数 */ //判断 if(pb.getCurrentPage()<=0) { pb.setCurrentPage(1);//把当前页设置为1 }else if(pb.getCurrentPage()> pb.getTotalPage()){ pb.setCurrentPage(pb.getTotalPage());//把当前页设置为最大页数 } //1.获取当前页: 计算查询的起始行、返回的行数 int currentPage= pb.getCurrentPage(); int index=(currentPage-1)* pb.getPageCount();//查询的起始行 int count= pb.getPageCount();//查询返回的行数 //3.分页查询数据;把查询到的数据设置到pb对象中 String sql="select * from employee limit ?,?"; try{ //得到Queryrunner对象 QueryRunner qr= JdbcUtils.getQueryRuner(); //根据当前页,查询当前页数据(一页数据) List<Employee> pageData= qr.query(sql,new BeanListHandler<Employee>(Employee.class), index, count); //设置到pb对象中 pb.setPageData(pageData); }catch(Exception e) { throw new RuntimeException(e); } } @Override public int getTotalCount() { String sql="select count(*) from employee"; try{ //创建QueryRunner对象 QueryRunner qr= JdbcUtils.getQueryRuner(); //执行查询, 返回结果的第一行的第一列 Long count= qr.query(sql,new ScalarHandler<Long>()); return count.intValue(); }catch(Exception e) { throw new RuntimeException(e); } } } |
- service接口层
//3.业务逻辑层接口设计 public interface IEmployeeService{ /** *分页查询数据 */ public void getAll(PageBean<Employee> pb); } |
- service实现层
//3.业务逻辑层,实现 public classEmployeeServiceimplementsIEmployeeService { //创建Dao实例 privateIEmployeeDaoemployeeDao= new EmployeeDao(); @Override public voidgetAll(PageBean<Employee>pb) { try{ employeeDao.getAll(pb); }catch(Exceptione) { throw newRuntimeException(e); } } } |
- Servlet
/** * 4.控制层开发 */ public class IndexServletextends HttpServlet{ //创建Service实例 private IEmployeeService employeeService=new EmployeeService(); //跳转资源 private String uri; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ try{ //1.获取"当前页"参数; (第一次访问当前页为null) String currPage= request.getParameter("currentPage"); //判断 if(currPage==null ||"".equals(currPage.trim())){ currPage="1";//第一次访问,设置当前页为1; } //转换 int currentPage= Integer.parseInt(currPage); //2.创建PageBean对象,设置当前页参数; 传入service方法参数 PageBean<Employee> pageBean=new PageBean<Employee>(); pageBean.setCurrentPage(currentPage); //3.调用service employeeService.getAll(pageBean);//【pageBean已经被dao填充了数据】 //4.保存pageBean对象,到request域中 request.setAttribute("pageBean", pageBean); //5.跳转 uri="/WEB-INF/list.jsp"; }catch(Exception e) { e.printStackTrace();//测试使用 //出现错误,跳转到错误页面;给用户友好提示 uri="/error/error.jsp"; } request.getRequestDispatcher(uri).forward(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ this.doGet(request, response); } } |
- JSP
<html> <head> <title>分页查询数据</title> <metahttp-equiv="pragma"content="no-cache"> <metahttp-equiv="cache-control"content="no-cache"> <metahttp-equiv="expires"content="0"> </head>
<body> <tableborder="1"width="80%"align="center"cellpadding="5"cellspacing="0"> <tr> <td>序号</td> <td>员工编号</td> <td>员工姓名</td> </tr> <!--迭代数据 --> <c:choose> <c:whentest="${not emptyrequestScope.pageBean.pageData}"> <c:forEachvar="emp"items="${requestScope.pageBean.pageData}"varStatus="vs"> <tr> <td>${vs.count }</td> <td>${emp.empId }</td> <td>${emp.empName }</td> </tr> </c:forEach> </c:when> <c:otherwise> <tr> <tdcolspan="3">对不起,没有你要找的数据</td> </tr> </c:otherwise> </c:choose>
<tr> <tdcolspan="3"align="center"> 当前${requestScope.pageBean.currentPage }/${requestScope.pageBean.totalPage }页
<ahref="${pageContext.request.contextPath }/index?currentPage=1">首页</a> <ahref="${pageContext.request.contextPath }/index?currentPage=${requestScope.pageBean.currentPage-1}">上一页</a> <ahref="${pageContext.request.contextPath }/index?currentPage=${requestScope.pageBean.currentPage+1}">下一页</a> <ahref="${pageContext.request.contextPath }/index?currentPage=${requestScope.pageBean.totalPage}">末页</a> </td> </tr> </table> </body> </html> |
- web.xml
<servlet> <servlet-name>IndexServlet</servlet-name> <servlet-class>cn.itcast.servlet.IndexServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>IndexServlet</servlet-name> <url-pattern>/index</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> |