MyBatisPlus 封裝分頁(yè)方法示例
一、前言
作為一個(gè) CRUD 工程師,查詢必然少不了,分頁(yè)查詢更是常見,市面上也有很多成熟的分頁(yè)插件,都各有優(yōu)缺點(diǎn),這里整理一下,基于 MybatisPlus 的分頁(yè)插件進(jìn)一步封裝分頁(yè)的公共方法。
二、對(duì)象封裝
其實(shí)分頁(yè)插件已經(jīng)提供了很強(qiáng)大的功能,但是在業(yè)務(wù)開發(fā)的時(shí)候不夠精簡(jiǎn),返回了很多我們并不關(guān)注的數(shù)據(jù),在這個(gè)基礎(chǔ)上進(jìn)一步封裝,使其更貼合我們的業(yè)務(wù)開發(fā)。
2.1 分頁(yè)結(jié)果對(duì)象封裝
首先我們定義一個(gè)通用的分頁(yè)結(jié)果對(duì)象,PageVO 包含我們關(guān)注的主要幾個(gè)數(shù)據(jù)值,總條數(shù),總頁(yè)數(shù),數(shù)據(jù)集。這里為了兼容各種數(shù)據(jù)類型,這里的數(shù)據(jù)集的類型通過(guò)泛型指定
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageVO<V> implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "總條數(shù)")
private Long total;
@Schema(description = "總頁(yè)數(shù)")
private Long pages;
@Schema(description = "數(shù)據(jù)")
private List<V> records;
}
2.2 分頁(yè)查詢對(duì)象封裝
為了兼容查詢對(duì)象的不同類型,這里使用泛型定義查詢對(duì)象類型,后面我們只需要根據(jù)使用場(chǎng)景定義對(duì)應(yīng)的 Query 對(duì)象就可以了
@Data
public class PageQuery<T> implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "當(dāng)前頁(yè)碼", defaultValue = "1")
private Integer pageNum = 1;
@Schema(description = "每頁(yè)顯示條數(shù)", defaultValue = "10")
private Integer pageSize = 10;
@Schema(description = "排序?qū)ο?,支持多字段排?)
private List<OrderItem> orderItems;
@Schema(description = "查詢對(duì)象")
private T search;
}
2.3 結(jié)合 Query 對(duì)象使用案例
第一步:
比如我們現(xiàn)在要完成用戶列表的分頁(yè)查詢,那么首先我們需要定義對(duì)應(yīng)的查詢對(duì)象 **UserQuery, **這里簡(jiǎn)單展示通過(guò)用戶名和昵稱進(jìn)行查詢。
@Data
public class UserQuery implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "用戶名")
private String username;
@Schema(description = "昵稱")
private String nickname;
}
第二步:
定義我們返回時(shí)需要的結(jié)果對(duì)象,我這里就叫 **UserListVO **我習(xí)慣將列表的 **VO **對(duì)象命名為 **xxxListVO,**詳情對(duì)象命名為 xxxDetailVO
@Data
public class UserListVO implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "主鍵ID")
private Long userId;
@Schema(description = "用戶名")
private String username;
@Schema(description = "昵稱")
private String nickname;
@Schema(description = "創(chuàng)建時(shí)間")
private LocalDateTime createTime;
@Schema(description = "更新時(shí)間")
private LocalDateTime updateTime;
}
第三步:
在 controller 層編寫接口
@Operation(summary = "分頁(yè)查詢")
@PostMapping("/page")
public R<PageVO<UserListVO>> findPage(@RequestBody PageQuery<UserQuery> userQuery) {
PageVO<UserListVO> page = userService.findPage(userQuery);
return R.ok(page);
}
可以看到這里我們通過(guò)前面定義的公共對(duì)象,以及具體的業(yè)務(wù)對(duì)象,經(jīng)過(guò)簡(jiǎn)單的組裝完成了,請(qǐng)求參數(shù) **userQuery **以及返會(huì)結(jié)果的封裝,并且我們可以很清楚的知道對(duì)應(yīng)的類型,想要擴(kuò)展也很容易實(shí)現(xiàn),以后所有的分頁(yè)查詢基本上都是類似的格式,不同的在于我們根據(jù)不同使用場(chǎng)景封裝對(duì)應(yīng)的業(yè)務(wù)返回 xxxVO 以及查詢對(duì)象 xxxQuery
第四步:
具體的分頁(yè)查詢實(shí)現(xiàn),即 findPage 方法的實(shí)現(xiàn)
@Override
public PageVO<UserListVO> findPage(PageQuery<UserQuery> userQuery) {
// 將查詢對(duì)象 轉(zhuǎn)換為 Mybatis Plus 的 Page 對(duì)象
Page<AdminUser> page = Page.of(userQuery.getPageNum(), userQuery.getPageSize());
UserQuery search = userQuery.getSearch();
// 查詢
lambdaQuery()
.eq(StrUtil.isNotBlank(search.getUsername()), AdminUser::getUsername, search.getUsername())
.or()
.like(StrUtil.isNotBlank(search.getNickname()), AdminUser::getNickname, search.getNickname())
.page(page);
// 將 Mybatis Plus 的 Page 對(duì)象 轉(zhuǎn)換為 PageVO
List<AdminUser> records = page.getRecords();
List<UserListVO> userListVOs = BeanUtil.copyToList(records, UserListVO.class);
return new PageVO<>(page.getTotal(), page.getPages(), userListVOs);
}
測(cè)試一下

