7.3 SpringBoot整合MyBatis分页插件github.pageHelper:实现图书列表API

CSDN成就一亿技术人

文章目录

  • 前言
  • 一、自己实现分页
    • 第一步,count 查询 总记录数(totalCount),计算总页数(totalPages)
    • 第二步,limit 查询 指定页数据
  • 二、不考虑分页的查询图书列表Mapper
    • BookServiceImpl
    • BookListParamBO
  • 三、集成github.pageHelper并实现分页列表
    • 第一步:引入pom依赖
    • 第二步:实现分页查询
      • BookService方法定义
      • BookServiceImpl核心实现
      • BooKBO
  • 四、封装通用分页结果
    • TgResult
    • BookListParamVO
    • application.properties
    • PostMan走一波
  • 最后


前言

在软件开发中,分页是一个非常常见的需求,无论是在Web应用程序还是在移动应用程序中,我们经常需要将大量的数据分成多个页面进行展示。
本文主要实现图书列表API,使用SpringBoot集成MyBatis分页插件github.pageHelper,首先会从「自己实现分页原理」说起,再到「使用github.pageHelper实现分页以及注意点」,最后回到图书借阅系统实战项目中,「结合通用分页结果」,实现「统一规范的图书列表API」,读完本文,你就可以轻松拿捏通用分页。


一、自己实现分页

当你可以自己造轮子以后,再去学习其它分页组件,就会觉得非常Easy!

通常分页有两种实现方式:

  1. 将全部结果通过sql查询加载到内存中,再到内存中实现分页。 缺点显而易见,一次性加载所有数据到内存中,因为结果可能会非常大,会消耗大量的资源,甚至可能导致内存溢出,所以并不推荐!
  2. 只加载当页数据,这是真正我们期望的,所以我们实现这种!

接下来,我们以Java+MySQL的「伪代码」来演示实现分页的思路!
在这里插入图片描述

第一步,count 查询 总记录数(totalCount),计算总页数(totalPages)

接收前端参数:
// 当前页码(默认第1页)
int pageNum = 1;
// 每页记录数(默认一页10条)
int pageSize = 10;

先查总计录数和总页数的目的:返回给前端展示,让用户清楚一共多少条,一共多少页

select count(*) as totalCount from book where 。。。

使用Java代码计算总页数 totalPages

int totalPages = (int) Math.ceil((double) totalCount / pageSize);

第二步,limit 查询 指定页数据

limit 接受一个或两个数字参数。
我们主要使用两个参数:第一个参数指定第一个返回记录行的偏移量offset(可选),第二个参数指定返回记录行的最大数目rows;
基本语法是:

limit [offset] rows

rows就是pageSize,所以我们需要先使用pageNum计算出offset:

if (pageNum > totalPages) {
    pageNum = totalPages;
}
int offset = (pageNum - 1) * pageSize;

然后,通过limit查询指定页数据。

select * from book where 。。。 limit offset, pageSize

二、不考虑分页的查询图书列表Mapper

有了实现的思路,在实际的开发中你会发现,所有的分页场景都是类似的逻辑,重复的代码,实现起来就是一个字:繁琐!相当的不爽,那么有没有一种让你爽的方式呢?没错,github.pageHelper组件,它可以与MyBatis等持久化框架无缝集成,帮助我们快速实现分页功能。它提供了丰富的功能和灵活的配置选项,使得分页变得非常简单。我们只需要实现【主查询SQL】,对于其它的像totalCount和totalPages等等统统不用管,这些通用功能都由它封装到内部了。

既然如此,我们就先实现不考虑分页的查询图书列表Mapper

需求:
首先,这是管理后台的图书列表,所以可以查询出所有图书。
可选的筛选条件:图书名称、图书编号、作者、图书状态(0-闲置 1-借阅中)、图书录入时间(开始时间和结束时间,YYYY-MM-DD即可)

因为是单表查询,我们仍然使用5.6 Mybatis代码生成器Mybatis Generator (MBG)实战详解 中的example方式

BookServiceImpl

对于example方式,根据需求,我们主要是构建BookExample

/**
 * 组装图书列表查询的BookExample
 **/
