【Java 干货教程】Java实现分页的几种方式详解
一、前言
无论是自我学习中,还是在工作中,固然会遇到与前端搭配实现分页的功能,发现有几种方式,特此记录一下。
二、实现方式
2.1、分页功能直接交给前端实现
这种情况也是有的,(根据业务场景且仅仅只能用于数据量少的情况)。即后端不做任何数据的限制,直接把全部数据返回给前端,前端通过组件实现分页,筛选等功能。请不要轻视该方式,好处即只需要前后端交互一次。
2.2、数据库SQL的限制条件
即给搜索语句加上条件,限制查询出来的数据个数。(这里不同数据库可能sql语句写法不一样)
- mysql数据库是使用 limit n,m 从第n个开始,往后取m个(注 不包括第n个数据)
- oracle数据库是使用 OFFSET n ROWS FETCH NEXT m ROWS ONLY 从第n行开始,往后取m行(注 不包括第n行数据)
oracle的可以查看这篇文章:oracle中将数据进行排序之后,获取前几行数据的写法(rownum、fetch方式)
2.3、使用List集合的截取功能实现
即将数据都查到内存中List集合,在内存中找到要的数据。当然有人说这种方式还不如第二点,但请具体情况具体分析,有可能需求要的数据,是从数据库中查询不到的,需要将原始数据查到内存加工处理数据之后得到,才能进行分页处理。(同理,该方法,只能根据需求且数据量少的情况)。
2.4、插件PageHelper
使用优秀的插件PageHelper,真的很不错。
如果想详细了解PageHelper插件的,可以访问:如何使用分页插件
2.5、SpringData
SpringData我还没用过,这里就不展开详细说明了,后期如果业务使用到了,会更新到这篇文章。
三、详细介绍
分页功能交给前端实现的这里就不展示了,比较我们标题是后端实现分页功能。
3.1、数据库SQL的限制条件(limit,fetch)
sql语句
mysql写法:
SELECT * FROM user2
LIMIT (#{pageNum} - 1) * #{pageSize}, #{pageSize}oracle写法:
SELECT * FROM user2
OFFSET (#{pageNum} - 1) * #{pageSize} ROWS FETCH NEXT #{pageSize} ROWS ONLY
Dao层(也可以叫Mapper层)
@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);
}
Mapper.xml
<?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实现层
@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);}
}
PageRequest
// 若分页的需求很多,可把分页相关的参数抽出来
@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;}
}
UserRequest
// 入参
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserRequest extends PageRequest {// 搜索参数private String nameParam;
}
PageResponse
我这边只返回给前端查询的某页数据、和一共多少条数据,如果前端需要知道可以分多少页,需要前端自己计算一下,当然后端其实也可以计算,只需要添加一个参数和一个方法。
// 返回实体类,因为分页需要返回总条数,前端好做下标第几页
@Data
@AllArgsConstructor
public class PageResponse<T> {private List<T> data;// 总条数private int total;
}
Controller层
@RestController
@RequestMapping("/pageTest")
public class PageTestController {private final PageTestService pageTestService;@PostMapping("/page-test")public PageResponse<UserEntity> getPageTest(@RequestBody UserRequest userRequest){return pageTestService.getPageTest(userRequest);}
}
运行结果
3.2、使用List集合的截取功能(subList())实现
先看一下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));}
回归上述分页例子,代码改成如下:
dao层 不加 limit 条件
SELECT * FROM user2name 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.3、插件PageHelper
这是一个特别好用的分页插件。
其实PageHelper官网中有详细的文档以及例子:https://pagehelper.github.io/docs/howtouse/
下面例子只是讲其与springboot结合的核心内容,即快速开发:
引入相关jar包坐标到pom.xml中
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.3.0</version>
</dependency>
配置项目application.yml文件
#bybatis分页插件配置
pagehelper:helper-dialect: mysql #数据库reasonable: truesupport-methods-arguments: trueparams: count=countSql
3.3.1、案例1
前端所需要的数据就是数据库中表的数据
dao层的sql不需要加 Limit 条件(因为PageHelper会自动帮忙加的)
SELECT * FROM user2name like CONCAT('%', #{nameParam}, '%')
service层修改如下
public PageInfo<UserEntity> getPageTest(UserRequest userRequest) {// 告诉PageHelper数据要从第几页,每页多少条数据// 注:一定要在select查询语句之前使用该方法,否则无效PageHelper.startPage(userRequest.getPageNum(), userRequest.getPageSize());// 查询sqlfinal List<UserEntity> userEntityList =
pageTestDao.getUserInfoByParamsNotLimit(userRequest.getNameParam());// 返回dto,使用插件自带的PageInforeturn new PageInfo<>(userEntityList);// 上述逻辑还可以简写为:// return PageHelper.startPage(userRequest.getPageNum(), userRequest.getPageSize())// .doSelectPageInfo(() ->
pageTestDao.getUserInfoByParamsNotLimit(userRequest.getNameParam()));}
结果如下(与之前查询结果一致,没问题)
{"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
}
3.3.2、案例2
前端所需要的数据不只是数据库中表的数据,还有一些需要Java代码逻辑计算得到的数据。那么上面的PageHelper.startPage(userRequest.getPageNum(), userRequest.getPageSize());就失效了。
public PageInfo<UserEntityResp> getPageTest(UserRequest userRequest) {//分页类的创建PageInfo<UserEntityResp> res = new PageInfo<>();// 查询sqlList<UserEntity> userEntityList =
pageTestDao.getUserInfoByParamsNotLimit(userRequest.getNameParam());//对userEntityList中的数据进行了一些算法操作,改变了原来从数据库中查询到的数据//或者以什么排序等等操作,最终得到resultList<UserEntityResp> result = ..... ; int total = result.size();//注意:这里的start,end是需要通过userRequest.getPageNum(), userRequest.getPageSize()//计算得到的Double index = (Double)Math.ceil(total * 1.0 / userRequest.getPageSize());if (index.intValue()>=userRequest.getPage()){start = (userRequest.getPage() - 1) * userRequest.getPageSize();end = Math.min(start + userRequest.getPageSize(), total);} else{start = 0;end = total;}List<InterfaceConfirmTimeResp> pageList = result.subList(start, end);//将分页相关对象的属性设置res.setList(pageList);res.setTotal(result.size());res.setPageNum(userRequest.getPage());res.setPageSize(userRequest.getPageSize());res.setPages((int)Math.ceil(result.size()*1.0/userRequest.getPageSize()));return res;}
这是通过PageHelp插件中的PageInfo类和List中的subList()方法实现的,其实一般这种情况用的也是比较多的。
3.3.3、为什么PageHelp插件优秀
为什么说该插件很优秀呢,查看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;
查看PageHelper执行了什么sql语句
3.3.4、spring结合mybatis整合PageHelper框架
Spring整合:导入pom.xml
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper --><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.2</version></dependency>
配置项目配置文件(我在spring和mybatis整合的配置文件中配置的,如果在mybatis核心配置文件中配置,百度一下)
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 依赖数据源 --><property name="dataSource" ref="dataSource"/><!-- 注册加载myBatis映射文件 --><property name="mapperLocations"><array><value>classpath*:com/yyz/mapper/*Mapper.xml</value></array></property><!-- PageHelper分页配置 --><property name="plugins"><array><bean class="com.github.pagehelper.PageInterceptor"><property name="properties"><!--使用下面的方式配置参数,一行配置一个,后面会有所有的参数介绍 --><value><!--helperDialect属性来指定分页插件使用哪种方言。-->helperDialect=mysql<!--分页合理化参数,设置为true时,pageNum<=0时会查询第一页,pageNum>pages(超过总数时),会查询最后一页。-->reasonable=true<!--为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值,可以配置 pageNum,pageSize,count,pageSizeZero,reasonable-->params=count=countSql<!--支持通过Mapper接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。-->supportMethodsArguments=true<!--默认值为 false。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页-->autoRuntimeDialect=true</value></property></bean></array></property><!-- 给数据库实体起别名 --><property name="typeAliasesPackage" value="com.yyz.entity;"/></bean>
以上就是Java实现分页的几种方式,希望对你有所帮助,如果有其它方式可以在评论区留言!!!
参考文章:java中实现分页的常见几种方式_java 分页-CSDN博客
相关文章:

【Java 干货教程】Java实现分页的几种方式详解
一、前言 无论是自我学习中,还是在工作中,固然会遇到与前端搭配实现分页的功能,发现有几种方式,特此记录一下。 二、实现方式 2.1、分页功能直接交给前端实现 这种情况也是有的,(根据业务场景且仅仅只能用于数据量…...

关于Python里xlwings库对Excel表格的操作(三十一)
这篇小笔记主要记录如何【如何使用“Chart类”、“Api类"和“Axes函数”设置绘图区外框线型、颜色、粗细及填充颜色】。前面的小笔记已整理成目录,可点链接去目录寻找所需更方便。 【目录部分内容如下】【点击此处可进入目录】 (1)如何安…...

QML使用QCustomPlot笔记
这里在QML中使用QCustomPlot是定义一个继承自QQuickPaintedItem的类,它包含一个QCustomPlot对象,在paint函数中将这个对象转化为pixmap绘制到布局中显示。 在QML中使用QT的Widget控件也可以借鉴这个思路实现 顺便记录一下QCustomPlot的简单设置与使用。…...

【REST2SQL】06 GO 跨包接口重构代码
【REST2SQL】01RDB关系型数据库REST初设计 【REST2SQL】02 GO连接Oracle数据库 【REST2SQL】03 GO读取JSON文件 【REST2SQL】04 REST2SQL第一版Oracle版实现 【REST2SQL】05 GO 操作 达梦 数据库 对所有关系数据的操作都只有CRUD,采用Go 的接口interface{}重构代码…...

《NLP入门到精通》栏目导读
一、说明 栏目《NLP入门到精通》本着从简到难得台阶式学习过度。将自然语言处理得知识贯穿过来。本栏目得前导栏目是《深度学习》、《pytorch实践》,因此,读者需要一定得深度学习基础,才能过度到此栏目内容。 二、博客建设理念 本博客基地&am…...

C++学习笔记——类继承
目录 一、一个简单的基类 1.1封装性 1.2继承性 1.3虚函数 1.4多态性 二、基类 2.1一个简单的C基类的示例 2.2 Animal是一个基类。 三、继承 3.1概念 3.2is-a关系 3.3多态公有继承 3.4静态联编和动态联编 3.5访问控制 3.6ABC理念 一、一个简单的基类 C中的基类是一…...

ARCGIS PRO SDK 使用条件管理 Pro UI
ARCGIS PRO UI简单介绍以下: 第一步:在Config.daml中在</AddInfo>标签下加上条件<conditions>标签(必须添加的) <conditions><!-- 定义条件 ,此处定义了两个--Tab 另一个为 group><insert…...

Halcon经典的边缘检测算子Sobel/Laplace/Canny
Halcon经典的边缘检测算子 文章目录 Halcon经典的边缘检测算子1. Sobel算子2. Laplace 算子3. Canny 算子4. 总结 关于边缘检测,有许多经典的算子,各大图形处理库都有各自的边缘检测算子,这里简要介绍几种。 1. Sobel算子 Sobel算子结合了高…...

用单片机设计PLC电路图
自记: 见另一篇文章,MOS驱动差了一个充电电容,栅极电容充电会有问题; 光耦用的直插,但板子用的贴片,此文档仅供参考 基本列出了PCB板情况,基础元器件,部分连接,原理等…...

【设计模式-6】建造者模式的实现与框架中的应用
建造者模式又被成为生成器模式,是一种使用频率比较低,相对复杂的创建型模式,在很多源码框架中可以看到建造者的使用场景,稍后我们会在本文末尾展示几个框架的使用案例。 建造者模式所构造的对象通常是比较复杂而且庞大的&#x…...

PositiveSSL和Sectigo的多域名证书
首先,我们要知道PositiveSSL是Sectigo旗下的子品牌,提供多种类型的SSL数字证书,包括DV基础型的多域名SSL证书。Sectigo的SSL证书产品同样比较丰富,不仅有DV基础型多域名SSL证书,还有OV企业型以及EV增强型的多域名SSL证…...

Docker:docker exec命令简介
介绍 docker exec [OPTIONS] 容器名称 COMMAND [ARG...] OPTIONS说明: -d,以后台方式执行命令; -e,设置环境变量 -i,交互模式 -t,设置TTY -u,用户名或UID,例如myuser:myu…...

【大数据进阶第三阶段之Hive学习笔记】Hive的数据类型与数据操作
目录 1、Hive数据类型 1.1、基本数据类型 1.2、集合数据类型 1.3、类型转化 2、DDL数据定义 2.1、创建数据库 2.2、查询数据库 2.3删除数据库 2.4、创建表 2.4.1、内部表 2.4.2、外部表 2.4.3管理表与外部表的互相转换 2.5、分区表(partitionÿ…...

GPT2:Language Models are Unsupervised Multitask Learners
目录 一、背景与动机 二、卖点与创新 三、几个问题 四、具体是如何做的 1、更多、优质的数据,更大的模型 2、大数据量,大模型使得zero-shot成为可能 3、使用prompt做下游任务 五、一些资料 一、背景与动机 基于 Transformer 解码器的 GPT-1 证明…...

微创新与稳定性的权衡
之前做过一个项目,业务最高峰CPU使用率也才50%,是一个IO密集型的应用。里面涉及一些业务编排,所以为了提高CPU使用率,我有两个方案:一个是简单的梳理将任务可并行的采用并行流、额外线程池等方式做并行;另外…...

对回调函数的各种讲解说明
有没有跟我师弟一样的童靴~,学习和使用ROS节点时,对其中的callback函数一直摸不着头脑的,以下这么多回调函数的讲解,挨个看,你总会懂的O.o 回调函数怎么调用,如何定义回调函数: 回调函数怎么调用,如何定义…...

Java多线程:创建多线程的三种方式
在Java中,有三种方式创建多线程,继承类Thread,继承接口Runnable,继承接口Callable。其中Thread和Runnable需要重写方法run,方法run没有返回值;Callable需要重写方法call,方法call可以返回值。 …...

Unity中打印信息的两种方式
不继承MonoBehaviour的普通C#类中打印信息: 使用Debug类的方法: Unity提供了Debug类,其中包含了一些用于打印信息的静态方法。以下是常用的几种方法: Debug.Log(message):打印普通信息。Debug.LogWarning(message)&a…...

给定n个字符串s[1...n], 求有多少个数对(i, j), 满足i < j 且 s[i] + s[j] == s[j] + s[i]?
题目 思路: 对于字符串a,b, (a.size() < b.size()), 考虑对字符串b满足什么条件: 由1、3可知a是b的前后缀,由2知b有一个周期是3,即a.size(),所以b是用多个a拼接而成的,有因为a是b的前后缀&…...

Linux磁盘空间与文件大小查看命令详解
1. 查看磁盘空间大小 在Linux系统中,有多个命令可以用来查看磁盘空间的使用情况。最常用的命令是df(disk free)。 df -hdf命令的 -h 选项以人类可读的方式显示磁盘空间,该命令将显示文件系统的使用情况、剩余空间等信息。 2. 查看…...

网络通信过程的一些基础问题
客户端A在和服务器进行TCP/IP通信时,发送和接收数据使用的是同一个端口吗? 这个问题可以这样来思考:在客户端A与服务器B建立连接时,A需要指定一个端口a向服务器发送数据。当服务器接收到A的报文时,从报文头部解析出A的…...

STL——stack容器和queue容器详解
目录 💡stack 💡基本概念 常用接口 💡queue 💡基本概念 💡常用接口 💡stack 💡基本概念 栈(stack):一种特殊的线性表,其只允许在固定的一端…...

django websocket实现聊天室功能
注意事项channel版本 django2.x 需要匹配安装 channels 2 django3.x 需要匹配安装 channels 3 Django3.2.4 channels3.0.3 Django3.2.* channels3.0.2 Django4.2 channles3.0.5 是因为最新版channels默认不带daphne服务器 直接用命令 python manage.py runsever 默认运行的是w…...

软件测评中心▏性能测试之压力测试、负载测试的区别和联系简析
在如今的信息时代,软件已经成为人们日常工作和生活不可或缺的一部分。然而,随着软件的发展和应用范围的不断扩大,软件性能的优劣也成为了影响用户使用体验的重要因素。 软件性能测试即对软件在不同条件下的性能进行评估和验证的过程。通过模…...

Go 语言 panic 和 recover 详解
panic() 和 recover() 是 Go 语言中用于处理错误的两个重要函数。panic() 函数用于中止程序并引发panic,而 recover() 函数用于捕获panic并恢复程序的执行。 什么是panic和recover? panic panic() 函数用于中止程序并引发panic。panic() 函数可以接收…...

NAND Separate Command Address (SCA) 接口数据传输解读
在采用Separate Command Address (SCA) 接口的存储产品中,DQ input burst和DQ output burst又是什么样的策略呢? DQ Input Burst: 在读取操作期间,数据以一种快速并行的方式通过DQ总线传送到控制器。在SCA接口下,虽然命令和地址信…...

彻底认识Unity ui设计中Space - Overlay、Screen Space - Camera和World Space三种模式
文章目录 简述Screen Space - Overlay优点缺点 Screen Space - Camera优点缺点 World Space优点缺点 简述 用Unity中开发了很久,但是对unity UI管理中Canvas组件的Render Mode有三种主要类型:Screen Space - Overlay、Screen Space - Camera和World Spa…...

档案数字化怎样快速整理资料
对于机构和组织来说,档案数字化是一个重要的信息管理和保护措施。要快速整理资料进行档案数字化,可以遵循以下步骤: 1. 准备工具和设备:确保有一台计算机、扫描仪和相关软件。 2. 分类和组织资料:先将资料分类…...

面试算法100:三角形中最小路径之和
题目 在一个由数字组成的三角形中,第1行有1个数字,第2行有2个数字,以此类推,第n行有n个数字。例如,下图是一个包含4行数字的三角形。如果每步只能前往下一行中相邻的数字,请计算从三角形顶部到底部的路径经…...

androj studio安装及运行源码
抖音教学视频 目录 1、 jdk安装 2、下载安装androj studio 3 、打开源码安装运行相关组件 4、 安装模拟器 1、 jdk安装 安卓项目也是java开发的,运行在虚拟机上,安装jdk及运行的时候,就会自动生成虚拟机, jdk前面已经讲过&…...