课程表

Spring Boot课程

工具箱
速查手册

Boot JPA和自定义的分页

当前位置:免费教程 » Java相关 » Spring Boot
注意:本页面内容为W3xue原创,未经授权禁止转载,违者必究!
来源:W3xue  发布时间:2019/10/10 15:02:01

分页是现代Web应用程序中常用的功能,JPA其实提供了非常简便的分页功能。但是,在开发的时候,我们往往会发现JPA的分页过于臃肿,灵活性不佳,w3xue在这里提供了一种完全自定义的分页方式,供大家学习参考。首先,我们来看下JPA的分页功能。


一、JPA分页

JPA的分页使用非常简单,只需要2步即可。第1步,MainService接口中定义一个方法:

  1. Page<MainBean> findByJpaPage(int page, int size);

MainServiceImpl类中实现该方法:

  1. @Override
  2. public Page<MainBean> findByJpaPage(int page, int size){
  3.     return mainDao.findAll(PageRequest.of(page,size));
  4. }

根据需要,你必须引用这2个依赖包(IntelliJ IDEA 会帮你搞定):

  1. import org.springframework.data.domain.Page;
  2. import org.springframework.data.domain.PageRequest;

在更老的版本中,实现方法可能是这样的:

  1. @SuppressWarnings("unchecked") //强制类型转换,自定义SQL、自定义分页用
  2. public Page<MainBean> findByJpaPage(int page, int size){
  3.     PageRequest pageRequest = new PageRequest(page, size);
  4.     return mainDao.findAll(pageRequest);
  5. }

你会发现2点不同,一是使用@SuppressWarnings注解,让编译器忽略指定的警告;二是申明了一个实体,用这个实体作为参数传给JPA的自定义分页系统,而后来的版本中,是直接使用静态方法体返回一个PageRequest对象来做到这一点的,语法更简洁,实际上老版本的申明实体代码应该会被划上删除线,表明已经不受系统推荐了:PageRequest(page, size)

第2步,在MainRestController类加上一个新的路由和方法体:

  1. @GetMapping("/jpaPage")
  2. public JSONObject jpaPage(@RequestParam("page") int pPage, @RequestParam("size") int pSize){
  3.     Page<MainBean> studentPage =  mainServiceImpl.findByJpaPage(pPage, pSize);
  4.     JSONObject jsonObject = (JSONObject) JSON.toJSON(studentPage);
  5.     return jsonObject;
  6. }

然后重新启动项目,访问“http://localhost:8080/jiaocheng/jpaPage?page=0&size=2”,你会看到出现如下结果:

  1. {"number":0,"last":false,"numberOfElements":2,"size":2,"totalPages":2,"pageable":{"paged":true,"pageNumber":0,"offset":0,"pageSize":2,"unpaged":false,"sort":{"unsorted":true,"sorted":false,"empty":true}},"sort":{"unsorted":true,"sorted":false,"empty":true},"content":[{"parent_name":"张无忌","grade":"二年级","name":"张三","parent_mobilephone":"18899998888","id":1,"age":8,"studentClass":"三班"},{"parent_name":"李寻欢","grade":"五年级","name":"李四","parent_mobilephone":"17722338899","id":2,"age":11,"studentClass":"六班"}],"first":true,"empty":false,"totalElements":3}

我们使用JSON在线编辑器来整理一下:

  1. {
  2.     "number": 0,
  3.     "last": false,
  4.     "numberOfElements": 2,
  5.     "size": 2,
  6.     "totalPages": 2,
  7.     "pageable": {
  8.         "paged": true,
  9.         "pageNumber": 0,
  10.         "offset": 0,
  11.         "pageSize": 2,
  12.         "unpaged": false,
  13.         "sort": {
  14.             "unsorted": true,
  15.             "sorted": false,
  16.             "empty": true
  17.         }
  18.     },
  19.     "sort": {
  20.         "unsorted": true,
  21.         "sorted": false,
  22.         "empty": true
  23.     },
  24.     "content": [
  25.         {
  26.             "parent_name": "张无忌",
  27.             "grade": "二年级",
  28.             "name": "张三",
  29.             "parent_mobilephone": "18899998888",
  30.             "id": 1,
  31.             "age": 8,
  32.             "studentClass": "三班"
  33.         },
  34.         {
  35.             "parent_name": "李寻欢",
  36.             "grade": "五年级",
  37.             "name": "李四",
  38.             "parent_mobilephone": "17722338899",
  39.             "id": 2,
  40.             "age": 11,
  41.             "studentClass": "六班"
  42.         }
  43.     ],
  44.     "first": true,
  45.     "empty": false,
  46.     "totalElements": 3
  47. }

