自定義註解,更優雅的使用MP分頁功能
阿新 • • 發佈:2021-01-12
分頁功能使用
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;
}
上面的程式碼比較簡單,具體就不分析了。