private BookExample buildBookPageExample(BookListParamBO paramBO) {
    BookExample example = new BookExample();
    BookExample.Criteria criteria = example.createCriteria();
    if (!StringUtils.isEmpty(paramBO.getBookName())) {
        // 图书名称不为空, 模糊查询图书名称, 等同于sql: and book_name like 'xxx%'
        criteria.andBookNameLike(paramBO.getBookName() + "%");
    }
    if (!StringUtils.isEmpty(paramBO.getBookNo())) {
        // 图书编号不为空, 模糊查询图书编号
        criteria.andBookNoLike(paramBO.getBookNo() + "%");
    }
    if (!StringUtils.isEmpty(paramBO.getAuthor())) {
        // 作者不为空, 模糊查询作者
        criteria.andAuthorLike(paramBO.getAuthor() + "%");
    }
    if (paramBO.getStatus() != null) {
        // 图书状态不为空, 指定查询该状态
        criteria.andStatusEqualTo(paramBO.getStatus());
    }
    if (paramBO.getStartDay() != null) {
        // 录入开始时间不为空, >= 录入开始时间
        criteria.andGmtCreateGreaterThanOrEqualTo(paramBO.getStartDay());
    }
    if (paramBO.getEndDay() != null) {
        // 录入结束时间不为空, <= 录入结束时间
        criteria.andGmtCreateLessThanOrEqualTo(paramBO.getEndDay());
    }
    return example;
}

解读:只是筛选条件比较多:
对于Criteria,实际就是Where条件,只是将sql转成了Java对象方式,你更喜欢哪种?文末投票看看吧~

然后,查询就更简单了,调用selectByExample即可~

/**
 *  查询图书列表
 **/
private List<Book> getBookList(BookListParamBO paramBO) {
    // 组装Example
    BookExample example = buildBookPageExample(paramBO);
    // 查询
    return bookMapper.selectByExample(example);
}

BookListParamBO

参数BookListParamBO 就是查询列表的参数BO,定义在bo包下:

@Data
public class BookListParamBO implements Serializable {
    private String bookName;
    private String bookNo;
    private String author;
    private Integer status;
    private Date startDay;
    private Date endDay;
    private int pageNum = 1;
    private int pageSize = 10;
}

三、集成github.pageHelper并实现分页列表

上段已经实现了主查询,接下来,我们使用github.pageHelper实现通用分页!

第一步:引入pom依赖

在5.1 SpringBoot整合Mybatis, 老鸟教你五分钟学会:正确且全面的方式 中曾介绍过,SpringBoot的各种starter的用途,以及官方starter和第三方框架的starter命名规范,对于pageHelper,同样如此,只需引入pagehelper-spring-boot-starter !

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.2.10</version>
</dependency>

因为是通用功能,所以依赖放到tg-book-common中,版本号在父项目的dependencyManagement节点指定,详见 2-1. Maven 三层项目结构搭建 和 2-2. SpringBoot API开发详解

温馨提示: 加入依赖以后,别忘了刷新Maven依赖

第二步:实现分页查询

BookService方法定义

Page<BookBO> getBookPage(BookListParamBO bookListParamBO);

Page是返回结果,这是github.pageHelper定义的通用分页结果,在下面封装通用返回结果时再映射相应字段。

BookServiceImpl核心实现

这是本文的核心,也是重点!

github.pageHelper如何通过一个主查询,就能实现的分页呢?

这里介绍我比较喜欢的使用方式:

Page<XxxBO> page = PageHelper.startPage(pgeNum, pageSize)
	.doSelectPage(() -> 你的查询方法);

不仅实现了通用分页,还非常明确且简洁。这里主要使用基础知识的是【泛型】和【Lambda表达式】,如果这两个还不熟悉的同学尽快补充一下【Java技能树】

  • PageHelper.startPage返回的是Page<E>泛型对象

在这里插入图片描述

  • doSelectPage传入的是ISelect接口参数

ISelect接口只有一个无参无返回值的方法
在这里插入图片描述
目的是调用我们的任意方法。
在这里插入图片描述
当然你可能好奇,这里是如何处理返回结果的,实际内部是使用的Mybatis拦截器Interceptor,自动实现的的count方法,组装的全部逻辑,感兴趣的同学可以查看其源码,这不是本文的重点,所以不做赘述!