到這里基本上已經(jīng)完成了,但是細(xì)心的會(huì)發(fā)現(xiàn)我們沒有處理排序字段,而且這種對(duì)象來(lái)回轉(zhuǎn)換的方法非常繁瑣。
三、進(jìn)一步封裝對(duì)象轉(zhuǎn)換
對(duì)象轉(zhuǎn)換處理:
基于上面的接口實(shí)現(xiàn)進(jìn)一步完善,首先第一點(diǎn),查詢對(duì)象 轉(zhuǎn)換為 Mybatis Plus 的 Page 對(duì)象,我們先來(lái)完成這個(gè)封裝。
你可以單獨(dú)寫到一個(gè)工具類里,這里我直接寫在 PageQuery 對(duì)象中,這里方便我拿取參數(shù),省的傳參了,而且這樣也更符合面向?qū)ο缶幊蹋@種轉(zhuǎn)換能力應(yīng)該屬于 PageQuery 對(duì)象。
/**
* 將當(dāng)前對(duì)象轉(zhuǎn)換為 MybatisPlus 分頁(yè)對(duì)象
*
* @param <PO> PO類型
* @return Page<PO>
*/
public <PO> Page<PO> toMpPage() {
return Page.of(pageNum, pageSize);
}
那相同的 VO的轉(zhuǎn)換能力應(yīng)該由 PageVO提供,所以 VO轉(zhuǎn)換寫在 PageVO 里
/**
* 將 MybatisPlus 分頁(yè)結(jié)果轉(zhuǎn)換為 PageDTO
*
* @param page MybatisPlus 分頁(yè)結(jié)果
* @param targetClass 目標(biāo)類型字節(jié)碼
* @param <V> 目標(biāo)數(shù)據(jù)類型
* @param <P> 原始數(shù)據(jù)類型
* @return 分頁(yè)結(jié)果 PageDTO
*/
public static <V, P> PageVO<V> of(Page<P> page, Class<V> targetClass) {
List<P> records = page.getRecords();
if (records.isEmpty()) {
return empty(page);
}
// 將原始數(shù)據(jù)轉(zhuǎn)換為目標(biāo)數(shù)據(jù) 這里我使用了 hutool 的 BeanUtil,可以根據(jù)需要自行替換
List<V> vs = BeanUtil.copyToList(records, targetClass);
return new PageVO<>(page.getTotal(), page.getPages(), vs);
}
/**
* 返回空的分頁(yè)結(jié)果
*
* @param page MybatisPlus 分頁(yè)結(jié)果
* @param <V> 目標(biāo)數(shù)據(jù)類型
* @param <P> 原始數(shù)據(jù)類型
* @return 分頁(yè)結(jié)果 PageDTO
*/
public static <V, P> PageVO<V> empty(Page<P> page) {
return new PageVO<>(page.getPages(), page.getPages(), Collections.emptyList());
}
這樣我們之前的分頁(yè)查詢就可以寫成這樣
@Override
public PageVO<UserListVO> findPage(PageQuery<UserQuery> userQuery) {
// 將查詢對(duì)象 轉(zhuǎn)換為 Mybatis Plus 的 Page 對(duì)象
Page<AdminUser> page = userQuery.toMpPage();
UserQuery search = userQuery.getSearch();
// 查詢
lambdaQuery()
.eq(StrUtil.isNotBlank(search.getUsername()), AdminUser::getUsername, search.getUsername())
.or()
.like(StrUtil.isNotBlank(search.getNickname()), AdminUser::getNickname, search.getNickname())
.page(page);
// 將 Mybatis Plus 的 Page 對(duì)象 轉(zhuǎn)換為 PageVO
return PageVO.of(page, UserListVO.class);
}
排序處理:
在我們處理將當(dāng)前對(duì)象轉(zhuǎn)換為 MybatisPlus分頁(yè)對(duì)象的時(shí)候,只處理了 pageNum 和 pageSize , 接下來(lái)我們處理一下排序的情況。
/**
* 將當(dāng)前對(duì)象轉(zhuǎn)換為 MybatisPlus 分頁(yè)對(duì)象
*
* @param <PO> PO類型
* @return Page<PO>
*/
public <PO> Page<PO> toMpPage() {
Page<PO> page = Page.of(pageNum, pageSize);
if (orderItems != null && !orderItems.isEmpty()) {
page.addOrder(orderItems);
} else {
// 如果不傳默認(rèn)根據(jù)創(chuàng)建時(shí)間倒序
page.addOrder(OrderItem.desc("create_time"));
}
return page;
}
測(cè)試一下

