java中实现分页的几种常见方式总结
1. 前言
无论是自我学习中,还是在工作中,固然会遇到与前端搭配实现分页的功能,发现有几种方式,特此记录一下。
2. 先说结论
- 分页功能直接交给前端实现(根据业务场景且仅仅只能用于数据量少的情况)。即后端不做任何数据的限制,直接把全部数据返回给前端,前端通过组件实现分页,筛选等功能。请不要轻视该方式,好处即只需要前后端交互一次。
- 使用数据库SQL的限制条件,即给搜索语句加上条件,限制查询出来的数据个数:
- mysql数据库是使用 limit n,m 从第n个开始,往后取m个(注 不包括第n个数据)
- oracle数据库是使用 OFFSET n ROWS FETCH NEXT m ROWS ONLY 从第n行开始,往后取m行(注 不包括第n行数据)
- oracle的可以查看这篇文章:oracle中将数据进行排序之后,获取前几行数据的写法(rownum、fetch方式)
- 使用List集合的截取功能实现,即将数据都查到内存中List集合,在内存中找到要的数据。当然有人说这种方式还不如第二点,但请具体情况具体分析,有可能需求要的数据,是从数据库中查询不到的,需要将原始数据查到内存加工处理数据之后得到,才能进行分页处理。(同理,该方法,只能根据需求且数据量少的情况)
- 使用优秀的插件PageHelper,真的很不错。
3. 例子
1. 数据库SQL的限制条件(limit、fetch)
先说结论:
mysql写法: SELECT * FROM user2 LIMIT (#{pageNum} - 1) * #{pageSize}, #{pageSize} oracle写法: SELECT * FROM user2 OFFSET (#{pageNum} - 1) * #{pageSize} ROWS FETCH NEXT #{pageSize} ROWS ONLY
直接看代码:
@Mapper public interface PageTestDao { // 查数据 // start:从第几条开始,向后要数据 // pageSize:一页多少条数据 List<UserEntity> getUserInfoByParams(@Param("nameParam") String name, @Param("start") int start, @Param("pageSize") int pageSize); // 返回总条数 int getCountByParams(@Param("nameParam") String name); }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.csdn2.page_test.dao.PageTestDao"> <sql id="nameCondition"> <where> <if test="nameParam != null and nameParam != ''"> name like CONCAT('%', #{nameParam}, '%') </if> </where> </sql> <select id="getUserInfoByParams" resultType="com.example.csdn2.page_test.entity.UserEntity"> SELECT * FROM user2 <include refid="nameCondition" /> LIMIT #{start}, #{pageSize} </select> <select id="getCountByParams" resultType="int"> SELECT COUNT(*) FROM user2 <include refid="nameCondition" /> </select> </mapper>
@Service @RequiredArgsConstructor public class PageTestService { private final PageTestDao pageTestDao; public PageResponse<UserEntity> getPageTest(UserRequest userRequest) { final List<UserEntity> userEntityList = pageTestDao.getUserInfoByParams(userRequest.getNameParam(), userRequest.getStart(), userRequest.getPageSize()); final int total = pageTestDao.getCountByParams(userRequest.getNameParam()); return new PageResponse<>(userEntityList, total); } }
// 若分页的需求很多,可把分页相关的参数抽出来 @Data public class PageRequest { // 第几页 private int pageNum; // 每页几行数据 private int pageSize; // 计算从第几行开始 // 无论是limit、还是fetch 都是从某一行数据开始,向后取 pageSize 条数据 public int getStart() { if (pageNum <= 0) { return 0; } return (pageNum - 1) * pageSize; } } // 入参 @EqualsAndHashCode(callSuper = true) @Data public class UserRequest extends PageRequest { // 搜索参数 private String nameParam; } // 返回实体类,因为分页需要返回总条数,前端好做下标第几页 @Data @AllArgsConstructor public class PageResponse<T> { private List<T> data; // 总条数 private int total; }
@RestController @RequiredArgsConstructor public class PageTestController { private final PageTestService pageTestService; @PostMapping("/page-test") public PageResponse<UserEntity> getPageTest(@RequestBody UserRequest userRequest){ return pageTestService.getPageTest(userRequest); } }
2. 使用List集合的截取功能实现
1.先看一下List的截取
// 从第几个下标,到第几个下标 List<E> subList(int fromIndex, int toIndex);
public void test_ListSub() { // 创建模拟数据,字符串 0-9的集合 final List<String> list = IntStream.range(0, 10) .mapToObj(i -> i + "") .collect(Collectors.toList()); System.out.println(list); // 截取从下标0到5的数据 System.out.println(list.subList(0, 5)); // 截取从下标3到5的数据 System.out.println(list.subList(3, 5)); }
2.回归上述分页例子,代码改成如下:
dao层 不加 limit 条件
SELECT * FROM user2 name like CONCAT('%', #{nameParam}, '%')
server层:
public PageResponse<UserEntity> getPageTestByListSub(UserRequest userRequest) { final List<UserEntity> allData = pageTestDao.getUserInfoByParamsNoLimit(userRequest.getNameParam()); // 下标开始 final int start = userRequest.getStart(); // 下标结束 final int end = start + userRequest.getPageSize(); // 截取数据 final List<UserEntity> userEntityList = allData.subList(start, end); final int total = pageTestDao.getCountByParams(userRequest.getNameParam()); return new PageResponse<>(userEntityList, total); }
3. 插件PageHelper
1.其实PageHelper官网中有详细的文档以及例子:https://pagehelper.github.io/docs/howtouse/
2.下面例子只是讲其与springboot结合的核心内容,即快速开发:
3.引入相关jar包坐标到pom.xml中
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency>
4.dao层的sql不需要加 Limit 条件(因为PageHelper会自动帮忙加的)
SELECT * FROM user2 name like CONCAT('%', #{nameParam}, '%')
5.service层修改如下:
public PageInfo<UserEntity> getPageTest(UserRequest userRequest) { // 告诉PageHelper数据要从第几页,每页多少条数据 // 注:一定要在select查询语句之前使用该方法,否则无效 PageHelper.startPage(userRequest.getPageNum(), userRequest.getPageSize()); // 查询sql final List<UserEntity> userEntityList = pageTestDao.getUserInfoByParamsNotLimit(userRequest.getNameParam()); // 返回dto,使用插件自带的PageInfo return new PageInfo<>(userEntityList); // 上述逻辑还可以简写为: // return PageHelper.startPage(userRequest.getPageNum(), userRequest.getPageSize()) // .doSelectPageInfo(() -> pageTestDao.getUserInfoByParamsNotLimit(userRequest.getNameParam())); }
6.结果如下(与之前查询结果一致,没问题):
{
"total": 9,
"list": [
{
"name": "4a",
"pwd": "D"
},
{
"name": "5a",
"pwd": "E"
},
{
"name": "6a",
"pwd": "F"
}
],
"pageNum": 2,
"pageSize": 3,
"size": 3,
"startRow": 4,
"endRow": 6,
"pages": 3,
"prePage": 1,
"nextPage": 3,
"isFirstPage": false,
"isLastPage": false,
"hasPreviousPage": true,
"hasNextPage": true,
"navigatePages": 8,
"navigatepageNums": [
1,
2,
3
],
"navigateFirstPage": 1,
"navigateLastPage": 3
}
7.为什么说该插件很优秀呢,查看PageInfo的返回参数,核心内容:
// 当前页 private int pageNum; // 每页的数量 private int pageSize; // 当前页的数量 private int size; // 总记录数 private long total; // 总页数 private int pages; // 结果集 private List<T> list; // 以下内容都是其自动帮生成的 // 对于前端来说极其友好,前端分页功能的全部参数都包含了 // 前一页的页码 private int prePage; // 下一页的页码 private int nextPage; // 是否为第一页 private boolean isFirstPage = false; // 是否为最后一页 private boolean isLastPage = false; // 是否有前一页 private boolean hasPreviousPage = false; // 是否有下一页 private boolean hasNextPage = false; // 导航条上的第一页的页码 private int navigateFirstPage; // 导航条上的第一页的页码 private int navigateLastPage;
8.查看PageHelper执行了什么sql语句
总结
到此这篇关于java中实现分页的几种常见方式的文章就介绍到这了,更多相关java实现分页方式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
springboot serverEndpoint导致@resource注解不生效
在SpringBoot中,@Resource注解用于注入依赖,本文主要介绍了springboot serverEndpoint导致@resource注解不生效,具有一定的参考价值,感兴趣的可以了解一下2023-12-12Java String源码分析并介绍Sting 为什么不可变
这篇文章主要介绍了Java String源码分析并介绍Sting 为什么不可变的相关资料,需要的朋友可以参考下2017-02-02Java 使用POI生成带联动下拉框的excel表格实例代码
本文通过实例代码给大家分享Java 使用POI生成带联动下拉框的excel表格,代码简单易懂,非常不错,具有参考借鉴价值,需要的朋友参考下吧2017-09-09JavaSE static final及abstract修饰符实例解析
这篇文章主要介绍了JavaSE static final及abstract修饰符实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下2020-06-06Java Optional解决空指针异常总结(java 8 功能)
这篇文章主要介绍了Java Optional解决空指针异常总结(java 8 功能),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2020-11-11基于springboot bean的实例化过程和属性注入过程
这篇文章主要介绍了基于springboot bean的实例化过程和属性注入过程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2021-11-11
最新评论