OK,本文图书列表的分页的核心实现如下:

@Override
public Page<BookBO> getBookPage(BookListParamBO paramBO) {
    // 组装Example
    BookExample example = buildBookPageExample(paramBO);
    // 查询并分页
    Page<Book> page = PageHelper.startPage(paramBO.getPageNum(), paramBO.getPageSize())
            .doSelectPage(() -> bookMapper.selectByExample(example));

    // Page<Book> 转成 Page<BookBO>
    Page<BookBO> pageBO = new Page<>();
    BeanUtils.copyProperties(page, pageBO);
    for (Book book : page.getResult()) {
        BookBO bookBO = new BookBO();
        BeanUtils.copyProperties(book, bookBO);
        pageBO.add(bookBO);
    }
    return pageBO;
}

可以看到,分页的代码非常少,只是PO转BO的代码有点繁琐,不要急,后面会做单独封装,会单独写一篇详细讲解!
特别注意: 对于doSelectPage内的【Lambda表达式】请保证只调用Mapper方法,因为它只会对Mapper返回结果做Interceptor,所以如果你调用Mapper以后做了其它处理,它是无法感知到的,那也就不会生效!所以请不要那样使用!!!

BooKBO

因为筛选条件中有【图书状态】和 【录入时间】,所以在BooKBO中,也补充上这两个字段:

@Data
public class BookBO implements Serializable {
    private Integer id;
    private String bookNo;
    private String bookName;
    private Integer bookType;
    private String author;
    private String description;
    private String publisher;
    private Date publishDate;
    private String coverImage;
    // 图书状态(0-闲置 1-借阅中)
    private Integer status;
    // 录入时间
    private Date gmtCreate;
}

四、封装通用分页结果

上面实现了Service层,接下来在BookAdminController中定义API:

@PostMapping("/book/list")
public TgResult<BookBO> getBookList(@RequestBody BookListParamVO bookListParamVO) {
    return TgResult.ok(bookService.getBookPage(bookListParamVO.toBO()));
}

因为参数比较多,所以我们采用Post Body的方式,参数少的话还是推荐Get请求!

TgResult

为了支持分页,需要在通用结果 TgResult 增加分页相关返回字段,如下:

// 分页结果==========
// 当前页码
private int pageNum;
// 每页计录数
private int pageSize;
// 总数
private long totalCount;
// 总页数
private long totalPages;
// 分页数据列表
private List<T> dataList;

并增加ok重载支持分页结果Page,也就是从Page中拿出有用的字段返回结前端:

public static <T> TgResult<T> ok(Page<T> page) {
    TgResult<T> result = build(true, "200", "成功", null);
    result.setPageNum(page.getPageNum());
    result.setPageSize(page.getPageSize());
    result.setTotalCount(page.getTotal());
    result.setTotalPages(page.getPages());
    result.setDataList(page.getResult());
    return result;
}

BookListParamVO

@Data
public class BookListParamVO implements Serializable {
    private String bookName;
    private String bookNo;
    private String author;
    private Integer status;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date startDay;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date endDay;
    private int pageNum = 1;
    private int pageSize = 10;

    public BookListParamBO toBO(){
        BookListParamBO bo = new BookListParamBO();
        // 结束时间到当天的23:59:59,如果默认传入的是年月日,所以需要单独设置
        BeanUtils.copyProperties(this, bo, "endDay");
        bo.setEndDay(getDayEndTime(this.endDay));
        return bo;
    }

    /**
     * 获取指定时间的那天 23:59:59.999 的时间
     */
    private Date getDayEndTime(final Date date) {
        if (date == null) {
            return null;
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.HOUR_OF_DAY, 23);
        c.set(Calendar.MINUTE, 59);
        c.set(Calendar.SECOND, 59);
        c.set(Calendar.MILLISECOND, 999);
        return c.getTime();
    }
}

主要是做了时间格式处理,保证查询的结束时间为23:59:59.999 的时间

application.properties

统一返回时间格式为 yyyy-MM-dd HH:mm:ss

spring.jackson.date-format=yyyy-MM-dd HH:mm:ss

PostMan走一波

在这里插入图片描述


最后

