为什么需要分页
用户使用的时候可以根据自己需要获取对应记录,记录数的多少出现不可控,有可能查询出来数据过多;为了避免一次性加载过多的数据,造成系统资源的浪费,甚至严重的性能问题等…,这时加载数据需要分页加载。
分页实现
设计与实现
1.查询数据需要分页。 2.一个系统可以对多种类型数据进行查询,设计时尽可能考虑通用性;查询用户需要对用户进行分页,查询商品需要对商品进行分页,…设计时尽可能的能同时满足不同的查询需要。
设计一个专门用来针对分页相关功能的类(对象) 定义变量: currentPage 当前页 Integer pageSize 一页显示几条数据 Integer totalRecord 总记录数 Integer totalPage 总页数 Integer list 显示的列表数据 List query 查询条件 一个条件用String,多个用泛型,跨表用HashMap
sql设计(Oracle)
--假如一页显示三条数据,查询第二页 select * from (select rownum rn,t.* from user t where rownum<=6) where rn>3; --第二页数据是从第三行开始,显示三行,所以rownum<=6,rn>3 --我们可以得出结论 select * from (select rownum rn,t.* from user t where rownum<=?) where rn>?; --第一个? pageSize*currentPage 显示行数*当前页面 --第二个? pageSize*(currentPage-1) 显示行数*当前页面减一分页实例
假如数据库有一个用户表user,有字段name,pwd,15条数据。
新建一个web项目,导入相关jar包 创建分页实体类PageBean
import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Map; public class PageBean<T> implements Serializable { /* currentPage 查询的当前页 pageSize 页面大小 totalPage 总页数 totalRecord 总记录数 list 显示的列表数据 queryObject 查询条件 。。。 select * from (select rownum rn ,t.* from tt12 t where rownum<8) where rn>4; */ private Integer currentPage = 1;//查询的当前页 可以从页面获取 这里定义初始化值 private Integer pageSize = 10;//页面大小 页面获取 private Integer totalRecord;//总记录数 可以从数据库查询 private Integer totalPage;//总页数 通过计算 private Map<String, Object> otherQuery = new HashMap<String, Object>();//其它查询条件,预留,可以从页面获取 private T queryObject; //针对本类型的查询条件 可以从页面获取 private List<T> list; //数据列表,可以从数据库查询 public Integer getCurrentPage() { return currentPage; } public void setCurrentPage(Integer currentPage) { this.currentPage = currentPage; } public Integer getPageSize() { return pageSize; } public void setPageSize(Integer pageSize) { this.pageSize = pageSize; } public Integer getTotalPage() { //自己完成总页数的计算 if (totalRecord % pageSize == 0) { //5 21 totalPage = totalRecord / pageSize; } else { totalPage = totalRecord / pageSize + 1; } return totalPage; } public void setTotalPage(Integer totalPage) { this.totalPage = totalPage; } public Integer getTotalRecord() { return totalRecord; } public void setTotalRecord(Integer totalRecord) { this.totalRecord = totalRecord; } public Map<String, Object> getOtherQuery() { return otherQuery; } public void setOtherQuery(Map<String, Object> otherQuery) { this.otherQuery = otherQuery; } public T getQueryObject() { return queryObject; } public void setQueryObject(T queryObject) { this.queryObject = queryObject; } public List<T> getList() { return list; } public void setList(List<T> list) { this.list = list; } @Override public String toString() { return "PageBean [currentPage=" + currentPage + ", pageSize=" + pageSize + ", totalPage=" + totalPage + ", totalRecord=" + totalRecord + ", otherQuery=" + otherQuery + ", queryObject=" + queryObject + ", list=" + list + "]"; } }创建User实体类
import java.io.Serializable; public class User implements Serializable{ private String name; private String pwd; public String getName(){ return name; } public String setName(String name){ this.name=name } public String getPwd(){ return pwd; } public String setPwd(String pwd){ this.pwd=pwd } }创建数据库工具类BaseDaoUtil
创建业务类接口UserService
//接口定义方法 public PageBean<User> selectPage(PageBean<User> pageBean);创建业务类接口实现类UserServiceImpl
public class UserServiceImpl implements UserService { private Connection conn; private PreparedStatement pstmt; private ResultSet rs; @Override public PageBean<User> selectPage(PageBean<User> pageBean) { try { //rownum的开始数值为1,不是0。 //分页查询,第一占位符?表示该页最后一条,第二个占位符?表示上一页的最后一条 String sql = "select * from (select rownum rn ,c.* from user c where rownum<=?) where rn>?"; //该页最后一条记录(查询时包括该条记录) int end = pageBean.getPageSize()*pageBean.getCurrentPage(); //从上一页最后一条(不包括该条)记录开始 int start = pageBean.getPageSize()*(pageBean.getCurrentPage()-1); conn = BaseDaoUtil.getConnection(); pstmt = conn.prepareStatement(sql); pstmt.setInt(1,end); pstmt.setInt(2,start); rs = pstmt.executeQuery(); List<User> list = new ArrayList<User>();//用来存放查询的记录 User returnUser = null; while (rs.next()) { returnUser = new User(); returnUser.setName(rs.getString("name")); returnUser.setPwd(rs.getString("pwd")); list.add(returnUser);//把查询的对象存到列表里 } //把数据列表存放到pageBean pageBean.setList(list); BaseDaoUtil.closeRS(rs);//清理原来的资源 BaseDaoUtil.closeStatement(pstmt);//清理原来的资源 //查询总记录数 String sql2 = "select count(0) c from user"; pstmt = conn.prepareStatement(sql2); rs = pstmt.executeQuery(); if (rs.next()) { int count = rs.getInt("c"); //returnCustom.setCustomPwd(rs.getString("custom_pwd")); pageBean.setTotalRecord(count); } return pageBean; } catch (Exception e) { e.printStackTrace(); } finally { DaoUtil.close(rs, pstmt , conn); } return null; } }创建UserServlet
/** * Servlet implementation class CustomServlet */ @WebServlet("/CustomPageServlet") public class UserServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取页面传过来的当前页 String currentPage = request.getParameter("currentPage"); //因为从浏览器直接访问这个servlet时,没有相关的参数,所以为null,当为null,默认为查询和第一页 PageBean<User> pageBean = new PageBean<User>(); if(null!=currentPage){ //当不为null时,把当前页转为数字存到pageBean pageBean.setCurrentPage(Integer.parseInt(currentPage)); } //调用业务层的方法,查询分页的相关数据 UserService userService = new UserServiceImpl(); PageBean<User> returnPageBean = userService.selectPage(pageBean); //把pageBean放到request对象带回页面 request.setAttribute("pageBean", returnPageBean); //转发到列表页面 request.getRequestDispatcher("/index.jsp").forward(request, response); } }JSP页面显示
<%@page import="com.cn.webdemo.entity.User"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!--定义变量存储项目名--> <c:set var="base" value="${pageContext.request.contextPath }"></c:set> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>登陆窗口</title> </head> <body> <table border="1" cellpadding="5" cellspacing="0" width="80%" align="center"> <tr> <td>序号</td> <td>姓名</td> <td>密码</td> </tr> <!--下边的条件也可以用下一行代码代替,如果不指定requestScope对象,pageBean的属性将按本页、请求、会话、全局范围的顺序获取 test="${not empty requestScope.pageBean.list}"--> <c:if test="${not empty pageBean.list}"> <c:forEach var="user" items="${pageBean.list}" varStatus="cs"> <tr> <td>${cs.count}</td> <td>${user.name }</td> <td>${user.pwd }</td> </tr> </c:forEach> </c:if> <tr align="center"> <td colspan="4"> <!-- 分页页面处理: 1. 当前为第一页,所以首页和上一页不能再点击了,总页数为多页,那可以点击下一页和尾页 - 2. 当前页为最后一页,下一页和尾页不能点击;总页数为多页,那前面应该有具它页 ,可以点一页和首页 3. 当前页等于总页数,并且总页数不大于1(其实就是1或0),都不可以点 4。其它的情况都可以点 --> <c:choose> <c:when test="${pageBean.currentPage == 1 && pageBean.totalPage > 1}"> <!-- 当前为第一页,所以首页和上一页不能再点击了,总页数为多页,那可以点击下一页和尾页 --> 首页 上一页 <a href="${pageContext.request.contextPath }/CustomPageServlet?currentPage=${pageBean.currentPage+1}">下一页</a> <a href="${pageContext.request.contextPath }/CustomPageServlet?currentPage=${pageBean.totalPage}">尾页</a> </c:when> <c:when test="${pageBean.currentPage==pageBean.totalPage && pageBean.totalPage > 1}"> <!-- 当前页为最后一页,下一页和尾页不能点击;总页数为多页,那前面应该有具它页 ,可以点一页和首页--> <a href="${pageContext.request.contextPath }/CustomPageServlet?currentPage=1">首页</a> <a href="${pageContext.request.contextPath }/CustomPageServlet?currentPage=${pageBean.currentPage-1}">上一页</a> 下一页 尾页 </c:when> <c:when test="${pageBean.currentPage == pageBean.totalPage}"> <!--i当前页等于总页数,并且总页数不大于1(其实就是1或0) --> 首页 上一页 下一页 尾页 </c:when> <c:otherwise> <!-- 其它情况,都可以点击 --> <a href="${pageContext.request.contextPath }/CustomPageServlet?currentPage=1">首页</a> <a href="${pageContext.request.contextPath }/CustomPageServlet?currentPage=${pageBean.currentPage-1}">上一页</a> <a href="${pageContext.request.contextPath }/CustomPageServlet?currentPage=${pageBean.currentPage+1}">下一页</a> <a href="${pageContext.request.contextPath }/CustomPageServlet?currentPage=${pageBean.totalPage}">尾页</a> </c:otherwise> </c:choose> 当前${pageBean.currentPage }/${pageBean.totalPage }页 </td> </tr> </table> </body> </html>