java中实现分页的常见几种方式

news2024/12/23 14:23:19

文章目录

  • 1. 前言
  • 2. 先说结论
  • 3. 例子
    • 1. 数据库SQL的限制条件(limit、fetch)
    • 2. 使用List集合的截取功能实现
    • 3. 插件PageHelper

1. 前言

  1. 无论是自我学习中,还是在工作中,固然会遇到与前端搭配实现分页的功能,发现有几种方式,特此记录一下。

2. 先说结论

  1. 分页功能直接交给前端实现(根据业务场景且仅仅只能用于数据量少的情况)。即后端不做任何数据的限制,直接把全部数据返回给前端,前端通过组件实现分页,筛选等功能。请不要轻视该方式,好处即只需要前后端交互一次。
  2. 使用数据库SQL的限制条件,即给搜索语句加上条件,限制查询出来的数据个数:
    1. mysql数据库是使用 limit n,m 从第n个开始,往后取m个(注 不包括第n个数据)
    2. oracle数据库是使用 OFFSET n ROWS FETCH NEXT m ROWS ONLY 从第n行开始,往后取m行(注 不包括第n行数据)
    3. oracle的可以查看这篇文章:oracle中将数据进行排序之后,获取前几行数据的写法(rownum、fetch方式)
  3. 使用List集合的截取功能实现,即将数据都查到内存中List集合,在内存中找到要的数据。当然有人说这种方式还不如第二点,但请具体情况具体分析,有可能需求要的数据,是从数据库中查询不到的需要将原始数据查到内存加工处理数据之后得到,才能进行分页处理。(同理,该方法,只能根据需求数据量少的情况)
  4. 使用优秀的插件PageHelper,真的很不错。

3. 例子

