【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博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/238099.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

6、C语言:输入与输出

输入输出 标准输入输出getchar&putchar函数printf函数sprintf函数格式化输入——scanf函数 文件访问文件读写 错误处理&#xff1a;stderr和exit行输入和行输出常用函数字符串操作函数字符类别测试和转换函数存储管理函数数学函数随机数发生器函数其他 标准输入输出 getch…

x-cmd pkg | grex - 用于生成正则表达的命令行工具

目录 简介首次用户生成的正则表达式与 perl 和 rust 兼容支持 Unicode 符号友好的用户体验进一步阅读 简介 grex 是一个旨在简化创作正则表达式的复杂且繁琐任务的库和命令行程序。这个项目最初是 Devon Govett 编写的 JavaScript 工具 regexgen 的 Rust 移植。但 regexgen 在…

红酒和果酒推荐

一、红酒 首先&#xff0c;说一下大家常见的几十元红酒和贵的红酒的区别。 1.品牌价值。 2.工艺要求。 3.主要原料优质与否。几十元的红酒&#xff1a; 工艺要求没有高档红酒要求高&#xff0c;另外用的葡萄是榨的汁&#xff0c;品牌价值低&#xff08;目前市场品牌推广的费…

vue组件通信

1. 概述 组件通信, 就是指 组件与组件 之间的数据传递。 注&#xff1a;组件的数据是独立的&#xff0c;无法直接访问其他组件的数据。所以需要了解组件通信 口诀&#xff1a;谁的数据谁处理 2. 组件关系 不同的组件关系包括&#xff1a; 父子关系&#xff08;包含&#xff…

启英泰伦推出「离线自然说」,离线语音交互随意说,不需记忆词条

离线语音识别是指不需要依赖网络&#xff0c;在本地设备实现语音识别的过程&#xff0c;通常以端侧AI语音芯片作为载体来进行数据的采集、计算和决策。但是语音芯片的存储空间有限&#xff0c;通过传统的语音算法技术&#xff0c;最多也只能存储数百条词条&#xff0c;导致用户…

SOLID 原则

单一功能原则 单一功能原则&#xff08;Single responsibility principle&#xff09;规定每个类都应该有一个单一的功能&#xff0c;并且该功能应该由这个类完全封装起来。所有它的&#xff08;这个类的&#xff09;服务都应该严密的和该功能平行&#xff08;功能平行&#x…

杨中科 EFCORE 第四部分 命令详解56-61

Migrations 深入研究Migrations 1、使用迁移脚本&#xff0c;可以对当前连接的数据库执行编号更高的迁移&#xff0c;这个操作叫做“向上迁移” (Up)&#xff0c;也可以执行把数据库回退到旧的迁移&#xff0c;这个操作叫“向下迁移(Down&#xff09; 2、除非有特殊需要&…

在Android原生项目中 创建 Flutter模块

前言 应用场景&#xff1a;在已有的Android原生项目中&#xff0c;引入Flutter模块&#xff0c;摸索了两天&#xff0c;终于给整出来了&#xff1b; 如果是新项目&#xff0c;最好直接创建Flutter项目&#xff0c;然后在Fluter的 android / ios目录中&#xff0c;写原生代码&…

贝锐蒲公英云智慧组网解读:实现工业设备远程调试、异地PLC互联

这个时候&#xff0c;使用异地组网是非常有效的解决方案。在12月28日贝锐官方的直播中&#xff0c;请到了贝锐蒲公英的技术研发经理&#xff0c;为大家分享了贝锐蒲公英云智慧组网解决方案&#xff0c;以及蒲公英二层组网相关的技术和应用。 搜索“贝锐”官方视频号&#xff0c…

好物周刊#36:程序员简历

村雨遥的好物周刊&#xff0c;记录每周看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;每周五发布。 一、项目 1. SmartDNS 一个运行在本地的 DNS 服务器&#xff0c;它接受来自本地客户端的 DNS 查询请求&#xff0c;然后从多个上游 DNS 服务器获取 DNS 查询…

【BetterBench】2024年都有哪些数学建模竞赛和大数据竞赛?

2024年每个月有哪些竞赛&#xff1f; 2024年32个数学建模和数据挖掘竞赛重磅来袭&#xff01;&#xff01;&#xff01; 2024年数学建模和数学挖掘竞赛时间目录汇总 一月 &#xff08;1&#xff09;2024年第二届“华数杯”国际大学生数学建模竞赛 报名时间&#xff1a;即日起…

苍穹外卖学习----出错记录

1.微信开发者工具遇到的问题&#xff1a; 1.1appid消失报错&#xff1a; {errMsg: login:fail 系统错误,错误码:41002,appid missing [20240112 16:44:02][undefined]} 1.2解决方式&#xff1a; appid可在微信开发者官网 登录账号后在开发栏 找到 复制后按以下步骤粘贴即…

【MySQL】子查询

文章目录 子查询一、子查询的基本使用子查询的分类 二、单行子查询2.1 单行比较操作符2.2 HAVING 中的子查询2.3 CASE中的子查询2.4 子查询中的空值问题2.5 非法使用子查询 三、多行子查询3.1 多行比较操作符3.2 ANY与ALL的区别 四、相关子查询4.1 相关子查询执行流程4.1.1 代码…

【大数据进阶第三阶段之Datax学习笔记】使用阿里云开源离线同步工具DataX 实现数据同步

【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax概述 【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax快速入门 【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax类图 【大数据进阶第三阶段之Datax学习笔记】使用…

Django数据库选移的preserve_default=False是什么意思?

有下面的迁移命令&#xff1a; migrations.AddField(model_namemovie,namemov_group,fieldmodels.CharField(defaultdjango.utils.timezone.now, max_length30),preserve_defaultFalse,),迁移命令中的preserve_defaultFalse是什么意思呢&#xff1f; 答&#xff1a;如果模型定…

数学建模.皮尔逊相关系数假设检验

一、步骤 查表找临界值 二、更好的方法 三、使用条件 作图可以使用spss 这个图对不对还不好说&#xff0c;因为还没进行正态分布的验证 四、正态分布验证 &#xff08;1&#xff09;JB检验 所以之前的数据的那个表是错的&#xff0c;因为不满足正态分布 &#xff08;2&#xff…

基于Token认证的登录功能实现

Session 认证和 Token 认证过滤器和拦截器 上篇文章我们讲到了过滤器和拦截器理论知识以及 SpringBoot 集成过滤器和拦截器&#xff0c;本篇文章我们使用过滤器和拦截器去实现基于 Token 认证的登录功能。 一、登录校验 Filter 实现 1.1、Filter 校验流程图 获得请求 url。判…

C语言入门教程,C语言学习教程(第三部分:C语言变量和数据类型)一

第三部分&#xff1a;C语言变量和数据类型 本章也是C语言的基础知识&#xff0c;主要讲解变量、数据类型以及运算符&#xff0c;这其中涉及到了数据的存储格式以及不同进制。 一、大话C语言变量和数据类型 在《数据在内存中的存储&#xff08;二进制形式存储&#xff09;》一…

性能分析与调优: Linux 内存观测工具

目录 一、实验 1.环境 2.vmstat 3.PSI 4.swapon 5.sar 6.slabtop 7.numstat 8.ps 9.top 10.pmap 11.perf 12.bpftrace 二、问题 1.接口读写报错 2.slabtop如何安装 3.numactl如何安装 4.numad启动服务与关闭NUMA 5. perf如何安装 6. kernel-lt-doc与kern…