前言
本文中介绍的项目框架使用的是springboot+mybatisplus,如果项目中使用的是mybatis框架,具体分页功能的实现方式有一些区别,在这里不过多赘述。
基于mybatisplus配置使用PageHelper分页插件
1.1 依赖
在pom文件中引入Mybatis-plus的启动器依赖
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<!-- 选择合适的版本 -->
<version>${mybatis.plus.version}version>
dependency>
1.2 分页拦截器配置
使用分页插件需要配置MybatisPlusInterceptor
,将分页拦截器添加进来
@Configuration
publicclassMybatisPlusConfig {
@Bean
publicMybatisPlusInterceptormybatisPlusInterceptor() {
MybatisPlusInterceptorinterceptor=newMybatisPlusInterceptor();
interceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.MYSQL));
returninterceptor;
}
}
#将分页的拦截器配置写在config专门的配置类里,方便管理和使用。
1.3 项目中如何使用
配置完成后就可以使用mybatis-plus进行分页了。mybatis-plus在dao层包含了基础的增删改查方法,如额外需要其他方法,自己再在dao层添加即可,这就是使用mybatis-plus的一大好处,省略了dao层的编写。这里以自定义的sql查询为例:
1.3.1在xml中编写查询sql
<selectid="queryDesensitizationRulePage"
parameterType="com.zsmart.nros.mdm.common.query.DesensitizationRuleQuery"
resultMap="BaseResultMap">
select
id,measure_code, measure_name, type, type_name, rule, create_date, modify_date
fromdesensitization_rule
select>
1.3.2添加查询列表的mapper
接口
IPage<DesensitizationRuleInfo>queryDesensitizationRulePage(IPage<BaseModel>page, @Param("ruleQuery") DesensitizationRuleQueryruleQuery);
1.3.3分页工具类
自定义分页工具类,用于封装返回 Page 分页对象
publicfinalclassPageUtils {
publicstatic<TextendsBaseModel>IPage<T>buildPage(BaseQuerybaseQuery) {
Page<T>page=newPage<>();
page.setCurrent(baseQuery.getPageIndex() ==0?1 : baseQuery.getPageIndex());
page.setSize(baseQuery.getPageSize() ==0?10 : baseQuery.getPageSize());
returnpage;
}
}
1.3.4开启分页,返回查询结果集
publicIPagequeryDesensitizationRulePage(intpageIndex,intpageSize,DesensitizationRuleQueryruleQuery) {
BaseQuerybaseQuery=newBaseQuery();
#pageIndex参数是页码(从1开始),pageSize参数是分页大小
baseQuery.setPageIndex(pageIndex);
baseQuery.setPageSize(pageSize);
#和分页功能有关的Page<T>类
IPagepage=PageUtils.buildPage(baseQuery);
#使用的时候需要将创建的Page对象作为第一个参数
IPageiPage=desensitizationRuleMapper.queryDesensitizationRulePage(page, ruleQuery);
returniPage;
}
注意:参数和结果都是用Page对象来包装
1.3.5查询结果分析
控制台打印结果
[] -params: [{"pageIndex":1,"pageSize":3}]
[] -==> Preparing: SELECTCOUNT(*) AStotalFROMdesensitization_rule
[] -==>Parameters:
[] -<== Total: 1
[] -==> Preparing: selectid ,measure_code, measure_name, type, type_name, rule, create_date, modify_datefromdesensitization_ruleLIMIT?
[] -==>Parameters: 3(Long)
[] -<== Total: 3
返回的查询结果
{
"records": [ //用来存放查询出来的数据
{
"id": 18,
"measureCode": "1",
"measureName": "11",
"type": "FULLY_COVERED",
"typeName": "全部遮盖",
"rule": "{\"sign\": \"$$\"}",
"createDate": 1665729507000,
"modifyDate": 1665732256000
},
...
],
"total": 11,//返回记录的总数
"size": 3,//每页显示条数(默认值:10)
"current": 1,//当前页(默认值:1)
"orders": [],//排序字段信息
"optimizeCountSql": true,//自动优化 COUNT SQL(默认值:true)
"searchCount": true,//是否进行 count 查询,设置false后不会返回total(默认值:true)
"countId": null,
"maxLimit": null,//单页分页条数限制
"pages": 4//总页数
}
由上可以看到PageHelper分页插件主要帮我们干了两件事情:
a、执行了select count(*)...语句统计了数据总数;
b、在查询sql后面拼接了limit分页关键字和分页参数,进行分页查询。
PageHelper是如何帮我们做到这两件事情的呢?下面我们来具体分析一下
1.3.6原理与源码解析
IPage是基于拦截器,它拦截的是方法以及方法中的参数。它首先会判断是否是查询操作,如果是查询操作,才会进入分页的处理逻辑。进入分页逻辑处理后,拦截器会通过反射获取该方法的参数进行判断是否存在IPage对象的实现类。如果不存在则不进行分页,存在则将该参数赋值给IPage对象。然后进行count查询和拼接分页sql的操作。我们来看一下对应源码:
a、 对MybatisPlusInterceptor分页插件进行拦截会发现,当执行sql的时候mybatis-plus会对所有SQL语句进行拦截并做各种判断与附加操作。
b、 如果是查询语句,就会先执行willDoQuery方法,其次再执行 beforeQuery。因为在1.2拦截器配置中new出来的是 PaginationInnerInterceptor 对象,所以这里就会走该对象中的方法;
c、在willDoQuery()方法中对查询参数做了提取并通过ParameterUtils.findPage()
方法进行了转换判断,如果为空则返回null;如果有则返回IPage
类型的参数,并处理count语句。
d、willDoQuery方法执行完之后,调用了 beforeQuery()方法对分页查询进行了拦截。
beforeQuery()先是处理了orderBy语句拼接
然后又组装了分页语句
可以发现,PageHelper的分页实现其实是借助了拦截器的拦截功能,在查询之前对查询语句进行了改造,最终完成了分页查询的封装操作 。