想要看更多实战好文章,还是给大家推荐我的实战专栏–>《基于SpringBoot+SpringCloud+Vue前后端分离项目实战》,由我和 前端狗哥 合力打造的一款专栏,可以让你从0到1快速拥有企业级规范的项目实战经验!

具体的优势、规划、技术选型都可以在《开篇》试读!

订阅专栏后可以添加我的微信,我会为每一位用户进行针对性指导!

另外,别忘了关注我:天罡gg ,发布新文不容易错过: https://blog.csdn.net/scm_2008

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FastDFS单机部署及SpringBoot整合

前言 FastDFS是一个开源的高性能分布式文件系统。它的主要功能包括&#xff1a;文件存储、文件同步和文件访问&#xff08;文件上传和文件下载&#xff09;&#xff0c;可以解决高容量和负载平衡问题。FastDFS应满足其服务基于文件的网站的要求&#xff0c;如照片共享网站和视…

Maynor的博客专家成长之路——暨2023年中复盘

文章目录 博客专家成长之路——暨2023年中复盘前言念念不忘的博客专家每天只做三件事敲代码写博客健健身 我的感悟 不足之处未来&#xff1a;和CSDN共同成长最后 博客专家成长之路——暨2023年中复盘 前言 ​ 2023年不知不觉已经过去了半年有余&#xff0c;也是时候作年中复盘…

ChatGPT 是什么?

写在前面&#xff1a;这篇文章是今年1月份对chatgpt做调研学习时写的&#xff0c;都是从别处搬来的&#xff0c;纯扫盲的作用。本来一直以草稿的形势存在&#xff0c;但今天整理博客&#xff0c;顺便给发出来吧。 文章目录 1. ChatGPT简介1.1 ChatGPT 支持的场景举例 2 ChatGPT…

计算机网络————应用层

文章目录 概述域名系统DNS域名结构域名服务器解析过程常见的DNS记录DNS报文格式基础结构部分问题部分资源记录(RR, Resource Record)部分 万维网WWWURLHTTPHTTP发展HTTP报文结构请求报文响应报文 cookie 内容分发网络CDN 概述 应用层的具体内容就是规定应用进程在通信时所遵循的…

python数据分析之利用多种机器学习方法实现文本分类、情感预测

大家好&#xff0c;我是带我去滑雪&#xff01; 文本分类是一种机器学习和自然语言处理&#xff08;NLP&#xff09;任务&#xff0c;旨在将给定的文本数据分配到预定义的类别或标签中。其目标是为文本数据提供自动分类和标注&#xff0c;使得可以根据其内容或主题进行组织、排…

【AI】PyTorch安装记录及Anaconda环境配置

【AI】PyTorch安装记录及Anaconda环境配置 说下本地环境&#xff0c;RTX4070 12GB GPU&#xff1b;618刚买&#xff0c;不能让他闲着&#xff0c;配置一下炼丹环境&#xff0c;开始为打工人工作。为了方便后续部署模型之间依赖不冲突&#xff0c;所以使用Anaconda管理Python环…

网络环境TFTPNFS搭建

文章目录 1. TFTP服务搭建2. NFS 环境搭建 1. TFTP服务搭建 1、Ubuntu上搭建TFTP服务器&#xff0c;需要安装tftp-hpa和tftpd-hpa&#xff0c;命令如下&#xff1a; sudo apt-get install tftp-hpa tftpd-hpa sudo apt-get install xinetd2、TFTP也需要一个文件夹来存放文件…

Django DRF - 【Token】认证基本使用

一. 前言 Django Rest Framework Token是Django Rest Framework中的一个扩展&#xff0c;用于实现用户认证和授权。它为每个用户生成一个唯一的Token&#xff0c;并将其存储在数据库中。在用户进行API请求时&#xff0c;用户需要在请求的HTTP Header中包含Token&#xff0c;这…

考场作弊行为自动抓拍告警算法 yolov7

考场作弊行为自动抓拍告警系统通过yolov7python网络模型算法&#xff0c;考场作弊行为自动抓拍告警算法实时监测考场内所有考生的行为&#xff0c;对考生的行为进行自动抓拍&#xff0c;并分析判断是否存在作弊行为。YOLOv7 的发展方向与当前主流的实时目标检测器不同&#xff…