1. 数据库SQL的限制条件(limit、fetch)

  1. 先说结论

    mysql写法:
    SELECT * FROM user2
    LIMIT (#{pageNum} - 1) * #{pageSize}, #{pageSize}
    
    oracle写法:
    SELECT * FROM user2
    OFFSET (#{pageNum} - 1) * #{pageSize} ROWS FETCH NEXT #{pageSize} ROWS ONLY
    
  2. 直接看代码:

    @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语句
    在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IIC总线(二)-----IIC控制器与MPU6050

1.Exynos_4412下的IIC控制器 Exynos 4412 SCP简化指令集计算机&#xff08;RISC&#xff09;微处理器支持四个多主控间集成电路&#xff08;I2C&#xff09;总线串行接口。为了在连接到I2C总线的总线主机和外围设备之间传输信息&#xff0c;我们使用了一条专用的串行数据线&am…

IO流(一)

IO流的思维导图如下所示&#xff1a; 我们下来对文件、IO流原理及流的分类&#xff0c;节点流&#xff08;访问文件的、访问数组的、访问管道的&#xff09;和处理流&#xff08;缓冲流、对象流、管道流&#xff09;&#xff0c;输入流&#xff08;InputStream和Reader)和输出流…

[附源码]Nodejs计算机毕业设计基于协同过滤技术的旅游景点购票系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

Python+Selenium自动化测试详细教程

前言 PythonSelenium 来实现的web端自动化, 以下演示会用到禅道、百度和自己编写的html. 一、准备工作 1、安装 安装Python 3安装selenium库&#xff0c;命令&#xff1a;pip install selenium搭建禅道环境 2、导入浏览器驱动 selenium操作不同的浏览器&#xff0c;需要下…

Windows10 系统下载网址推荐(二)

Windows10 系统下载网址推荐&#xff08;二&#xff09;1. 计算机操作系统概述2.HelloWindows3. 山己几子木4. xitongku5. TechBench结束语1. 计算机操作系统概述 操作系统&#xff08;Operating System&#xff0c;OS&#xff09;是一组主管并控制计算机操作、运用和运行硬件…

设计一个接口务必考虑好这14个基本点

目录&#xff1a;导读 前言 1、入参合法性校验 2、接口的版本控制 3、接口考虑幂等性 4、接口考虑防止重复请求 5、提高接口的响应时间 6、接口限流控制 7、黑白IP白名单 8、敏感数据脱敏 9、请求接口的先决条件-token 10、记录接口请求日志 11、调用第三方接口要考…

分解优化react对redux的基础使用

之前写了 react18 通过redux 做一个简单的状态管理基站 但代码确实相对比较乱 这次进行一些小封装和分解 优化一下管理质量 首先 我们创建一个 react项目 然后在项目中引入 npm install redux --save在src目录下创建 reducers 文件夹 下面创建 counter.js counter.js 参考代码…

有什么免费python安装包?

前言 Python的安装涉及到&#xff1a;Python编辑器、Python解释器、Python包管理工具&#xff08;pip&#xff09;。因此&#xff0c;首先我们要搞清楚这三个东西都是啥。 Python编辑器 正如在电脑上编辑文档需要用Word、处理数据需要用Excel、做演示文稿需要用PPT、修图需要…

git add 命令详解

1. 前言 2. git add 基本操作 3. git add 命令参数 4. git add 背后做了什么 1. 前言 众所周知&#xff0c;git 中有工作区、暂存区、版本库三大组成部分 工作区: 电脑中能看到的目录&#xff0c;也就是写代码的地方 暂存区: 英文叫 stage 或 index。一般存放在 .git 目录下…

【图像分割】灰狼算法最小交叉熵多阈值图像分割【含Matlab源码 903期】

⛄一、最小交叉熵多阈值图像分割简介 1 单阈值分割 设有两个概率分布P{p1, p2, …, pN}和Q{q1, q2, …, qN}, 交叉熵度量它们之间的信息量差异。其对称形式为 交叉熵既可看成是采用P取代Q作为单个系统概率分布时系统信息量变化的期望值, 也可看成是两个概率系统P和Q之间的信息…

CSAPP-Lab5 CacheLab解析

Review Cache Struct A cache is a set of 2s2^s2s cache setsA cache set is a set of E cache lines if E1, it is called “direct-mapped” Each cache line stores a blockTotal Capacity S * B * E 由此&#xff0c;我们可以写出cache line和cache的结构&#xff1a; …

微服务框架 SpringCloud微服务架构 服务异步通讯 50 消息可靠性 50.4 失败重试机制 50.4.1 消费者失败重试

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 服务异步通讯 文章目录微服务框架服务异步通讯50 消息可靠性50.4 失败重试机制50.4.1 消费者失败重试50 消息可靠性 50.4 失败重试机制 50…

可路由计算引擎实现前置数据库

❤️作者主页&#xff1a;小虚竹 ❤️作者简介&#xff1a;大家好,我是小虚竹。Java领域优质创作者&#x1f3c6;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;掘金年度人气作者&#x1f3c6;&#xff0c;阿里云专家博主&#x1f3…

非零基础自学Golang 第9章 结构体 9.1 理解结构体 9.2 定义结构体 9.3 实例化结构体

非零基础自学Golang 文章目录非零基础自学Golang第9章 结构体9.1 理解结构体9.2 定义结构体9.3 实例化结构体9.3.1 标准实例化9.3.2 new函数实例化9.3.3 取地址实例化9.3.4 访问成员第9章 结构体 在Go语言官网的常见问题解答一栏中&#xff0c;有这样一个问题&#xff1a;“Is…

Fiddler(7):fiddler设置弱网测试

弱网测试 概念&#xff1a;弱网看字面意思就是网络比较弱&#xff0c;我们通称为信号差&#xff0c;网速慢。 意义&#xff1a;模拟在地铁、隧道、电梯和车库等场景下使用APP &#xff0c;网络会出现延时、中断和超时等情况。 Fiddler弱网测试流程&#xff1a; 一、限速操作…

基于云开发的微信小程序、QQ小程序详细教程(更新中)

云开发解决方案 小程序云开发解决方案 为企业和开发者提供一站式后端云服务&#xff0c;无需管理基础架构&#xff0c;一次开发多端运行&#xff0c;腾讯云和微信联合出品。 云开发&#xff08;Tencent CloudBase&#xff0c;TCB&#xff09;是腾讯云提供的云原生一体化开发环…

数据结构---大整数相加

大整数相加列竖式运算第一步第二步第三步第四步JAVA实现给出两个很大的整数&#xff0c;要求实现程序求出两个整数之和。 记得这个题目我大二ACM课程老师讲过&#xff0c;但是忘记了。。。。。。。。。。 列竖式运算 程序不可能通过一条指令计算出两个大整数之和&#xff0c;…

【学习打卡04】可解释机器学习笔记之Grad-CAM

可解释机器学习笔记之Grad-CAM 文章目录可解释机器学习笔记之Grad-CAMGrad-CAM介绍Grad-CAM是CAM的泛化形式Gard-CAM可视化结果Grad-CAM算法的优点Grad-CAM算法的缺点Grad-CAM变种Grad-CAMScore-CAMLayer-CAM思考与总结参考阅读首先非常感谢同济子豪兄拍摄的可解释机器学习公开…

SAP S4 FICO 固定资产模块后台配置详解

1. 概述 资产会计&#xff08;FI-AA&#xff09;作为总帐模块&#xff08;FI-GL&#xff09;的子分类帐&#xff0c;对企业的固定资产、无形资产、在 建工程、低值易耗品、长期待摊、从购置、资本化、折旧、调拨到出售/报废的整个生命周期 进行全过程的管理&#xff0c;并和…

java实现给微信群中定时推送消息

大家好&#xff0c;我是雄雄。 前言 上一篇&#xff0c;我们介绍了如何通过调用接口的方式&#xff0c;将每日新闻发送到自己的博客中。我们会发现&#xff0c;将新闻以文章的形式发布&#xff0c;并且相关内容按照markdown的形式进行格式调整&#xff0c;有需要的可以点击这里…