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) {// 组装ExampleBookExample 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) {// 组装ExampleBookExample 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

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

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

相关文章

CSS_高度自动过渡 auto height

方法一 grid 布局中的 fr 单位&#xff08;推荐使用&#xff09; <div class"wrap"><button class"trigger">鼠标放上来试试</button><div class"grid"><div><p>高度自动过渡</p></div></d…

Linux服务器同步Windows目录同步-rsync

前言 最近需要&#xff0c;Linux的服务器同步Windows的一个目录。查了下&#xff0c;大概有三种方法&#xff1a;网盘同步&#xff1b;rsync同步&#xff1b;挂载目录。 网盘同步&#xff0c;可以选择搭建一个Nextcloud 。但是问题在于&#xff0c;我需要的是&#xff0c;客户…

LangChain-Agent自定义Tools类 ——输入参数篇(二)

给自定义函数传入输入参数&#xff0c;分别有single-input 参数函数案例和multi-input 参数函数案例&#xff1a; from langchain.agents import Tool from langchain.tools import BaseTool from math import pi from typing import Union from math import pi from typing …

金蝶云星空财务软件被locked勒索病毒攻击后如何更快解密数据库数据?

金蝶云星空财务软件是一款广泛应用于企业财务管理领域的软件&#xff0c;然而&#xff0c;近期很多企业的金蝶云星空财务软件遭受到了locked勒索病毒的攻击&#xff0c;导致数据库数据被加密。而这次的locked勒索病毒采用了新的加密形式&#xff0c;它不仅能够扫描出各种软件系…

LLM 应用参考架构:ArchGuard Co-mate 实践示例

随着&#xff0c;对于 LLM 应用于架构领域探索的进一步深入&#xff0c;以及 ArchGuard Co-mate 开发进入深入区&#xff0c;我们发现越来越多的通用模式。 在先前的文章里&#xff0c;我们总结了一系列的设计原则&#xff0c;在这篇文章里&#xff0c;我们将介绍 ArchGuard Co…

数字信号的载波传输

从信号传输质量来看&#xff0c;数字系统优于模拟系统。 由于数字基带信号的频谱包含低频成分&#xff0c;而许多重要的通信信道是带通型的&#xff0c;比如无线信道和许多有线信道&#xff0c;这时需要调制成数字频带信号。 数字调制与模拟调制原理基本相似&#xff0c;有调幅…

STM32单片机(三)第二节:GPIO输出练习3(蜂鸣器)

❤️ 专栏简介&#xff1a;本专栏记录了从零学习单片机的过程&#xff0c;其中包括51单片机和STM32单片机两部分&#xff1b;建议先学习51单片机&#xff0c;其是STM32等高级单片机的基础&#xff1b;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 &#xff1a;适用于想要…

UWB超宽带定位技术的原理及定位方法

uwb定位技术即超宽带技术&#xff0c;它是一种无载波通信技术&#xff0c;利用纳秒级的非正弦波窄脉冲传输数据&#xff0c;因此其所占的频谱范围很宽。传统的定位技术是根据信号强弱来判别物体位置&#xff0c;信号强弱受外界 影响较大&#xff0c;因此定位出的物体位置与实际…

centos8.x系统安装K8S,kubernetes集群v1.23.9,docker支持的最后一个版本

1. 部署环境主机&#xff08;条件说明&#xff09; 卸载podman&#xff0c;centos默认安装了podman容器&#xff08;不管有没有&#xff0c;执行下总没错&#xff09;&#xff0c;可能与docker存在冲突 #环境准备 master 192.168.186.128 CentOS Linux release 8.5 (Core) n…

CentOS 挂载ntfs格式U盘

1、查看磁盘信息 fdisk -l 如上图所示&#xff0c;可以看到插入的U盘/dev/sdc 2、查看磁盘块信息 lsblk 如上图所示&#xff0c;sdc即是插入的U盘&#xff0c;sdc1为磁盘块&#xff0c;挂载的时候使用sdc1 3、查看磁盘文件系统类型 parted -l 如上图所示&#xff0c;U盘是WD…

Electron + ts + vue3 + vite 项目搭建

Electron 是一个基于 Chromium 和 Node.js 的桌面应用程序开发框架&#xff0c;而 Vue3 则是一种流行的前端框架。将两者结合使用可以快速地打造出跨平台的桌面应用程序。在这种组合中&#xff0c;Electron 提供了强大的桌面应用开发能力&#xff0c;而 Vue3 则提供了易用的 UI…

4.28 白噪声功率谱密度的估计

前一节有下面结论&#xff1a; 什么仿真的白噪声波形是均匀的&#xff0c;均匀的特点是相关函数在0时刻是相关的&#xff08;自己和自己相关的&#xff09;0以外时刻都互相不相关