自定义注解,更优雅的使用MP分页功能
分页功能使用
MP的分页功能是通过MyBatis的插件实现的,使用起来也非常简单。下面先介绍下使用方式。
step1:配置分页插件
@Configuration
@EnableTransactionManagement
@MapperScan("com.csx.demo.spring.boot.dao")
public class MyBatisPlusConfig {
private static final Logger log = LoggerFactory.getLogger(MyBatisPlusConfig.class);
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 如果是单数据源的话,最好制定数据库类型,不然的话MP需要根据数据库连接来推断数据库类型
// 性能上略有损失
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
需要注意的是:MP提供了很多开箱即用的插件,这些插件的使用顺序有讲究。官方文档建议的配置顺序是:
目前已有的功能:
- 自动分页: PaginationInnerInterceptor
- 多租户: TenantLineInnerInterceptor
- 动态表名: DynamicTableNameInnerInterceptor
- 乐观锁: OptimisticLockerInnerInterceptor
- sql性能规范: IllegalSQLInnerInterceptor
- 防止全表更新与删除: BlockAttackInnerInterceptor
注意:
使用多个功能需要注意顺序关系,建议使用如下顺序
多租户,动态表名
分页,乐观锁
sql性能规范,防止全表更新与删除
总结: 对sql进行单次改造的优先放入,不对sql进行改造的最后放入
step2:写分页代码
IPage<User> page = new Page<>(1,10);
((Page<User>) page).addOrder(OrderItem.desc("user_id"));
IPage<User> userIPage = userDAO.selectPage(page, null);
自定义注解,更优雅的使用MP分页功能
我们发现:虽然MP的分页插件使用起来非常简单,但是还是需要每次从参数中拿分页参数、排序参数等,代码看起来还是略微显得冗余。
这边定义了一个自定义注解,可以简化上面的这些操作。下面是实现的代码。
step1:定义自己的PageInfo
说明下:这边的PageInfo是可以不定义的,你可以直接使用MP的IPage实现。但是个人具有洁癖,有些信息不想返回前端,所以定义了一个精简的PageInfo.
/**
* 自定义的PageInfo
* 内容比MP中的IPage精简
* @param <T>
*/
public class PageInfo<T> {
private Integer pageNo;
private Integer pageSize;
private String sortColumn;
private Long total;
private List<T> rows;
public PageInfo(Integer pageNo, Integer pageSize, String sortColumn) {
this.pageNo = pageNo;
this.pageSize = pageSize;
this.sortColumn = sortColumn;
}
// 省略get和set方法
}
step2:定义分页注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Pagination {
// 可以自定义分页字段名称,当前页字段名称默认是pageNO
String pageNoField() default "pageNo";
// 可以自定义分页字段名称,每页数量名称默认是pageNO
String pageSizeField() default "pageSize";
// 可以自定义分页字段名称,排序字段名称默认是pageNO
String sortField() default "sort";
// 也可以通过注解指定排序字段
String sortItem() default "";
}
step3:注解处理类
@Aspect
@Component
public class PaginationHandler {
private static final Logger log = LoggerFactory.getLogger(PaginationHandler.class);
private static final int DEFAULT_PAGE_NO = 1;
private static final int DEFAULT_PAGE_SIZE = 10;
@Around("@annotation(pagination)&&args(pageParam)")
public Object handlePagination(ProceedingJoinPoint point,
Pagination pagination,
Object pageParam) throws Throwable {
int pageNo = DEFAULT_PAGE_NO;
int pageSize = DEFAULT_PAGE_SIZE;
String sortCols;
String pageNoField = pagination.pageNoField();
String pageSizeField = pagination.pageSizeField();
String sortField = pagination.sortField();
sortCols = pagination.sortItem();
if (pageParam == null) {
PageInfo pageInfo = new PageInfo(pageNo, pageSize, sortCols);
PageUtil.setPageInfo(pageInfo);
} else {
if (pageParam instanceof Map) {
Map<String, Object> param = (Map<String, Object>) pageParam;
JSONObject json = new JSONObject(param);
if (json.getInteger(pageNoField) != null) {
pageNo = json.getIntValue(pageNoField);
}
if (json.getInteger(pageSizeField) != null) {
pageSize = json.getIntValue(pageSizeField);
}
if (json.getInteger(sortField) != null) {
sortCols = json.getString(sortField);
}
PageInfo pageInfo = new PageInfo(pageNo, pageSize, sortCols);
PageUtil.setPageInfo(pageInfo);
} else {
// 暂时只支持Map类型的参数
// 如果需要支持其他类型的参数,可以在这边添加
PageInfo pageInfo = new PageInfo(pageNo, pageSize, sortCols);
PageUtil.setPageInfo(pageInfo);
}
}
try {
Object result = point.proceed();
if (result instanceof Response) {
Object data = ((Response) result).getData();
if(data instanceof IPage){
long total = ((IPage) data).getTotal();
List records = ((IPage) data).getRecords();
PageInfo pageInfo = PageUtil.getPageInfo();
pageInfo.setTotal(total);
pageInfo.setRows(records);
((Response) result).setData(pageInfo);
}
return result;
} else {
// Todo 暂时没想到好的处理方法
return result;
}
} finally {
PageUtil.removePageInfo();
}
}
}
step4:分页工具
public class PageUtil {
private static final String ASC = "asc";
private static final String DESC = "desc";
private static final Logger log = LoggerFactory.getLogger(PageUtil.class);
private static final ThreadLocal<PageInfo> pageInfoHolder = new ThreadLocal<>();
public static void setPageInfo(PageInfo pageInfo) {
pageInfoHolder.set(pageInfo);
}
public static void removePageInfo() {
pageInfoHolder.remove();
}
public static PageInfo getPageInfo() {
return pageInfoHolder.get();
}
public static <T> IPage<T> page() {
PageInfo pageInfo = getPageInfo();
Integer pageNo = pageInfo.getPageNo();
Integer pageSize = pageInfo.getPageSize();
//col1:aes,col2:des形式
String sortCols = pageInfo.getSortColumn();
IPage<T> iPage = new Page<>(pageNo, pageSize);
if (!StringUtils.isEmpty(sortCols)) {
String[] split = sortCols.split(",");
for (String s : split) {
try {
int index = s.lastIndexOf(':');
String col = s.substring(0, index);
String sortType = s.substring(index, s.length());
if(ASC.equalsIgnoreCase(sortCols)){
((Page<T>) iPage).addOrder(OrderItem.asc(col));
} else if (DESC.equalsIgnoreCase(sortType)){
((Page<T>) iPage).addOrder(OrderItem.desc(col));
} else {
log.warn("sort col {} is invalid, ignore it...",s);
continue;
}
} catch (Exception e) {
log.warn("sort col {} is invalid, ignore it...",s);
}
}
}
return iPage;
}
}
step5:使用
@PostMapping("/page")
@Pagination
public Object info(@RequestBody Map param) {
IPage<User> page = userService.page(PageUtil.page(), null);
Response response = new Response();
response.success().success().setData(page);
return response;
}
上面的代码比较简单,具体就不分析了。
自定义注解,更优雅的使用MP分页功能的更多相关文章
- 手写SpringBoot自动配置及自定义注解搭配Aop,实现升级版@Value()功能
背景 项目中为了统一管理项目的配置,比如接口地址,操作类别等信息,需要一个统一的配置管理中心,类似nacos. 我根据项目的需求写了一套分布式配置中心,测试无误后,改为单体应用并耦合到项目中.项目中使 ...
- ssm+redis 如何更简洁的利用自定义注解+AOP实现redis缓存
基于 ssm + maven + redis 使用自定义注解 利用aop基于AspectJ方式 实现redis缓存 如何能更简洁的利用aop实现redis缓存,话不多说,上demo 需求: 数据查询时 ...
- 如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志 | 修订版
欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 资深架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...
- 用大白话聊聊JavaSE -- 自定义注解入门
注解在JavaSE中算是比较高级的一种用法了,为什么要学习注解,我想大概有以下几个原因: 1. 可以更深层次地学习Java,理解Java的思想. 2. 有了注解的基础,能够方便阅读各种框架的源码,比如 ...
- java中自定义注解的应用
要想深刻的理解注解,我们必须能实现自己的注解,然后应用自己的注解去实现特定的业务,使用注解可以更优雅的做到某些事情. 有这样一个场景,在需要文件导出时,我们需要将一个model中的一些重要字段导出到c ...
- SpringBoot系列(十三)统一日志处理,logback+slf4j AOP+自定义注解,走起!
往期精彩推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件详解 SpringBoot系列(四)we ...
- Spring中如何使用自定义注解搭配@Import引入内外部配置并完成某一功能的启用
文章背景 有一个封装 RocketMq 的 client 的需求,用来提供给各项目收.发消息,但是项目当中常常只使用收或者发消息的单一功能,而且不同的项目 group 等并不相同而且不会变化,可以在项 ...
- 如何通过自定义注解实现AOP切点定义
面向切面编程(Aspect Oriented Programming, AOP)是面向对象编程(Object Oriented Programming,OOP)的强大补充,通过横切面注入的方式引入其他 ...
- 使用 Promises 编写更优雅的 JavaScript 代码
你可能已经无意中听说过 Promises,很多人都在讨论它,使用它,但你不知道为什么它们如此特别.难道你不能使用回调么?有什么了特别的?在本文中,我们一起来看看 Promises 是什么以及如何使用它 ...
随机推荐
- Making Games with Python & Pygame 中文翻译
Making Games with Python & Pygame 用Pygame做游戏 第1章-安装python和pygame 原文作者:Al Sweigart 翻译:bigbigli/李超 ...
- Proxy:简单小巧又强大好用的代理系统
之前的文章介绍了许多我们在用的DevOps相关的工具系统,例如:方便创建多套运行环境的Alodi,对运维友好的配置中心Kerrigan,强大的自定义任务引擎Probius以及专注于数据库自动化的ove ...
- 半夜删你代码队 Day6冲刺
一.每日站立式会议 1.站立式会议 成员 昨日完成工作 今日计划工作 遇到的困难 陈惠霖 完成注册界面 好友界面 无 侯晓龙 了解数据库使用 帮助他人建立数据库 无 周楚池 完成登录界面+管理员界面初 ...
- 通过url传递对象
1.使用 encodeURI() 对对象进行编码 2.在另一个页面使用
- Deep Learning with Differential Privacy
原文链接:Deep Learning with Differential Privacy abstract:新的机器学习算法,差分隐私框架下隐私成本的改良分析,使用非凸目标训练深度神经网络. 数学中最 ...
- Codeforces Edu Round 52 A-E
A. Vasya and Chocolate 模拟题.数据会爆\(int\),要开\(long\) \(long\) #include <iostream> #include <cs ...
- 电脑获取手机app内的scheme
做app开发,有时需要跳转打开外部的app应用,来促成引流或者分享等,这个时候就需要通过scheme跳转协议来完成. 使用scheme跳转外部app,就需要配置对应app的scheme,那这个sche ...
- 1.pipeline原理
redis基本语法:https://www.cnblogs.com/xiaonq/p/7919111.html redis四篇:https://www.cnblogs.com/xiaonq/categ ...
- 马赛克密码破解——GitHub 热点速览 Vol.50
作者:HelloGitHub-小鱼干 "xx"(爆粗口) 这个词是最能体现本人看到本周 GitHub 热点的心情的.那一天,看到用图片处理技术还原马赛克密码的 Depix 便惊为天 ...
- el-amap 遮罩(带洞多边形)
el-amap 遮罩(带洞多边形) 遮罩(带洞多边形) 效果图 代码 <template> <div> <el-amap vid="amapDemo" ...