你可以看到,http://localhost:8080/jiaocheng/jpaPage?page=0&size=2”这个地址带了2个参数,一个是page,一个是size。page是从0开始的,0就是第1页,1就是第2页,以此类推,而size则是每页数据的多少,这里定义为2,因为迄今为止,我们只添加了3条测试信息。取到这个JSON数据后,前端就可以用来进行无刷新的分页制作了。

可以看出,JPA分页最大的优点是,太方便了,几行代码就搞定了分页,缺点大家也看到了,那一坨JSON数据,不整理一下简直没法看,臃肿不堪,很不灵活。


二、w3xue提供的自定义分页

我们在这里提供一个自定义分页的解决方案。其实,JPA的分页最终利用的也是MySql支持的“LIMIT”语法。我们在这里就利用这一点,搭建我们自定义的方案。本方案相对复杂,但搭建后,使用起来相对灵活。

第1步

我们在MainDao类添加一个自定义的方法体和HQL:

  1. @Query(value = "SELECT * FROM t_w3xue_student order by f_id desc LIMIT :start,:number", nativeQuery = true)
  2. public List<MainBean> getByW3xuePage(@Param("start") Integer start, @Param("number") Integer number);

第2步

我们在MainService接口中定义一个方法:

  1. String findByW3xuePage(int pageid, int size);

然后,在MainServiceImpl类中实现该方法:

  1. @Override
  2. public String findByW3xuePage(int pageid, int size) {
  3.     Integer nStart=(pageid-1)*size; //开始索引
  4.     StringBuilder sb=new StringBuilder();
  5.     try {
  6.         List<MainBean> stuData=mainDao.getByW3xuePage(nStart,size);
  7.         for (MainBean stu:stuData) {
  8.             sb.append("<li><strong>"+stu.getId() +"</strong>号学生:"+stu.getName()+",年级和班级:"+stu.getGrade()+" "+stu.getStudentClass()+",家长姓名:"+stu.getParent_name()+"</li>");
  9.         }
  10.     } catch (Exception e) {
  11.         sb.append("暂时没有数据");
  12.     }
  13.     return sb.toString();
  14. }

第3步