==> Preparing: SELECT user_id, username, password, nickname, create_time, update_time, is_deleted FROM itshare_admin_user WHERE is_deleted = 0 ORDER BY user_id DESC LIMIT ?
控制臺(tái)輸出的 SQL 也如我們預(yù)期一樣
多條件測(cè)試
==> Preparing: SELECT user_id, username, password, nickname, create_time, update_time, is_deleted FROM itshare_admin_user WHERE is_deleted = 0 ORDER BY user_id DESC, create_time ASC LIMIT ?
四、總結(jié)
這樣我們基本上完成了項(xiàng)目中分頁(yè)場(chǎng)景下的代碼封裝,后續(xù)分頁(yè)場(chǎng)景,我們只需要定義好 xxxQuery 對(duì)象,以及 xxxVO 對(duì)象即可完成分頁(yè)查詢,大大簡(jiǎn)化了編碼過(guò)程,提高了編碼效率。其實(shí)就目前我們依然有很多具有共性的代碼,比如對(duì)條件 sql 的編寫,我們能不能根據(jù)對(duì)象類型以及前端配合傳參動(dòng)態(tài)去實(shí)現(xiàn),這樣我們就可以完全解放雙手,定義兩個(gè)對(duì)象就搞定一個(gè)分頁(yè)接口的查詢了。
到此這篇關(guān)于MyBatisPlus 封裝分頁(yè)方法示例的文章就介紹到這了,更多相關(guān)MyBatisPlus 分頁(yè)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
activemq整合springboot使用方法(個(gè)人微信小程序用)
這篇文章主要介紹了activemq整合springboot使用(個(gè)人微信小程序用),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
Java?SpringBoot?獲取接口實(shí)現(xiàn)類匯總
這篇文章主要介紹了Java?SpringBoot?獲取接口實(shí)現(xiàn)類匯總,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09
Java上傳文件錯(cuò)誤java.lang.NoSuchMethodException的解決辦法
今天小編就為大家分享一篇關(guān)于Java上傳文件錯(cuò)誤java.lang.NoSuchMethodException的解決辦法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01
Java 并發(fā)編程ArrayBlockingQueue的實(shí)現(xiàn)
這篇文章主要介紹了Java 并發(fā)編程ArrayBlockingQueue的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
使用nexus3.X上傳本地jar包并且通過(guò)pom讀取的解決方案(全網(wǎng)最新)
這篇文章主要介紹了使用nexus3.X上傳本地jar包并且通過(guò)pom讀取的解決方案(全網(wǎng)最新),本文內(nèi)容有點(diǎn)長(zhǎng),結(jié)合圖文實(shí)例給大家講解的非常詳細(xì),需要的朋友可以參考下2023-11-11
spring中的BeanFactory與FactoryBean的講解
今天小編就為大家分享一篇關(guān)于spring中的BeanFactory與FactoryBean的講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01
java實(shí)現(xiàn)短地址服務(wù)的方法(附代碼)
大多數(shù)情況下URL太長(zhǎng),字符多,不便于發(fā)布復(fù)制和存儲(chǔ),本文就介紹了通過(guò)java實(shí)現(xiàn)短地址服務(wù),減少了許多使用太長(zhǎng)URL帶來(lái)的不便,需要的朋友可以參考下2015-07-07