关于Apache Dubbo反序列化漏洞(CVE-2023-23638)的预警提示与对应的Zookeeper版本

公司在升级dubbo过程中因zookeeper版本不匹配&#xff0c;导致服务注册和调用出现异常 一、漏洞详情 Apache Dubbo是一款高性能、轻量级的开源Java服务框架。 Apache官方发布安全公告&#xff0c;修复了Apache Dubbo中的一个反序列化漏洞&#xff08;CVE-2023-23638&#xff…

玩转C++调试之Python的GDB库增强

玩转C调试之Python的GDB库增强 0.导语 调试是软件开发过程中不可或缺的一环&#xff0c;而GDB&#xff08;GNU调试器&#xff09;作为一款功能强大的调试工具&#xff0c;在开发者中得到广泛应用。除了传统的命令行调试功能外&#xff0c;GDB还提供了Python的GDB库&#xff0c;…

计算机网络——自顶向下方法(第一章学习记录)

什么是Internet? 可以从两个不同的方面来理解Internet。&#xff08;它的构成。它的服务&#xff09; 1.因特网的主要构成 处在因特网的边缘部分就是在因特网上的所有主机&#xff0c;这些主机又称为端系统&#xff08;end system&#xff09;&#xff0c;端系统通过因特网服…

【C2】文件,时间,多线程,动静态库

文章目录 1.文件&#xff1a;fprint/fgets/fwrite/fread&#xff0c;ftell/rewind/fseek/fflush1.1 文本文件&#xff1a;FILE结构体1.2 二进制文件&#xff1a;没有行概念1.3 文件定位&#xff1a;linux下文本文件模式和二进制文件模式没有区别。fgets和fprintf以行方式读写文…

【测试效率提升技巧】xmind测试用例转换为excel工具使用手册

【测试效率提升技巧】xmind测试用例转换为excel工具使用手册 一、前置环境配置二、执行Xmind2testcase的转换方法1.在控制台输入xmind2testcase [path/xmind文件路径] [-csv] [-xml] [-json]&#xff0c;例&#xff1a;xmind2testcase /root/homin/XX测试点.xmind -csv ##在当前…

MacOS 升级golang版本后无法debug,升级delve版本

golang版本升级到1.20以后导致debug失效了&#xff0c;本文针对MacOS系统&#xff0c;win系统也可作参考。 WARNING: undefined behavior - version of Delve is too old for Go version 1.20.4 (maximum supported version 1.19) 1、升级delve版本 brew install delve 安装…

抖音seo账号矩阵系统源码代开发组件

一.开发矩阵系统的项目背景&#xff1a; 目录 一.开发矩阵系统的项目背景&#xff1a; 二.短视频矩阵系统SaaS模板组件通常包含以下几个方面的内容&#xff1a; 三.抖音SEO账号矩阵系统源码的技术搭建过程可以分为几个步骤&#xff1a; 1.确定系统的需求和目标&#xff0c…

MATLAB App Designer基础教程 Matlab GUI入门(一)

MATLAB GUI入门 第一天 学习传送门&#xff1a; 【MATLAB App Designer基础教程Matlab GUI界面设计&#xff08;全集更新完毕-用户界面设计appdesigner&#xff08;中文&#xff09;Matlab Gui教程】 https://www.bilibili.com/video/BV16f4y147x9/?p2&share_sourcecopy_…

Spring Boot是什么?详解它的优缺点以及四大核心

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 目录 一、Spring Boot 是什么&#xff1f; 二、Spring Boot 的优缺点 1、优点 ①可快速构建独立的 Spring 应用 ②直接嵌入Tomcat、Jett…

基于SpringBoot+mybatis+layui就业管理系统设计和实现

基于SpringBootmybatislayui就业管理系统设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码联系方式 文…

Rust语言从入门到入坑——(11)面向对象

文章目录 0、引入1、封装2、继承3、多态4、引用 0、引入 Rust 不是面向对象的编程语言&#xff0c;但是可以实现面向对象方法&#xff1a;封装与继承&#xff0c;以及不完全的多态 1、封装 "类"往往是面向对象的编程语言中常用到的概念。"类"封装的是数据…