我们在程序代码主目录建一个新的“utils”文件夹,和“bean”、“controller”等平行,然后存放页码显示工具类PageUtil类

  1. package com.w3xue.jiaocheng.utils;
  2.  
  3. public class PageUtil {
  4.     //显示页码
  5.     public static String showPage(Integer datacount, int maxperpage, String wholepagename, String para, Integer nPage, Integer showlevel) {
  6.         int pageid = 1, dspage;
  7.         boolean pageidIsnum;
  8.         String rank_pageid = "", rank_pageid2 = "", action = "";
  9.         StringBuilder page_result = new StringBuilder();
  10.  
  11.         if (para.length() > 0)   //在使用分页时带上rank参数,如果无视rank,则注释掉这个模块,如需添加,在下面模块添加
  12.         {
  13.             rank_pageid = "?" + para;
  14.             rank_pageid2 = "&" + para;
  15.         }
  16.  
  17.         dspage = datacount % maxperpage != 0 ? (int) datacount / maxperpage + 1 : (int) datacount / maxperpage;
  18.  
  19.         if (nPage < 2)
  20.             pageid = 1;
  21.         else if (pageid > dspage) //页码大于总页数
  22.             pageid = dspage;
  23.         else
  24.             pageid = nPage;
  25.  
  26.         page_result.append("<b class=\"shenhui qianpageid\">记录数:" + datacount + " 页数:" + pageid + "/" + dspage + "</b>");
  27.  
  28.         if (pageid != 1 && showlevel < 4) {
  29.             page_result.append("<a class=\"pageid\" href=\"" + wholepagename + rank_pageid + "\" target=\"_self\">首页<a>");
  30.         }
  31.  
  32.  
  33.         if (pageid != 1 && pageid != 2) {
  34.             page_result.append("<a class=\"pageid\" href=\"" + wholepagename + "?pageid=" + (pageid - 1) + rank_pageid2 + "\" target=\"_self\">上一页<a>");
  35.         } else if (pageid == 2) {
  36.             page_result.append("<a class=\"pageid\" href=\"" + wholepagename + rank_pageid + "\" target=\"_self\">上一页<a>");
  37.         }
  38.  
  39.         int l;
  40.         if (pageid > dspage - 5) {
  41.             l = pageid - 5 - (4 - dspage + pageid);
  42.         } else {
  43.             l = pageid - 5;
  44.         }
  45.         if (< 1) {
  46.             l = 1;
  47.         }
  48.         while (< pageid && showlevel < 3) {
  49.             if (== 1) {
  50.                 page_result.append("<a class=\"pageid\" href=\"" + wholepagename + rank_pageid + "\" target=\"_self\">" + l + "</a>");
  51.             } else {
  52.                 page_result.append("<a class=\"pageid\" href=\"" + wholepagename + "?pageid=" + l + rank_pageid2 + "\" target=\"_self\">" + l + "</a>");
  53.             }
  54.             l = l + 1;
  55.         }
  56.  
  57.         if (showlevel < 3)
  58.             page_result.append("<b class=\"shenhui pageid dazi\">" + pageid + "</b>");
  59.  
  60.         if (showlevel < 3) {
  61.             int r = pageid + 1;
  62.             if (pageid < 6) {
  63.                 while (<= 10 && r <= dspage && pageid != dspage) {
  64.                     page_result.append("<a class=\"pageid\" href=\"" + wholepagename + "?pageid=" + r + rank_pageid2 + "\" target=\"_self\">" + r + "</a>");
  65.                     r = r + 1;
  66.                 }
  67.             } else {
  68.                 while (< (pageid + 5) && r <= dspage && pageid != dspage) {
  69.                     page_result.append("<a class=\"pageid\" href=\"" + wholepagename + "?pageid=" + r + rank_pageid2 + "\" target=\"_self\">" + r + "</a>");
  70.                     r = r + 1;
  71.                 }
  72.             }
  73.         }
  74.  
  75.  
  76.         if (pageid != dspage && datacount != 0) {
  77.             page_result.append("<a class=\"pageid\" href=\"" + wholepagename + "?pageid=" + (pageid + 1) + rank_pageid2 + "\" target=\"_self\">下一页<a>");
  78.         }
  79.         if (pageid != dspage && datacount != 0 && showlevel < 4) {
  80.             page_result.append("<a class=\"pageid\" href=\"" + wholepagename + "?pageid=" + dspage + rank_pageid2 + "\" target=\"_self\">尾页</a>");
  81.         }
  82.         if (showlevel < 2) {
  83.             page_result.append(" <input type=\"number\" placeholder=\"页码\" id=\"pageinput\" style=\"width:50px;height:22px;margin:5px 4px\">");
  84.             page_result.append("<input type=\"button\" onclick=\"if(document.getElementById('pageinput').value!=''){location.href='" + holepagename + "?pageid='+document.getElementById('pageinput').value+'" + rank_pageid2 + "'}\" style=\"width:50px;height:22px;margin:5px 4px\" value=\"跳转\" />");
  85.         }
  86.         return page_result.toString();
  87.     }
  88. }

这个类只有一个静态的方法:showPage,用来打印页码输出。它的几个参数作用如下:

  • datacount:数据总量,即需要显示的所有数据的条数

  • maxperpage:每页显示的数据量

  • wholepagename:完整的页面名称

  • para:带入的参数名称,如果页面需要其他参数,可以带入

  • nPage:当前页码

  • showlevel:显示等级,等级数值越小,显示的页码组件越多

这个方法是我封装好的,里面还带有CSS样式,可以配合页面的CSS使用。使用时直接将参数带入进去就可以,接下来会有详细的举例。

第4步

