Java Web之分页的实现(通用)
一、用到的工具类的封装
为了实现代码的重用性,我们将经常用到的代码封装到工具类中,以便在任何地方都可以调用
1、获取路径工具
在jsp页面中,我们经常会向Servlet发送请求,并通过反射,实现通过传递不同的参数,调用Servlet的对应方法
因此,我们在工具类中封装一个获取路径的方法,用于获取jsp页面的请求路径及相关参数
1 public static String getPath(HttpServletRequest request){ 2 String uri=request.getRequestURI(); //返回“项目名/请求Servlet名”的字符串 3 String quString=request.getQueryString(); //获取请求的参数部分 4 String path=uri+"?"+quString; //拼串,请求地址:项目名/servlet名?参数 5 if(path.contains("&pageNumber")){ 6 //截串,将没有用的参数截去,只留下用于反射的method参数 7 path=path.substring(0, path.indexOf("&pageNumber")); 8 } 9 return path; 10 }
二、后台分页的实现
1、bean层:
创建Page实体类:注意Page类要应用泛型,实现可重用
属性:
private List<T> list; //当前页列表数据,数据库查询得到
private int pageNumber; //当前页码,前端页面传递
private int totalRecord; //总记录数,数据库查询得到
private int pageSize; //每页显示条数,在Servlet中指定
//private int totalPage; //总页数,计算得到
//private int index; //当前页的起始索引,计算得到
private String path; //用来设置Servlet访问路径及method参数
方法:
各个属性对应的get、set方法以及getTotalPage()和getIndex()方法,用来计算总页数和索引值
1 public class Page<T> {
2 private List<T> list; //当前页列表数据,数据库查询得到
3 private int pageNumber; //当前页码,前端页面传递
4 private int totalRecord; //总记录数,数据库查询得到
5 private int pageSize; //每页显示条数,前端页面传递
6 //private int totalPage; //总页数,计算得到
7 //private int index; //当前页的起始索引,计算
8 private String path; //用来设置Servlet访问路径及method参数
9
10 public Page() {
11 super();
12 }
13
14 public Page(int pageNumber, int totalRecord, int pageSize) {
15 super();
16 this.pageNumber = pageNumber;
17 this.totalRecord = totalRecord;
18 this.pageSize = pageSize;
19 }
20
21 public List<T> getList() {
22 return list;
23 }
24 public void setList(List<T> list) {
25 this.list = list;
26 }
27 public int getPageNumber() { //控制页码不能<1,也不能>totalPage
28 if(pageNumber<1){
29 pageNumber=1;
30 }else if (pageNumber>getTotalPage()) {
31 pageNumber=getTotalPage();
32 }
33 return pageNumber;
34 }
35 public void setPageNumber(int pageNumber) {
36 this.pageNumber = pageNumber;
37 }
38 public int getTotalRecord() {
39 return totalRecord;
40 }
41 public void setTotalRecord(int totalRecord) {
42 this.totalRecord = totalRecord;
43 }
44 public int getPageSize() {
45 return pageSize;
46 }
47 public void setPageSize(int pageSize) {
48 this.pageSize = pageSize;
49 }
50 public int getTotalPage() {
51 return (int) Math.ceil((double)getTotalRecord()/getPageSize());
52 }
53 public int getIndex() {
54 return (getPageNumber()-1)*getPageSize(); //分页查询,在数据访问层一定会调用getIndex方法获得索引值
55 } //而在getIndex方法中调用了getPageNumber方法,保证了页码在正常范围内
56
57 public String getPath() {
58 return path;
59 }
60
61 public void setPath(String path) {
62 this.path = path;
63 }
64
65 }
2、Servlet层:
创建getPage(req,resp)方法,用来获取对应页码的数据并封装为Page类的对象
1)通过工具类获取请求路径
2)获取请求页码参数
3)调用Service层的getPage方法,获取请求页面的信息,并封装为Page类对象
4)设置Page类对象的path属性(访问路径)
5)通过request.setAttribute("page", page);将页面信息放入域中
6)将请求转发到页面
1 public void getPage(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{ 2 String path=WEBUtils.getPath(request); 3 String pageNumber=request.getParameter("pageNumber"); //获取页码 4 Page<Book> page=new Page<Book>(); 5 page=bookService.getPage(pageNumber,pageSize); //获取页面信息 6 page.setPath(path); //设置访问路径 7 request.setAttribute("page", page); //将页面信息放入域中 8 request.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(request, response); 9 }
3、Service层:
1)设置默认页码
2)pageNumber类型转换
3)获取总记录数
4)封装Page类对象
5)获取当前页的数据列表并封装到page中
1 public Page<Book> getPage(String pageNumber,int pageSize) {
2 int pageNo=1; //设置默认页码,当pageNumber类型转换出错时,会起作用,否则值被覆盖
3 Page<Book> page=null;
4
5 try {
6 //servlet层获取的参数类型为string,需要转换为整型
7 pageNo=Integer.parseInt(pageNumber);
8 } catch (Exception e) {
9 System.out.println("字符串转换出错");
10 }
11 //1.获取总记录数
12 int totalRecord=bookDao.getRecordsCount();
13 //2.封装page对象
14 page=new Page<Book>(pageNo, totalRecord, pageSize);
15 //3.查询当前页对应的数据列表并封装到page对象中
16 List<Book> list=bookDao.getPageList(page.getIndex(),pageSize);
17 page.setList(list);
18 return page;
19 }
4、Dao层:
1)访问数据库,查询数据库中总记录数
2)访问数据库,通过limit index,number 实现分页查询,得到请求页的数据列表
1 public int getRecordsCount() { 2 conn=JDBCUtils.getConnection(); 3 String sql="select count(*) as totalPage from book"; 4 PreparedStatement ps=null; 5 ResultSet rs=null; 6 int totalPage=0; 7 8 try { 9 ps=conn.prepareStatement(sql); 10 rs=ps.executeQuery(); 11 if(rs.next()){ 12 totalPage=rs.getInt("totalPage"); 13 } 14 }catch(SQLException e){ 15 e.printStackTrace(); 16 } finally { 17 JDBCUtils.closeStatement(rs, ps); 18 JDBCUtils.closeConnection(conn); 19 } 20 return totalPage; 21 }
1 public List<Book> getPageList(int index, int pageSize) { 2 conn=JDBCUtils.getConnection(); 3 String sql="select id,book_name,author,price,sales,stock,img_path,create_date,update_date,status" 4 + " from book limit ?,?"; 5 PreparedStatement ps=null; 6 ResultSet rs=null; 7 List<Book> list=new ArrayList<Book>(); 8 9 try { 10 ps=conn.prepareStatement(sql); 11 ps.setInt(1, index); 12 ps.setInt(2, pageSize); 13 rs=ps.executeQuery(); 14 while (rs.next()) { 15 list.add(createBook(rs)); 16 } 17 }catch(SQLException e){ 18 e.printStackTrace(); 19 }finally { 20 JDBCUtils.closeStatement(rs, ps); 21 JDBCUtils.closeConnection(conn); 22 } 23 return list; 24 }
三、前台分页的实现
为了实现分页的通用性,我们在这里将分页的代码封装到一个新的jsp页面中
只需要在其他的jsp页面中通过<%@include file="XXX"%>标签导入,就可以实现分页功能
注意:
1、jsp页面中所有请求servlet的路径都通过${page.path}&pageNumber=XXX的形式(page.path由请求动态获取路径信息,具有通用性)pageNumber表示请求页码
2、第一页不能再向上一页跳转、末页不能再想下一页跳转问题:通过在Page类的getPageNumber方法中限制页码的范围实现
3、通过<c:set></c:set>设置页码在页面中出现的范围
1.总页码<=5时,显示所有页数
2.总页码>5时:
当前页码<=3时:显示1~5页
当前页码>3时:显示当前页在中间的5页
4、通过<c:forEach></c:forEach>显示由begin到end的5个页面,当前页用【】标识
1 <div class="page">
2 <a href="${page.path}&pageNumber=1">首页</a>
3 <a href="${page.path}&pageNumber=${page.pageNumber-1}">上一页</a>
4 <!--
5 始终保证当前页在中间,一共显示5页
6 1.总页码<=5时,显示所有页数
7 2.总页码>5时:
8 当前页码<=3时:显示1~5页
9 当前页码>3时:显示当前页在中间的5页,当当前页为倒数前3页时,显示最后5页
10 -->
11 <c:choose>
12 <c:when test="${page.totalPage<=5}">
13 <c:set var="begin" value="1"></c:set>
14 <c:set var="end" value="${page.totalPage}"></c:set>
15 </c:when>
16 <c:when test="${page.pageNumber<=3}">
17 <c:set var="begin" value="1"></c:set>
18 <c:set var="end" value="5"></c:set>
19 </c:when>
20 <c:when test="${page.pageNumber>3}">
21 <c:set var="begin" value="${page.pageNumber-2}"></c:set>
22 <c:set var="end" value="${page.pageNumber+2}"></c:set>
23 <c:if test="${page.pageNumber+2>=page.totalPage}">
24 <c:set var="begin" value="${page.totalPage-4}"></c:set>
25 <c:set var="end" value="${page.totalPage}"></c:set>
26 </c:if>
27 </c:when>
28 </c:choose>
29 <!-- 通过循环显示由begin到end的5个页面,当前页用【】标识 -->
30 <c:forEach begin="${begin}" end="${end}" var="index">
31 <c:if test="${page.pageNumber==index}">
32 <a href="${page.path}&pageNumber=${index}">【${index}】</a>
33 </c:if>
34 <c:if test="${page.pageNumber!=index}">
35 <a href="${page.path}&pageNumber=${index}">${index}</a>
36 </c:if>
37 </c:forEach>
38
39 <a href="${page.path}&pageNumber=${page.pageNumber+1}">下一页</a>
40 第${page.pageNumber}页,共${page.totalPage}页
41 转到第<input id="setPage" type="text" value="${page.pageNumber}"/>页,<a id="goto" href="">跳转</a>
42 <a href="${page.path}&pageNumber=${page.totalPage}">末页</a>
43 <script type="text/javascript">
44 window.onload=function(){
45 var agoto=document.getElementById("goto");
46 agoto.onclick=function(){
47 var setPage=document.getElementById("setPage").value;
48 window.location="${page.path}&pageNumber="+setPage;
49 return false;
50 };
51 };
52 </script>
53 <!--或 <script type="text/javascript">
54 $(function(){
55 $("#goto").click(function(){
56 var $setPage=$("#setPage").val();
57 window.location="/MyBookStore/book?method=getPage&pageNumber="+$setPage;
58 return false;
59 });
60 });
61 </script> -->
62 </div>