CSDN:https://blog.csdn.net/NOT_TWO_CHEN/
简书:https://www.jianshu.com/p/a24a9ff323c9
一. 开发准备
1. 开发工具
2. 开发环境
3. 开发依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.3version>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-starterartifactId>
<version>1.3.0version>
dependency>
二. 技术文档
1. 基于SpringBoot
2. 基于MyBatis
3. 集成PageHelper
https://github.com/javastacks/spring-boot-best-practice
三. 应用讲解
1. 基本使用
在实际项目运用中,
PageHelper
的使用非常便利快捷,仅通过
PageInfo
+
PageHelper
两个类,就足以完成分页功能,然而往往这种最简单的集成使用方式,却在很多实际应用场景中,没有得到充分的开发利用.
接下来是我们最常见的使用方式:
public PageInfo page(RequestParamDto param) {
PageHelper.startPage(param.getPageNum(), param.getPageSize());
List list = mapper.selectManySelective(param);
PageInfo pageInfo = (PageInfo)list;
return pageInfo;
}
在某种程度上而言,上述写法的确是符合PageHelper的使用规范 :
在集合查询前使用`PageHelper.startPage(pageNum,pageSize)`,并且*中间不能穿插执行其他SQL*
但是作为Developer的我们,往往只有在追求完美和极致的道路上才能够寻得突破和机遇;
以下是合理且规范的基本使用:
public PageInfo page(RequestParamDto param) {
return PageHelper.startPage(param.getPageNum(), param.getPageSize())
.doSelectPageInfo(() -> list(param))
}
public List list(RequestParamDto param) {
return mapper.selectManySelective(param);
}
FAQ
1. 为什么要重新声明一个list函数?
答: 往往在很多实际业务应用场景中,
分页查询
是基于大数据量的表格展示需求来进行的.
然而很多时候,
譬如
: 内部服务的互相调用,
OpenAPI
的提供.
甚至在某些前后端分离联调的业务场景中,是同样需要一个非分页集合查询接口来提供服务的.
另外,暂时以上因素抛开不谈,我们可以根据上述写法来定义和规范某些东西
譬如
: 分页和集合查询的
分离和解耦
(解耦详情请看进阶使用),
分页请求的请求和响应与实际业务
参数的分离
(详情请看进阶使用)等等...
2.
doSelectPageInfo
是什么?
答:
doSelectPageInfo
是
PageHelper.startPage()
函数返回的默认
Page
实例内置的函数,该函数可以用以
Lambda
的形式通过额外的
Function
来进行查询而不需要再进行多余的
PageInfo
与
List
转换,而
doSelectPageInfo
的参数则是
PageHelper
内置的
Function(ISelect)
接口用以达到转换
PageInfo
的目的
3. 这种写法的代码量看起来不少反多?
答: 正如同①中所描述的,就代码量而言,确实没有更进一步的简化,但是再某些业务场景中,在已具有
list
函数接口的情况下,是一种更直观的优化(优化详情请看进阶使用)
2. 进阶使用
先看代码,再谈解析:
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import java.util.List;
/**
* @param 泛型request
* @param 泛型response
*/
public interface BaseService<Param, Result> {
/**
* 分页查询
*
* @param param 请求参数DTO
* @return 分页集合
*/
default PageInfo page(PageParam param) {
return PageHelper.startPage(param).doSelectPageInfo(() -> list(param.getParam()));
}
/**
* 集合查询
*
* @param param 查询参数
* @return 查询响应
*/
List list(Param param);
}
可以看到
BaseService
可以作为全局
Service
通用接口的封装和声明,而作为通用分页接口page函数却在此处利用
interface
特有关键字
default
直接声明了
page
函数的方法体
body
import com.github.pagehelper.IPage;
import lombok.Data;
import lombok.experimental.Accessors;
@Data // 为省略冗余代码使用lombok 实际应有常规Getter/Setter Construction toString等
@Accessors(chain = true) // 此lombok注解是为了实现 Entity伪Build 譬如: entity.setX(x).setY(y)
public class PageParam<T> implements IPage {
// description = "页码", defaultValue = 1
private Integer pageNum = 1;
// description = "页数", defaultValue = 20
private Integer pageSize = 20;
// description = "排序", example = "id desc"
private String orderBy;
// description = "参数"
private T param;
public PageParam setOrderBy(String orderBy) {
this.orderBy = orderBy; // 此处可优化 优化详情且看解析
return this;
}
}
在
BaseService
中我们看到了一个新的
PageParam
,参考了
PageInfo
用以包装/声明/分离分页参数和业务参数,且参数类型为泛型,即支持任何数据类型的业务参数
同时也可以看到
PageParam
实现了
IPage
接口,并且多了一个
orderBy
属性字段
import common.base.BaseService;
import dto.req.TemplateReqDto;
import dto.resp.TemplateRespDto;
public interface TemplateService extends BaseService<TemplateReqDto, TemplateeRespDto> {
// 同为interface接口, 业务Service只需要继承BaseService
// 并根据实际使用场景声明请求参数和响应结果的Entity实体即可
}
在实际应用中,只需要声明我们通用的业务查询请求参数和响应结果即可
import dto.req.TemplateReqDto;
import dto.resp.TemplateRespDto;
import service.TemplateService;
import persistence.mapper.TemplateMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j // 基于lombok自动生成logger日志记录实例
@Service // SpringBoot中注册Service Bean的注解
@RequiredArgsConstructor