MainController类顶部申明一个“EntityManager”类的实体、并自动装配MainServiceImpl类的对象:

  1. @PersistenceContext
  2. EntityManager em;
  3.  
  4. @Autowired
  5. private MainServiceImpl mainServiceImpl;

这需要使用“@PersistenceContext”注解,这个注解的作用是注入一坨保存实体类状态的数据结构,针对实体类的不同的状态(四种,managedh或detached等)可以做出不同的反应(merge,persist等等),其实就是把数据从数据库里提出,然后在内存里处理的,再返回数据库的法则。

申明“EntityManager”类的实体需要引用依赖包:

  1. import javax.persistence.EntityManager;
  2. import javax.persistence.PersistenceContext;

其他的依赖包,按照提示来即可。

  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import com.w3xue.jiaocheng.service.MainServiceImpl;
  3. import com.w3xue.jiaocheng.utils.PageUtil;
  4. ....

然后,我们在MainController类中定义一个路由和相应的方法体:

  1. @RequestMapping("/diyPage")  //w3xue的自定义分页
  2. public ModelAndView diyPage(ModelAndView mv,@RequestParam(name="pageid",defaultValue = "1") int pPage, @RequestParam(name="size",defaultValue = "1") int pSize) {
  3.     Integer nStart=(pPage-1)*pSize; //开始索引
  4.  
  5.     Query query = em.createNativeQuery("SELECT COUNT(f_id) FROM t_w3xue_student");  //取出总数据量并放入内存
  6.     Object object = query.getResultList().get(0);
  7.     int totalElements = Integer.parseInt(object.toString());
  8.  
  9.     StringBuilder sbContent=new StringBuilder();
  10.     sbContent.append(mainServiceImpl.findByW3xuePage(pPage,pSize)); //主体内容部分
  11.     StringBuilder sbPage=new StringBuilder();
  12.     sbPage.append(PageUtil.showPage(totalElements, pSize, "/jiaocheng/diyPage", "size="+pSize, pPage, 1)); //页码部分
  13.     //你可以详细的看到showPage这个静态方法的参数作用,分别是:总数据量,每页数据量,页面地址,参数,当前页码,显示等级。你可以把显示等级调低,看看效果
  14.     mv.addObject("content",sbContent.toString());
  15.     mv.addObject("page",sbPage.toString());
  16.     mv.setViewName("/list");
  17.     return mv;
  18. }

这个方法体需要的引用包:

  1. import javax.persistence.Query;

第5步

我们在模板文件夹新建一个H5页面“list.html”,里面附带上关于页码的CSS样式:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Title</title>
  6.     <style>
  7.         .qianpageid  {font-size:14px;color:#333;display:block; float:left; height:25px; padding: 10px 0px 0px 0px; margin:5px 0x 0px 8px}
  8.         .qianpageid2  {font-size:14px;color:#333; display:block; float:left; height:25px; padding: 10px 0px 0px 0px; margin:5px 0x 0px 8px}
  9.         .pageid {font-size:14px;color:white; border:#fff 1px solid; display:block; float:left; background-color:#6C0002; height:30px; padding: 5px 6px 2px 6px; margin:5px 0px 0px 8px}
  10.         a.pageid {text-decoration:none;color:#ddd; float:left;  border:#fff 1px solid; display:block; height:30px; padding: 5px 6px 2px 6px; margin:5px 0px 0px 8px}
  11.         a.pageid:visited  {color:#ddd;}
  12.         a.pageid:hover {text-decoration:underline;color:white; border:#fff 1px solid; float:left; display:block;  background-color:#6C0002; background-image:url('') ;height:30px; padding: 5px 6px 2px 6px; margin:5px 0px 0px 8px}
  13.  
  14.     </style>
  15. </head>
  16. <body>
  17. <div th:utext="${content}"></div>
  18. <div th:utext="${page}"></div>
  19. </body>
  20. </html>

最后,我们访问“http://localhost:8080/jiaocheng/diyPage?pageid=1&size=2”,就可以看到最终效果啦:

1.jpg

注意:本页面内容为W3xue原创,未经授权禁止转载,违者必究!
来源:W3xue  发布时间:2019/10/10 15:02:01
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号