分页功能使用

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. 【题解】Fuzzy Google Suggest(UVA1462)

    题目链接 题意 给定一个字符串集合,有n次搜索,每次有一个整数x和一个字符串,表示可以对字符串进行x次修改, 包括增加.修改和删除一个字符,问修改后的字符串可能是字符集中多少个字符串的前缀. 思路 简 ...

  2. MySQL 5.7.29主从安装配置

    一.环境准备(关闭防火墙) 1.清除已安装数据库 [root@mysql01 ~]# rpm -qa | grep mariadb mariadb-libs-5.5.35-3.el7.x86_64 [ ...

  3. 08-flask-使用pymysql

    代码 from flask import Flask from flask import render_template import pymysql # 创建flask对象 app = Flask( ...

  4. vue第十七单元(电商项目逻辑处理,电商划分)

    第十七单元(电商项目逻辑处理,电商划分) #课程目标 1.什么是电商项目 2.什么是B2B,B2C,C2C模式,常见的电商项目 3.移动端电商项目常见的逻辑处理 4.[知识扩展]传统系统架构及分布式系 ...

  5. Python高级语法-多继承MRO相关-args和kwargs(4.5.2)

    @ 目录 1.说明 2.代码 关于作者 1.说明 args数据类型为元组 kwargs数据类型为字典 一般传入方法中使用遍历去得到值 这个传入参数的顺序没有特殊的要求 当你自定义的参数传完以后,写了名 ...

  6. js 获取某月第一天和最后一天

    1.获取某月第一天和最后一天日期 function getDateByMonth (timeStamp) { let inDate = new Date(timeStamp) let year = i ...

  7. Bootstrap留言板界面练习

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  8. 老哥你能写篇 SpringCloud Alibaba 全家桶吗? 看视频太累 太枯燥了 !

    最喜欢的一句话: 1.01的365次方=37.78343433289 >>>1 0.99的365次方= 0.02551796445229, 每天进步一点点的目标,贵在坚持 前端时间有 ...

  9. 自动测试LeetCode用例方法

    自动合并测试LeetCode解题方法 在leetcode.com上答题,Run Code或者Sumbmit通常要Spending一会,如果提交一次就Accepted那还好,如果反复Wrong Answ ...

  10. [Python] iupdatable包:Timer 类使用介绍

    iudatable包是我对常用函数进行的封装后发布的一个python包,教程汇总目录: [Python] iupdatable包使用说明 安装 iupdatable 包 pip install iup ...