一文詳解Springboot集成mybatis-plus
一、Mybatis-Plus介紹
Mybatis-plus是Mybatis的增強工具包,其官網(wǎng)的介紹如下:
- 潤物細無聲:只做增強不做改變,引入它不會對現(xiàn)有工程產(chǎn)生影響,如絲般順滑。
- 效率至上:只需簡單配置,即可快速進行單表CRUD操作,從而節(jié)省大量時間。
- 豐富功能:代碼生成、自動分頁、邏輯刪除、自動填充等功能一應俱全。
其優(yōu)點如下:
- 無侵入:Mybatis-Plus 在 Mybatis 的基礎上進行擴展,只做增強不做改變,引入 Mybatis-Plus 不會對您現(xiàn)有的 Mybatis 構(gòu)架產(chǎn)生任何影響,而且 MP 支持所有 Mybatis 原生的特性
- 依賴少:僅僅依賴 Mybatis 以及 Mybatis-Spring
- 損耗小:啟動即會自動注入基本CURD,性能基本無損耗,直接面向?qū)ο蟛僮?/li>
- 通用CRUD操作:內(nèi)置通用 Mapper、通用 Service,僅僅通過少量配置即可實現(xiàn)單表大部分 CRUD 操作,更有強大的條件構(gòu)造器,滿足各類使用需求
- 多種主鍵策略:支持多達4種主鍵策略(內(nèi)含分布式唯一ID生成器),可自由配置,完美解決主鍵問題
- 支持ActiveRecord:支持 ActiveRecord 形式調(diào)用,實體類只需繼承 Model 類即可實現(xiàn)基本 CRUD 操作
- 支持代碼生成:采用代碼或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 層代碼,支持模板引擎,更有超多自定義配置等您來使用(P.S. 比 Mybatis 官方的 Generator 更加強大?。?/li>
- 支持自定義全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 內(nèi)置分頁插件:基于Mybatis物理分頁,開發(fā)者無需關(guān)心具體操作,配置好插件之后,寫分頁等同于寫基本List查詢
- 內(nèi)置性能分析插件:可輸出Sql語句以及其執(zhí)行時間,建議開發(fā)測試時啟用該功能,能有效解決慢查詢
- 內(nèi)置全局攔截插件:提供全表 delete 、 update 操作智能分析阻斷,預防誤操作
二、Spring boot 整合Mybatis-plus
2.1 pom中引入Mybatis-plus依賴
<!--?https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter?--> <dependency> ????<groupId>com.baomidou</groupId> ????<artifactId>mybatis-plus-boot-starter</artifactId> ????<version>3.5.3.1</version> </dependency>
注:如果是gradle,引入的方式如下:
implementation group: 'com.baomidou', name: 'mybatis-plus-boot-starter', version: '3.5.3.1'
2.2 創(chuàng)建一張User表
創(chuàng)建對應的數(shù)據(jù)表 Schema 的表結(jié)構(gòu)和表數(shù)據(jù):
SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for `user_base_info` -- ---------------------------- DROP TABLE IF EXISTS `user_base_info`; CREATE TABLE `user_base_info` ( `id` int NOT NULL AUTO_INCREMENT COMMENT '主鍵ID', `u_id` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用戶ID', `name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用戶名', `cn_name` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '中文名', `sex` char(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '性別', `alias` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '別名', `web_chat` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '微信號', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
表中插入數(shù)據(jù)
-- ---------------------------- -- Records of user_base_info -- ---------------------------- INSERT INTO `user_base_info` VALUES ('1', '001', 'holmium', '鈥', '1', '虎嘯山村', 'holmium'); INSERT INTO `user_base_info` VALUES ('2', '001', 'test', '測試', '0', '美女', '虎嘯山村');
2.3 Mybatis-plus配置
#mybatis-plus mybatis-plus: ??##?這個可以不用配置,因其默認就是這個路徑 ??mapper-locations:?classpath:/mapper/*Mapper.xml ??#實體掃描,多個package用逗號或者分號分隔 ??typeAliasesPackage:?com.holmium.springboot.repository.*.entity ??global-config: ????#?數(shù)據(jù)庫相關(guān)配置 ????db-config: ??????#主鍵類型??AUTO:"數(shù)據(jù)庫ID自增",?INPUT:"用戶輸入ID",ID_WORKER:"全局唯一ID?(數(shù)字類型唯一ID)",?UUID:"全局唯一ID?UUID"; ??????id-type:?AUTO ??????#字段策略?IGNORED:"忽略判斷",NOT_NULL:"非?NULL?判斷"),NOT_EMPTY:"非空判斷" ??????field-strategy:?not_empty ??????#駝峰下劃線轉(zhuǎn)換 ??????column-underline:?true ??????#數(shù)據(jù)庫大寫下劃線轉(zhuǎn)換 ??????#capital-mode:?true ??????#邏輯刪除配置 ??????logic-delete-value:?0 ??????logic-not-delete-value:?1 ??????db-type:?h2 ????#刷新mapper?調(diào)試神器 ????refresh:?true ??#?原生配置 ??configuration: ????map-underscore-to-camel-case:?true ????cache-enabled:?false
2.4 創(chuàng)建一個實體
//BasePo,后續(xù)可以繼續(xù)擴展 @Data public?class?BasePo?{ ????@TableId(value?=?"id",?type?=?IdType.AUTO) ????private?Integer?id; } package?com.holmium.springboot.infra.user.entity; import?com.baomidou.mybatisplus.annotation.TableField; import?com.baomidou.mybatisplus.annotation.TableName; import?lombok.Getter; import?lombok.Setter; /** ?*?@author?holmium ?*?@description: ?*?@date?2023年04月20日16:19 ?*/ @TableName(value?=?"user_base_info",?autoResultMap?=?true) @Getter @Setter public?class?UserPo?extends?BasePo?{ ????/** ?????*?用戶ID ?????*/ ????@TableField(value?=?"u_id") ????String?uId; ????/** ?????*?用戶名 ?????*/ ????@TableField(value?=?"name") ????String?name; ????/** ?????*?中文名稱 ?????*/ ????@TableField(value?=?"cn_name") ????String?cnName; ????/** ?????*?性別:1-男?0-女 ?????*/ ????@TableField(value?=?"sex") ????String?sex; ????/** ?????*?別名 ?????*/ ????@TableField(value?=?"alias") ????String?alias; ????/** ?????*?微信號 ?????*/ ????@TableField(value?=?"web_chat") ????String?webChat; }
2.5 創(chuàng)建一個Mapper接口
package?com.holmium.springboot.infra.user.mapper; import?com.baomidou.mybatisplus.core.mapper.BaseMapper; import?com.holmium.springboot.infra.user.entity.UserPo; import?org.apache.ibatis.annotations.Mapper; @Mapper public?interface?UserMapper?extends?BaseMapper<UserPo>?{ }
2.6 修改服務接口
//如果不理解,可以看之前的文章 @RestController @RequestMapping("/user/center") public?class?UserApi?{ ????@Resource ????UserAppImpl?userApp; ?? ????@GetMapping(value?=?"/userinfo") ????public?UserVo?gerUserInfo(@RequestParam("id")?String?id)?throws?Exception?{ ????????return?userApp.getUserInfoByUserId(id); ????} }
2.7 在啟動類中添加 @MapperScan
注解,掃描 Mapper 文件夾
@SpringBootApplication @MapperScan("com.holmium.springboot.infra.*.mapper")?//添加mapper掃描 public?class?HolmiumApplication?{ ????public?static?void?main(String[]?args)?{ ????????SpringApplication.run(HolmiumApplication.class,?args); ????} }
2.8 測試
2.9 小結(jié)
通過以上的步驟,我們實現(xiàn)了對User表的查詢功能,可以看到對于簡單的CRUD操作,Mybatis-Plus
只需要定義一個Mapper
接口即可實現(xiàn),真正做到如他所說的那樣,簡單配置、效率至上。
三、Mybatis-plus 部分字段注解和查詢
3.1 主鍵
3.1.1 主鍵生成策略
主鍵生成策略一共提供的五種:
AUTO(0),遞增策略,如果使用該策略必須要求數(shù)據(jù)表的列也是遞增。 NONE(1),沒有策略,必須人為的輸入id值 INPUT(2),沒有策略,必須人為的輸入id值 ASSIGN_ID(3), 隨機生成一個Long類型的值。該值一定是唯一。而且每次生成都不會相同。算法:雪花算法。 適合分布式主鍵。 ASSIGN_UUID(4); 隨機產(chǎn)生一個String類型的值。該值也是唯一的。
3.1.2 使用方式
通過配置文件中,配置id-type
屬性:
mybatis-plus: ??global-config: ???#?數(shù)據(jù)庫相關(guān)配置 ????db-config: ??????#主鍵類型??AUTO:"數(shù)據(jù)庫ID自增",?INPUT:"用戶輸入ID",ID_WORKER:"全局唯一ID?(數(shù)字類型唯一ID)",?UUID:"全局唯一ID?UUID"; ??????id-type:?AUTO
也可在對象屬性上進行注解設置:
@Data public?class?BasePo?{ ????//配置為數(shù)據(jù)庫ID自增 ????@TableId(value?=?"id",?type?=?IdType.AUTO) ????private?Integer?id; }
3.2 刪除
實際開發(fā)過程中,對數(shù)據(jù)都不會直接刪除,都會采用邏輯刪除的方式。所謂的邏輯刪除,只是將數(shù)據(jù)置為一個狀態(tài),這個狀態(tài)代表數(shù)據(jù)為刪除狀態(tài),一般自己程序中寫的話,就設置一個狀態(tài)字段,給字段賦值為0
或 D
代表刪除。而Mybatis-plus提供了@TableLogic
注解,實現(xiàn)邏輯刪除。 只對自動注入的 sql 起效:
- 插入: 不作限制
- 查找: 追加 where 條件過濾掉已刪除數(shù)據(jù),且使用 wrapper.entity 生成的 where 條件會忽略該字段
- 更新: 追加 where 條件防止更新到已刪除數(shù)據(jù),且使用 wrapper.entity 生成的 where 條件會忽略該字段
- 刪除: 轉(zhuǎn)變?yōu)?更新
@Data public?class?BasePo?{ ????/** ?????*?主鍵 ?????*/ ????@TableId(value?=?"id",?type?=?IdType.AUTO) ????private?Integer?id; ????/** ?????*?是否刪除:0表示未刪除?1表示刪除. ?????*/ ????@TableLogic ????private?Boolean?deleted; }
3.3 自動填充
實際開發(fā)中,我們會在表中記錄數(shù)據(jù)創(chuàng)建時間、創(chuàng)建人、修改時間、修改人幾個字段,但是幾個字段如果我們每次都要進行賦值,代碼比較冗余,Mybatis-plus
提供的自動填充功能。
3.3.1 增加公共屬性對象:
@Data public?class?BasePo?{ ????/** ?????*?主鍵 ?????*/ ????@TableId(value?=?"id",?type?=?IdType.AUTO) ????private?Integer?id; ????/** ?????*?創(chuàng)建時間 ?????*/ ????@TableField(fill?=?FieldFill.INSERT) ????@JsonFormat(pattern?=?"yyyy-MM-dd?HH:mm:ss") ????private?Date?createTime; ????/** ?????*?最后更新時間 ?????*/ ????@TableField(fill?=?FieldFill.INSERT_UPDATE) ????@JsonFormat(pattern?=?"yyyy-MM-dd?HH:mm:ss") ????private?Date?updateTime; ????/** ?????*?創(chuàng)建者,默認系統(tǒng)User?的?id?編號 ?????*?<p> ?????*?使用?String?類型的原因是,未來可能會存在非數(shù)值的情況,留好拓展性。 ?????*/ ????@TableField(fill?=?FieldFill.INSERT,?jdbcType?=?JdbcType.VARCHAR) ????private?String?creator; ????/** ?????*?更新者,默認系統(tǒng)User?的?id?編號 ?????*?<p> ?????*?使用?String?類型的原因是,未來可能會存在非數(shù)值的情況,留好拓展性。 ?????*/ ????@TableField(fill?=?FieldFill.INSERT_UPDATE,?jdbcType?=?JdbcType.VARCHAR) ????private?String?updater; ????/** ?????*?是否刪除 ?????*/ ????@TableLogic ????private?Boolean?deleted; }
3.3.2 自定義實現(xiàn)類 MyMetaObjectHandler
public?class?DefaultDbFieldHandler?implements?MetaObjectHandler?{ ????@Override ????public?void?insertFill(MetaObject?metaObject)?{ ????????if?(Objects.nonNull(metaObject)?&&?metaObject.getOriginalObject()?instanceof?BaseEntity)?{ ????????????BaseEntity?baseDO?=?(BaseEntity)?metaObject.getOriginalObject(); ???? ????????????Date?current?=?new?Date(); ????????????//?創(chuàng)建時間為空,則以當前時間為插入時間 ????????????if?(Objects.isNull(baseDO.getCreateTime()))?{ ????????????????baseDO.setCreateTime(current); ????????????} ????????????//?更新時間為空,則以當前時間為更新時間 ????????????if?(Objects.isNull(baseDO.getUpdateTime()))?{ ????????????????baseDO.setUpdateTime(current); ????????????} ???? ????????????Long?userId?=?WebUtils.getLoginUserId(); ????????????//?當前登錄用戶不為空,創(chuàng)建人為空,則當前登錄用戶為創(chuàng)建人 ????????????if?(Objects.nonNull(userId)?&&?Objects.isNull(baseDO.getCreator()))?{ ????????????????baseDO.setCreator(userId.toString()); ????????????} ????????????//?當前登錄用戶不為空,更新人為空,則當前登錄用戶為更新人 ????????????if?(Objects.nonNull(userId)?&&?Objects.isNull(baseDO.getUpdater()))?{ ????????????????baseDO.setUpdater(userId.toString()); ????????????} ????????} ????} ???? ????@Override ????public?void?updateFill(MetaObject?metaObject)?{ ????????//?更新時間為空,則以當前時間為更新時間 ????????Object?modifyTime?=?getFieldValByName("updateTime",?metaObject); ????????if?(Objects.isNull(modifyTime))?{ ????????????setFieldValByName("updateTime",?new?Date(),?metaObject); ????????} ???? ????????//?當前登錄用戶不為空,更新人為空,則當前登錄用戶為更新人 ????????Object?modifier?=?getFieldValByName("updater",?metaObject); ????????Long?userId?=?WebUtils.getLoginUserId(); ????????if?(Objects.nonNull(userId)?&&?Objects.isNull(modifier))?{ ????????????setFieldValByName("updater",?userId.toString(),?metaObject); ????????} ????} }
3.4 條件查詢
3.4.1 根據(jù)各種條件查詢
Wrapper:封裝了關(guān)于查詢的各種條件方法。
有三個子類最常用: LambdaQueryWrapper
查詢條件 LambdaUpdateWrapper
修改條件 LambdaQueryWrapper
查詢使用lambda表達式條件
- LambdaQueryWrapper
selectPage(userDo,?new?LambdaQueryWrapperX<UserPo>() ????????????????.likeIfPresent(UserPo::getName,?userDo.getName()) ????????????????.likeIfPresent(UserPo::getSex,?userDo.getSex()) ????????????????.betweenIfPresent(UserPo::getCreateTime,?userDo.getCreateTime()) ????????????????.orderByDesc(UserPo::getId))
- LambdaUpdateWrapper
update(update,?new?LambdaUpdateWrapper<UserPo>() ???????????????.eq(UserPo::getId,?id).eq(UserPo::getName,?name))
- LambdaQueryWrapper
new?LambdaQueryWrapper<UserDo>() ????????????????.eq(UserPo::getId,?id) ????????????????.eq(UserPo::getName,?name);
3.5 分頁查詢
- 添加分頁攔截器
???@Bean ???public?MybatisPlusInterceptor?mybatisPlusInterceptor()?{ ???????MybatisPlusInterceptor?mybatisPlusInterceptor?=?new?MybatisPlusInterceptor(); ???????//?分頁插件 ???????mybatisPlusInterceptor.addInnerInterceptor(new?PaginationInnerInterceptor(DbType.MYSQL)); ???????return?mybatisPlusInterceptor; ???}
- 分頁查詢
Page<UserPo>?page?=?userMapper.selectPage(page,?wrapper);//把查詢的結(jié)果自動封裝到Page對象中
3.6 小結(jié)
到此簡單的查詢基本已介紹完畢,可滿足他80%的日常開發(fā)需求。
四、引入對象轉(zhuǎn)換組件mapstruct
從上述代碼中可以看到,我們從數(shù)據(jù)庫查詢出來的結(jié)果是轉(zhuǎn)換為一個想XXXPo
的對象,而接口返回的是XXXVo
對象。在實際項目中,一般一個project都會分很多層,每層都會定義自己的對象,如:PO、VO、DAO、BO、DTO、POJO等等。
- DO(Data Object):此對象與數(shù)據(jù)庫表結(jié)構(gòu)一一對應,通過 DAO 層向上傳輸數(shù)據(jù)源對象。
- DTO(Data Transfer Object):數(shù)據(jù)傳輸對象,Service 或 Manager 向外傳輸?shù)膶ο蟆?/li>
- BO(Business Object):業(yè)務對象,由 Service 層輸出的封裝業(yè)務邏輯的對象。
- AO(ApplicationObject):應用對象,在Web層與Service層之間抽象的復用對象模型, 極為貼近展示層,復用度不高。
- VO(View Object):顯示層對象,通常是 Web 向模板渲染引擎層傳輸?shù)膶ο蟆?/li>
- POJO是DO/DTO/BO/VO的統(tǒng)稱,禁止命名成xxxPOJO。
這些對象在傳遞過程中,需要相互轉(zhuǎn)換,如果手工書寫,往往會通過getxxx
,再setxxx
,操作起來非常繁瑣,那有沒有一種方式比較簡單實現(xiàn)能?下面我們介紹一個對象轉(zhuǎn)換的組件mapstruct
。
4.1 pom中引入依賴包
<!--?https://mvnrepository.com/artifact/org.mapstruct/mapstruct?--> <dependency> ????<groupId>org.mapstruct</groupId> ????<artifactId>mapstruct</artifactId> ????<version>1.5.4.Final</version> </dependency>
4.2 創(chuàng)建一個Convert接口
package?com.holmium.springboot.app.user.convert; import?com.holmium.springboot.api.user.vo.UserVo; import?com.holmium.springboot.common.user.app.dto.UserDto; import?org.mapstruct.Mapper;? import?org.mapstruct.factory.Mappers; /** ?*?@author?holmium ?*?@date?2023年04月16日?20:24 ?*/ @Mapper public?interface?UserAppConvert?{ ????UserAppConvert?INSTANCES?=?Mappers.getMapper(UserAppConvert.class); ????UserVo?voToDto(UserDto?userDto); }
避坑
這里的
@Mapper
注解和上述Mybatis-plus
中的@Mapper
注解相同,很容易引入錯誤,導致會報錯。這里的
Mapper
是import org.mapstruct.Mapper;
mybatis-plus
中的@Mapper
,import org.apache.ibatis.annotations.Mapper;
一定要注意看清楚引入的類
4.3 在類中引用
@Service public?class?UserAppImpl?implements?UserApp?{ ????@Resource ????public?UserDomain?userDomain; ????@Override ????public?UserVo?getUserInfoByUserId(String?userId)?throws?Exception?{ ????????//這樣就實現(xiàn)了對象轉(zhuǎn)換 ????????return?UserAppConvert.INSTANCES.voToDto(userDomain.getUserInfoByUid(userId)); ????} }
4.4 對象屬性不同怎么轉(zhuǎn)換
上述是兩個對象中屬性相同話,可以不用做其他任何操作,就可以事項對象互轉(zhuǎn),但實際在開發(fā)中,兩個對象屬性不可能完全一樣。而上述操作只能將相同屬性做轉(zhuǎn)換,不同的屬性沒法互相轉(zhuǎn)換,導致對象有部分數(shù)據(jù)丟失?那怎么解決,可在轉(zhuǎn)換方法上加入@Mappings
注解,如下:
@Mapper public?interface?UserAppConvert?{ ????UserAppConvert?INSTANCES?=?Mappers.getMapper(UserAppConvert.class); ????@Mappings({ ????????????//屬性不一致轉(zhuǎn)換 ????????????@Mapping(source?=?"name",?target?=?"userName"), ????????????//類型不一致轉(zhuǎn)換 ????????????@Mapping(target?=?"createTime",?expression?=?"java(com.java.mmzsblog.util.DateTransform.strToDate(source.getCreateTime()))"), ????}) ????UserVo?voToDto(UserDto?userDto); }
這樣就解決了不同對象屬性和屬性類型不一致轉(zhuǎn)換問題。
五、寫在最后
截止本篇文章,我們已經(jīng)將如何創(chuàng)建一個Spring boot 工程,如何開發(fā)一個服務,以及從數(shù)據(jù)庫總獲取數(shù)據(jù)基本已完成。根據(jù)這一系列文章,大家做日常的開發(fā)聯(lián)系基本夠。
后續(xù)章節(jié)將把druid和mybatis-plus的整合轉(zhuǎn)換成starter的方式,對其做一定的封裝。
同時我們會將系統(tǒng)的應用架構(gòu)轉(zhuǎn)換成DDD模式架構(gòu),后續(xù)我將用多個篇幅介紹DDD架構(gòu)。請持續(xù)關(guān)注跟蹤。
以上就是一文詳解Springboot集成mybatis-plus的詳細內(nèi)容,更多關(guān)于Springboot集成mybatis-plus的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java實現(xiàn)一次性壓縮多個文件到zip中的方法示例
這篇文章主要介紹了java實現(xiàn)一次性壓縮多個文件到zip中的方法,涉及java針對文件批量壓縮相關(guān)的文件判斷、遍歷、壓縮等操作技巧,需要的朋友可以參考下2019-09-09Maven 多模塊父子工程的實現(xiàn)(含Spring Boot示例)
這篇文章主要介紹了Maven 多模塊父子工程的實現(xiàn)(含Spring Boot示例),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-04-04Jetty啟動項目中引用json-lib相關(guān)類庫報錯ClassNotFound的解決方案
今天小編就為大家分享一篇關(guān)于Jetty啟動項目中引用json-lib相關(guān)類庫報錯ClassNotFound的解決方案,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12Mybatis中where標簽與if標簽結(jié)合使用詳細說明
mybatis中if和where用于動態(tài)sql的條件拼接,在查詢語句中如果缺失某個條件,通過if和where標簽可以動態(tài)的改變查詢條件,下面這篇文章主要給大家介紹了關(guān)于Mybatis中where標簽與if標簽結(jié)合使用的詳細說明,需要的朋友可以參考下2023-03-03