分页功能使用

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分页功能的更多相关文章

  1. 手写SpringBoot自动配置及自定义注解搭配Aop,实现升级版@Value()功能

    背景 项目中为了统一管理项目的配置,比如接口地址,操作类别等信息,需要一个统一的配置管理中心,类似nacos. 我根据项目的需求写了一套分布式配置中心,测试无误后,改为单体应用并耦合到项目中.项目中使 ...

  2. ssm+redis 如何更简洁的利用自定义注解+AOP实现redis缓存

    基于 ssm + maven + redis 使用自定义注解 利用aop基于AspectJ方式 实现redis缓存 如何能更简洁的利用aop实现redis缓存,话不多说,上demo 需求: 数据查询时 ...

  3. 如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志 | 修订版

    欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 资深架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...

  4. 用大白话聊聊JavaSE -- 自定义注解入门

    注解在JavaSE中算是比较高级的一种用法了,为什么要学习注解,我想大概有以下几个原因: 1. 可以更深层次地学习Java,理解Java的思想. 2. 有了注解的基础,能够方便阅读各种框架的源码,比如 ...

  5. java中自定义注解的应用

    要想深刻的理解注解,我们必须能实现自己的注解,然后应用自己的注解去实现特定的业务,使用注解可以更优雅的做到某些事情. 有这样一个场景,在需要文件导出时,我们需要将一个model中的一些重要字段导出到c ...

  6. SpringBoot系列(十三)统一日志处理,logback+slf4j AOP+自定义注解,走起!

    往期精彩推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件详解 SpringBoot系列(四)we ...

  7. Spring中如何使用自定义注解搭配@Import引入内外部配置并完成某一功能的启用

    文章背景 有一个封装 RocketMq 的 client 的需求,用来提供给各项目收.发消息,但是项目当中常常只使用收或者发消息的单一功能,而且不同的项目 group 等并不相同而且不会变化,可以在项 ...

  8. 如何通过自定义注解实现AOP切点定义

    面向切面编程(Aspect Oriented Programming, AOP)是面向对象编程(Object Oriented Programming,OOP)的强大补充,通过横切面注入的方式引入其他 ...

  9. 使用 Promises 编写更优雅的 JavaScript 代码

    你可能已经无意中听说过 Promises,很多人都在讨论它,使用它,但你不知道为什么它们如此特别.难道你不能使用回调么?有什么了特别的?在本文中,我们一起来看看 Promises 是什么以及如何使用它 ...

随机推荐

  1. Making Games with Python & Pygame 中文翻译

    Making Games with Python & Pygame 用Pygame做游戏 第1章-安装python和pygame 原文作者:Al Sweigart 翻译:bigbigli/李超 ...

  2. Proxy:简单小巧又强大好用的代理系统

    之前的文章介绍了许多我们在用的DevOps相关的工具系统,例如:方便创建多套运行环境的Alodi,对运维友好的配置中心Kerrigan,强大的自定义任务引擎Probius以及专注于数据库自动化的ove ...

  3. 半夜删你代码队 Day6冲刺

    一.每日站立式会议 1.站立式会议 成员 昨日完成工作 今日计划工作 遇到的困难 陈惠霖 完成注册界面 好友界面 无 侯晓龙 了解数据库使用 帮助他人建立数据库 无 周楚池 完成登录界面+管理员界面初 ...

  4. 通过url传递对象

    1.使用 encodeURI() 对对象进行编码 2.在另一个页面使用

  5. Deep Learning with Differential Privacy

    原文链接:Deep Learning with Differential Privacy abstract:新的机器学习算法,差分隐私框架下隐私成本的改良分析,使用非凸目标训练深度神经网络. 数学中最 ...

  6. Codeforces Edu Round 52 A-E

    A. Vasya and Chocolate 模拟题.数据会爆\(int\),要开\(long\) \(long\) #include <iostream> #include <cs ...

  7. 电脑获取手机app内的scheme

    做app开发,有时需要跳转打开外部的app应用,来促成引流或者分享等,这个时候就需要通过scheme跳转协议来完成. 使用scheme跳转外部app,就需要配置对应app的scheme,那这个sche ...

  8. 1.pipeline原理

    redis基本语法:https://www.cnblogs.com/xiaonq/p/7919111.html redis四篇:https://www.cnblogs.com/xiaonq/categ ...

  9. 马赛克密码破解——GitHub 热点速览 Vol.50

    作者:HelloGitHub-小鱼干 "xx"(爆粗口) 这个词是最能体现本人看到本周 GitHub 热点的心情的.那一天,看到用图片处理技术还原马赛克密码的 Depix 便惊为天 ...

  10. el-amap 遮罩(带洞多边形)

    el-amap 遮罩(带洞多边形) 遮罩(带洞多边形) 效果图 代码 <template> <div> <el-amap vid="amapDemo" ...