[TOC]
1、一款基于Mybatis的分页插件
2、可以兼容原生MyBatis、tk-Mybatis以及Mybatis-Plus等主流框架
3、解决复杂关联查询导致分页错误的问题 4、配合Web层拦截,实现无侵入式分页
添加依赖
<dependency>
<groupId>io.github.verygoodwlk</groupId>
<artifactId>ken-page-boot-starter</artifactId>
<version>1.2.9</version>
</dependency>
开启分页 - 在业务合适的地方,调用以下代码开启分页
//pageNum - 当前页码
//pageSize - 每页显示多少条
//注意:这行代码后,当前业务的所有数据库查询操作都将自动实现分页效果
KenPages.setPage(pageNum, pageSize);
查询后获取分页信息(总条数、总页码等数据)
//分页的相关信息
Page page = KenPages.getPage();
int count = page.getCount(); //获得总记录数
int totle = page.getTotle(); //总页数
注意:因为分页插件的无侵入设计,可以随时停止所有分页的功能。只需在application.yml中配置即可
#关闭分页功能 - 分页的业务会自动变成查询全部,默认开启
kenplugin:
page:
enable: false
插件自带SQL执行记录以及耗时监控功能,所有运行的sql语句以及相关参数还有耗时时间都将被日志记录
[SQL] executor - [select * from test where id = ?]
[SQL] params[0] - [id:5]
[SQL] take up time - [0.013s]
关闭SQL执行监控,只需要在application.yml配置即可
#关闭SQL记录,默认开启
kenplugin:
execsql:
enable: false
在一些复杂的业务中,可能存在多个子业务,有些子业务可能需要分页,有些子业务不需要,则可以使用定制化分页的功能
开启分页定制化
//参数二:表示开启定制化分页,默认关闭
KenPages.setPage(pageNum, pageSize, true);
标记分页注解 - 通常在子业务方法或者mapper接口方法上标记
主业务方法(){
//开启分页
KenPages.setPage(pageNum, pageSize, true);
//子业务1方法
//子业务2方法
//子业务3方法
//子业务4方法
}
子业务1方法(){
}
@Paging
子业务2方法(){
}
子业务3方法(){
}
@Paging
子业务4方法(){
}
当前模式下,只有标注了@Paging注解的业务,才会受到分页的影响
@Paging注解可以直接标记在Mapper接口的方法上
实际开发过程中,SQL可能会关联多张表查询,导致查出来的分页结果会存在数量不足的问题,比如
select * from
table1 t join table2 t2 on t1.id = t2.tid
以上这条SQL,本意是讲table1作为主表,关联查询出table2的结果,table2的结果作为子集放入到table1对应的记录中。
此时,如果要分页,应该是对table1表进行分页,但是因为关联的存在,实际table1查询出来的记录,并不会满足当前页的记录数。
解决方案
我们需要调整下SQL的结构
select * from
(select * from table1 limit ?) t join table2 t2 on t.id = t2.tid
table1作为主表,我们可以人为将主表的查询部分独立出来,然后在主表查询后面跟上limit ?, 插件会自动判别到该部分为主表查询,会先对该部分分页,再将分页出来的结果去关联其他表, 这样就会得到正确的分页结果。实际情况可能比这个复杂的多,所以需要开发者根据实际的业务去动态调整SQL语句的结构。
开启Web层分页兼容配置(默认关闭)
#开启web层分页兼容配置
kenplugin:
page:
webconfig:
enable: true
客户端传递分页参数
#pageNum - 当前页
#pageSize - 每页显示多少条
http://server.com/xxxx?pageNum=1&pageSize=5
开启web层兼容分页后,只需要客户端传递分页参数,后续业务会自动化完成分页, 无需再使用KenPages.setPage(new Page(pageNum, pageSize));方法来开启分页。
业务复杂的情况下,仍然可以使用@Paging注解实现定制化分页
定制分页参数名称
当不想使用pageNum和pageSize作为参数名称时,可以定制名称
kenplugin:
page:
key:
#定制当前页的参数名称
num: pageNo
#定制每页条数的参数名称
size: pageS
#定制返回的总条数参数名称
count: pageCount
#定制返回的总页码数参数名称
total: pageTotal
返回分页信息给客户端
Web层(Controller方法)返回的对象必须继承BaseResult类,比如
class OutPut<T> extends BaseResult{
Integer code;
String msg;
T datas;
}
@RequestMapping("/xxx/xxx")
public OutPut<List<A>> xxxx(){
}
客户端会收到如下的结果数据:
{
//分页信息 - 属性名称通过上面的参数可自定义(不设置则采用默认参数名称)
"page": {
"pageNo": 1,
"pageS": 2,
"pageCount": 25,
"pageTotal": 13
},
"code": 200,
"message": "请求成功",
"data": [
{
//数据部分....
}
]
}
实际开发过程中,可能会面临很多关联查询,这些查询结果需要映射到实体类集合中,为了实现嵌套映射,往往开发者需要编写大量的 ResultMap 标签内容来手动构建查询结果和实体类的映射关系。 自动映射功能并不是原来单纯的单表映射,而是可以借助注解轻松实现多表关联查询的自动映射。
注意: 1、该功能目前处于测试阶段,如果有任何问题可以直接关闭或者局部关闭,不影响原来正常功能的使用 2、该功能目前需要配合Mybatis-plus插件一起使用,原生或其他框架暂时不支持 3、该功能对Mybatis底层侵入较深,会影响一定的性能,请慎用,后续版本会进行性能优化
使用步骤
开启自动映射功能
#开启自动映射功能(默认关闭)
kenplugin:
auto:
mapping:
enable: true
编写Mapper.xml中的SQL语句
<!-- 这里直接使用resultType标签,指定接收的实体类类型 -->
<select id="queryAll" resultType="com.ken.entity.demo.Test">
select t.*, t2.id as lid, t2.likes, t2.like_time
<!-- 1对多关联查询 -->
from test t join test2 t2 on t.id = t2.uid
</select>
配置实体类
//采用lombok简化开发,可以无视
@Data
@Accessors(chain = true)
public class Test implements Serializable {
//使用mybatis-plus标签标识主键,如果数据库主键名称和当前字段名称不相同,可以通过value属性设置
@TableId(type = IdType.AUTO)
private Integer id;
//未标识的字段,默认和数据库同名列映射
private Integer age;
//如果数据库字段名称和当前字段名称不相同,可以通过@TableField注解value属性设置
//还可以通过该注解设置该列的typeHandler等属性
@TableField("p_name")
private String name;
//防止插入报错,告诉Mybatis-plus忽略该字段
@TableField(exist = false)
//标识对多映射,指定对多的集合体中实际的类型
//如果是对一映射,可以使用@ToOne注解即可
@ToMore(type = Test2.class)
private List<Test2> likes;
}
//关联的实体类 多的一方
@Data
@Accessors(chain = true)
public class Test2 implements Serializable {
@TableId(type = IdType.AUTO)
//需要注意,如果两个表的主键同名,需要通过@IdAlias注解设置一个别名id和数据库的主键映射,SQL语句中也必须指定id别名
@IdAlias("lid")
private Integer id;
private Integer uid;
private String likes;
private Date likeTime;
}
添加查询注解
//标注@AutoMapping的方法,才会启动自动映射的功能,起到一个局部控制的作用
@AutoMapping
List<Test> queryAll();
执行查询查看结果
...
"data": [
{
"id": 1,
"name": "小明",
"age": 18,
"likes": [
{
"id": 5,
"uid": 1,
"likes": "篮球",
"likeTime": "2007-09-08"
},
{
"id": 7,
"uid": 1,
"likes": "乒乓球",
"likeTime": "2005-01-07"
},
...
]
},
...
]
...