Springboot怎么整合Mybatis-plus???
點擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”
優(yōu)質(zhì)文章,第一時間送達(dá)
? 作者?|??碼農(nóng)BookSea
來源 |? urlify.cn/A3AVZb

一、添加依賴pom.xml
????mysql
????mysql-connector-java
????com.alibaba
????druid-spring-boot-starter
????1.1.20
????com.baomidou
????mybatis-plus-boot-starter
????3.3.2
????com.baomidou
????mybatis-plus-generator
????3.3.2
????org.freemarker
????freemarker
二、application.yml添加配置
spring:
??#數(shù)據(jù)庫配置
??datasource:
????url:?jdbc:mysql://127.0.0.1:3306/user_role?useUnicode=true&useSSL=false&characterEncoding=utf-8
????username:?root
????password:?root
????#?使用druid數(shù)據(jù)源
????type:?com.alibaba.druid.pool.DruidDataSource
????driver-class-name:?com.mysql.jdbc.Driver
三、application配置@MapperScan
@SpringBootApplication
@MapperScan("cn.com.vicente.demo.mapper")
public?class?BdDemoApplication?{
????public?static?void?main(String[]?args)?{
????????SpringApplication.run(BdDemoApplication.class,?args);
????}
}
到這里就引入了MyBatis-Plus了。
四、代碼生成器
很多時候,都不想寫entity,mapper等文件,這個時候就可以使用代碼生成器來自動生成對應(yīng)的文件了。
需要修改幾個地方:
1、數(shù)據(jù)庫連接
2、文件需要放置的文件夾地址。
具體代碼:
package?cn.com.bluemoon.demo.generator;
import?com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import?com.baomidou.mybatisplus.core.toolkit.StringPool;
import?com.baomidou.mybatisplus.core.toolkit.StringUtils;
import?com.baomidou.mybatisplus.generator.AutoGenerator;
import?com.baomidou.mybatisplus.generator.InjectionConfig;
import?com.baomidou.mybatisplus.generator.config.*;
import?com.baomidou.mybatisplus.generator.config.po.TableInfo;
import?com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import?com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import?java.util.ArrayList;
import?java.util.List;
import?java.util.Scanner;
// 演示例子,執(zhí)行 main 方法控制臺輸入模塊表名回車自動生成對應(yīng)項目目錄中
public?class?CodeGenerator?{
????/**
?????*?
?????*?讀取控制臺內(nèi)容
?????*?
?????*/
????public?static?String?scanner(String?tip)?{
????????Scanner?scanner?=?new?Scanner(System.in);
????????StringBuilder?help?=?new?StringBuilder();
????????help.append("請輸入"?+?tip?+?":");
????????System.out.println(help.toString());
????????if?(scanner.hasNext())?{
????????????String?ipt?=?scanner.next();
????????????if?(StringUtils.isNotEmpty(ipt))?{
????????????????return?ipt;
????????????}
????????}
????????throw?new?MybatisPlusException("請輸入正確的"?+?tip?+?"!");
????}
????public?static?void?main(String[]?args)?{
????????//?代碼生成器
????????AutoGenerator?mpg?=?new?AutoGenerator();
????????//?全局配置
????????GlobalConfig?gc?=?new?GlobalConfig();
????????String?projectPath?=?System.getProperty("user.dir");
????????gc.setOutputDir(projectPath?+?"/src/main/java");
????????gc.setAuthor("vicente");
????????gc.setOpen(false);
????????//?service?命名方式
????????gc.setServiceName("%sService");
????????//?service?impl?命名方式
????????gc.setServiceImplName("%sServiceImpl");
????????//?自定義文件命名,注意?%s?會自動填充表實體屬性!
????????gc.setMapperName("%sMapper");
????????gc.setXmlName("%sMapper");
????????gc.setFileOverride(true);
????????gc.setActiveRecord(true);
????????//?XML?二級緩存
????????gc.setEnableCache(false);
????????//?XML?ResultMap
????????gc.setBaseResultMap(true);
????????//?XML?columList
????????gc.setBaseColumnList(false);
????????//?gc.setSwagger2(true);?實體屬性?Swagger2?注解
????????mpg.setGlobalConfig(gc);
????????//?數(shù)據(jù)源配置
????????DataSourceConfig?dsc?=?new?DataSourceConfig();
????????dsc.setUrl("jdbc:mysql://127.0.0.1:3306/user_role?useUnicode=true&useSSL=false&characterEncoding=utf-8");
????????//?dsc.setSchemaName("public");
????????dsc.setDriverName("com.mysql.jdbc.Driver");
????????dsc.setUsername("root");
????????dsc.setPassword("root");
????????mpg.setDataSource(dsc);
????????//?包配置
????????PackageConfig?pc?=?new?PackageConfig();
????????//pc.setModuleName(scanner("模塊名"));
????????pc.setParent("cn.com.vicente.demo");
????????pc.setEntity("entity");
????????pc.setService("service");
????????pc.setServiceImpl("service.impl");
????????mpg.setPackageInfo(pc);
????????//?自定義配置
????????InjectionConfig?cfg?=?new?InjectionConfig()?{
????????????@Override
????????????public?void?initMap()?{
????????????????//?to?do?nothing
????????????}
????????};
????????//?如果模板引擎是?freemarker
????????String?templatePath?=?"/templates/mapper.xml.ftl";
????????//?如果模板引擎是?velocity
????????//?String?templatePath?=?"/templates/mapper.xml.vm";
????????//?自定義輸出配置
????????List?focList?=?new?ArrayList<>();
????????//?自定義配置會被優(yōu)先輸出
????????focList.add(new?FileOutConfig(templatePath)?{
????????????@Override
????????????public?String?outputFile(TableInfo?tableInfo)?{
????????????????//?自定義輸出文件名?,?如果你?Entity?設(shè)置了前后綴、此處注意?xml?的名稱會跟著發(fā)生變化!!
????????????????String?moduleName?=?pc.getModuleName()==null?"":pc.getModuleName();
????????????????return?projectPath?+?"/src/main/resources/mapper/"?+?moduleName
????????????????????????+?"/"?+?tableInfo.getEntityName()?+?"Mapper"?+?StringPool.DOT_XML;
????????????}
????????});
????????/*
????????cfg.setFileCreate(new?IFileCreate()?{
????????????@Override
????????????public?boolean?isCreate(ConfigBuilder?configBuilder,?FileType?fileType,?String?filePath)?{
????????????????//?判斷自定義文件夾是否需要創(chuàng)建
????????????????checkDir("調(diào)用默認(rèn)方法創(chuàng)建的目錄");
????????????????return?false;
????????????}
????????});
????????*/
????????cfg.setFileOutConfigList(focList);
????????mpg.setCfg(cfg);
????????//?配置模板
????????TemplateConfig?templateConfig?=?new?TemplateConfig();
????????//?配置自定義輸出模板
????????//指定自定義模板路徑,注意不要帶上.ftl/.vm,?會根據(jù)使用的模板引擎自動識別
????????//?templateConfig.setEntity("templates/entity2.java");
????????//?templateConfig.setService();
????????//?templateConfig.setController();
????????templateConfig.setXml(null);
????????mpg.setTemplate(templateConfig);
????????//?策略配置
????????StrategyConfig?strategy?=?new?StrategyConfig();
????????strategy.setNaming(NamingStrategy.underline_to_camel);
????????strategy.setColumnNaming(NamingStrategy.underline_to_camel);
????????//strategy.setSuperEntityClass("cn.com.bluemoon.demo.entity");
????????strategy.setEntityLombokModel(true);
????????strategy.setRestControllerStyle(true);
????????//?公共父類
????????//strategy.setSuperControllerClass("cn.com.bluemoon.demo.controller");
????????//?寫于父類中的公共字段
????????//strategy.setSuperEntityColumns("id");
????????strategy.setInclude(scanner("表名,多個英文逗號分割").split(","));
????????strategy.setControllerMappingHyphenStyle(true);
????????strategy.setTablePrefix(pc.getModuleName()?+?"_");
????????mpg.setStrategy(strategy);
????????mpg.setTemplateEngine(new?FreemarkerTemplateEngine());
????????mpg.execute();
????}
}
五、添加測試
這里主要是Mybatis-Plus的CURD等方法。
@RunWith(SpringRunner.class)
@SpringBootTest
public?class?SampleTest?{
????private?static?Logger?log?=?LoggerFactory.getLogger(SampleTest.class);
????@Autowired
????private?MpUserService?mpUserService;
????@Test
????public?void?test1()?{
????????//?插入新記錄
????????MpUser?mpUser?=?new?MpUser();
????????//mpUser.setId(1L);
????????mpUser.setEmail("[email protected]");
????????mpUser.setAge(22);
????????mpUser.setName("David?Hong");
????????mpUserService.save(mpUser);
????????//?或者
????????mpUser.insertOrUpdate();
????????//?更新完成后,mpUser對象的id會被補全
????????log.info("mpUser={}",?mpUser.toString());
????}
????@Test
????public?void?test2()?{
????????//?通過主鍵id查詢
????????MpUser?mpUser?=?mpUserService.getById(1);
????????log.info("mpUser={}",?mpUser.toString());
????}
????@Test
????public?void?test3()?{
????????//?條件查詢,下面相當(dāng)于xml中的?select?*?from?mp_user?where?name?=?'Tom'?and?age?=?'28'?limit?1
????????MpUser?mpUser?=?mpUserService.getOne(new?QueryWrapper().eq("name",?"Tom").eq("age",?"28").last("limit?1"));
????????log.info("mpUser={}",?mpUser.toString());
????????//?批量查詢
????????List?mpUserList?=?mpUserService.list();
????????System.out.println("------------------------------all");
????????mpUserList.forEach(System.out::println);
????????//?分頁查詢?
????????int?pageNum?=?1;
????????int?pageSize?=?10;
????????IPage?mpUserIPage?=?mpUserService.page(new?Page<>(pageNum,?pageSize),?new?QueryWrapper().gt("age",?"20"));
????????//?IPage?to?List
????????List?mpUserList1?=?mpUserIPage.getRecords();
????????System.out.println("------------------------------page");
????????mpUserList1.forEach(System.out::println);
????????//?總頁數(shù)
????????long?allPageNum?=?mpUserIPage.getPages();
????????System.out.println("------------------------------allPageNum");
????????System.out.println(allPageNum);
????}
?????@Test
????public?void?test4()?{
????????MpUser?mpUser?=?mpUserService.getById(2);
????????//?修改更新
????????mpUser.setName("廣東廣州");
????????//mpUserService.updateById(mpUser);
????????//?或者
????????mpUser.insertOrUpdate();
????????//?通過主鍵id刪除
????????mpUserService.removeById(1);
????????//?或者
????????//mpUser.deleteById();
????}
}
六、數(shù)據(jù)分頁
1、簡單分頁方法
int?pageNum?=?1;
int?pageSize?=?10;
IPage?mpUserIPage?=?mpUserService.page(new?Page<>(pageNum,?pageSize),?new?QueryWrapper().gt("age",?"20"));
上面的分頁其實是調(diào)用BaseMapper的selectPage方法,這樣的分頁返回的數(shù)據(jù)確實是分頁后的數(shù)據(jù),但在控制臺打印的SQL語句上看到其實并沒有真正的物理分頁,而是通過緩存來獲得全部數(shù)據(jù)中再進(jìn)行的分頁,這樣對于大數(shù)據(jù)量操作時是不可取的,那么接下來就敘述一下,真正實現(xiàn)物理分頁的方法。
2、 物理分頁方法
新建一個MybatisPlusConfig配置類文件
//Spring?boot方式
@EnableTransactionManagement
@Configuration
@MapperScan("com.baomidou.cloud.service.*.mapper*")
public?class?MybatisPlusConfig?{
????@Bean
????public?PaginationInterceptor?paginationInterceptor()?{
????????PaginationInterceptor?paginationInterceptor?=?new?PaginationInterceptor();
????????//?設(shè)置請求的頁面大于最大頁后操作,?true調(diào)回到首頁,false?繼續(xù)請求??默認(rèn)false
????????//?paginationInterceptor.setOverflow(false);
????????//?設(shè)置最大單頁限制數(shù)量,默認(rèn)?500?條,-1?不受限制
????????//?paginationInterceptor.setLimit(500);
????????return?paginationInterceptor;
????}
}
重新調(diào)用mpUserService.page可以看到數(shù)據(jù)有物理分頁
3、XML自定義分頁
UserMapper.java?方法內(nèi)容
public?interface?UserMapper{//可以繼承或者不繼承BaseMapper
????/**
?????*?
?????*?查詢?:?根據(jù)state狀態(tài)查詢用戶列表,分頁顯示
?????*?注意!!:?如果入?yún)⑹怯卸鄠€,需要加注解指定參數(shù)名才能在xml中取值
?????*?
?????*
?????*?@param?page?分頁對象,xml中可以從里面進(jìn)行取值,傳遞參數(shù)?Page?即自動分頁,必須放在第一位(你可以繼承Page實現(xiàn)自己的分頁對象)
?????*?@param?state?狀態(tài)
?????*?@return?分頁對象
?????*/
????IPage?selectPageVo(Page?page,?@Param("age")?Integer?age);
}
UserMapper.xml?等同于編寫一個普通?list?查詢,mybatis-plus?自動替你分頁
"1.0"?encoding="UTF-8"?>
"-//mybatis.org//DTD?Mapper?3.0//EN"?"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
"cn.com.bluemoon.demo.mapper.MpUserMapper">
????
UserServiceImpl.java 調(diào)用分頁方法
public?IPage?selectUserPage(Page?page,?Integer?state)?{
????//?不進(jìn)行?count?sql?優(yōu)化,解決?MP?無法自動優(yōu)化?SQL?問題,這時候你需要自己查詢?count?部分
????//?page.setOptimizeCountSql(false);
????//?當(dāng)?total?為小于?0?或者設(shè)置?setSearchCount(false)?分頁插件不會進(jìn)行?count?查詢
????//?要點!!?分頁返回的對象與傳入的對象是同一個
????return?baseMapper.selectPageVo(page,?state);
}
4、測試自定義方法
?@Test
????public?void?test5()?{
????????Page?mpUserPage?=?new?Page<>(1,2);
????????IPage?iPage?=?mpUserService.selectUserPage(mpUserPage,22);
????????System.out.println("總頁數(shù):"+iPage.getPages());
????????System.out.println("總記錄數(shù):"+iPage.getTotal());
????????List?mpUserList1?=?iPage.getRecords();
????????mpUserList1.forEach(System.out::println);
????}
七、打印sql日志
為了方便排查錯誤,很多時候需要打印mybatis生成的sql語句,這時候就需要打印日志了。
在application.yml中添加:
?Logger?Config
logging:
??level:
????cn.com.vicente.demo:?debug
或者
mybatis-plus:
??configuration:
????log-impl:?org.apache.ibatis.logging.stdout.StdOutImpl
八、邏輯刪除
很多時候需要表的數(shù)據(jù)雖然刪除了,但是還是希望不是真正刪除數(shù)據(jù),數(shù)據(jù)還是留在數(shù)據(jù)庫中,只需要使用一個字段來做標(biāo)志為即可,這時候就需要邏輯刪除功能。
SpringBoot 配置方式:
application.yml 加入配置(如果你的默認(rèn)值和mp默認(rèn)的一樣,該配置可無):
mybatis-plus:
??global-config:
????db-config:
??????logic-delete-value:?1?#?邏輯已刪除值(默認(rèn)為?1)
??????logic-not-delete-value:?0?#?邏輯未刪除值(默認(rèn)為?0)
注冊 Bean(3.1.1開始不再需要這一步):
import?com.baomidou.mybatisplus.core.injector.ISqlInjector;
import?com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import?org.springframework.context.annotation.Bean;
import?org.springframework.context.annotation.Configuration;
@Configuration
public?class?MyBatisPlusConfiguration?{
????@Bean
????public?ISqlInjector?sqlInjector()?{
????????return?new?LogicSqlInjector();
????}
}
實體類字段上加上@TableLogic注解
@TableField(select = false)注解,可以不查詢出deleted字段
@TableLogic
//@TableField(select = false)
private Integer deleted;
效果: 使用mp自帶方法刪除和查找都會附帶邏輯刪除功能 (自己寫的xml不會)
example
刪除時 update user set deleted=1 where id =1 and deleted=0
查找時 select * from user where deleted=0
附件說明
邏輯刪除是為了方便數(shù)據(jù)恢復(fù)和保護數(shù)據(jù)本身價值等等的一種方案,但實際就是刪除。
如果你需要再查出來就不應(yīng)使用邏輯刪除,而是以一個狀態(tài)去表示。
九、主鍵策略
mybatis-plus 的主鍵生成的類型 默認(rèn)類型 是 IdType.ID_WORKER全局唯一ID,內(nèi)容為空自動填充(默認(rèn)配置),雪花算法
1,局部主鍵策略實現(xiàn)
在實體類中 ID屬性加注解
@TableId(type?=?IdType.AUTO)?主鍵自增?數(shù)據(jù)庫中需要設(shè)置主鍵自增
private?Long?id;
@TableId(type?=?IdType.NONE)?默認(rèn)跟隨全局策略走
private?Long?id;
@TableId(type?=?IdType.UUID)?UUID類型主鍵
private?Long?id;
@TableId(type?=?IdType.ID_WORKER)?數(shù)值類型數(shù)據(jù)庫中也必須是數(shù)值類型?否則會報錯
private?Long?id;
@TableId(type?=?IdType.ID_WORKER_STR)?字符串類型???數(shù)據(jù)庫也要保證一樣字符類型
private?Long?id;
@TableId(type?=?IdType.INPUT)?用戶自定義了??數(shù)據(jù)類型和數(shù)據(jù)庫保持一致就行
private?Long?id;
2,全局主鍵策略實現(xiàn)
需要在application.yml文件中添加
mybatis-plus:
??global-config:
????db-config:
??????id-type:?uuid/none/input/id_worker/id_worker_str/auto
表示全局主鍵都采用該策略(如果全局策略和局部策略都有設(shè)置,局部策略優(yōu)先級高)
十、自動填充
很多時候表中都需要添加創(chuàng)建時間,創(chuàng)建人,修改時間,修改人來跟蹤數(shù)據(jù)的來源和變動,但每次插入數(shù)據(jù)和修改數(shù)據(jù)的時候都要set這幾個字段又感覺很麻煩,這個時候就系統(tǒng)系統(tǒng)能自動填充這幾個字段了。
字段必須聲明TableField注解,屬性fill選擇對應(yīng)策略,該申明告知 Mybatis-Plus 需要預(yù)留注入 SQL 字段
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill?=?FieldFill.INSERT_UPDATE)
private?LocalDateTime?updateTime;
屬性fill有四種對應(yīng)策略,分別為:
public?enum?FieldFill?{
????/**
?????*?默認(rèn)不處理
?????*/
????DEFAULT,
????/**
?????*?插入填充字段
?????*/
????INSERT,
????/**
?????*?更新填充字段
?????*/
????UPDATE,
????/**
?????*?插入和更新填充字段
?????*/
????INSERT_UPDATE
}
自定義實現(xiàn)類 MyMetaObjectHandler:
@Component
public?class?MyMetaObjectHandler?implements?MetaObjectHandler?{
????private?static?final?Logger?LOGGER?=?LoggerFactory.getLogger(MyMetaObjectHandler.class);
????@Override
????public?void?insertFill(MetaObject?metaObject)?{
????????LOGGER.info("start?insert?fill?....");
????????//this.setFieldValByName("createTime",?LocalDateTime.now(),?metaObject);
????????this.setInsertFieldValByName("createTime",?LocalDateTime.now(),?metaObject);
????????this.setInsertFieldValByName("updateTime",?LocalDateTime.now(),?metaObject);
????}
????@Override
????public?void?updateFill(MetaObject?metaObject)?{
????????LOGGER.info("start?update?fill?....");
????????this.setUpdateFieldValByName("updateTime",?LocalDateTime.now(),?metaObject);
????}
}
測試使用
?@Test
????public?void?testInsert()?{
????????//?插入新記錄
????????MpUser?mpUser?=?new?MpUser();
????????mpUser.setEmail("[email protected]");
????????mpUser.setAge(28);
????????mpUser.setName("王蒙");
????????mpUserService.save(mpUser);
????????log.info("mpUser={}",?mpUser.toString());
????}
?@Test
????public?void?testUpdate()?{
????????//?更新記錄
????????MpUser?mpUser?=?new?MpUser();
????????mpUser.setId(1182478087497998337L);
????????MpUser?newUser?=?mpUser.selectById();
????????System.out.println(mpUser?==?newUser);
????????mpUser.setName("王天");
????????mpUser.updateById();
????????log.info("mpUser={}",?mpUser.toString());
????????log.info("newUser={}",?newUser.toString());
????}
自動填充優(yōu)化
insertFill方法每次插入的時候都會調(diào)用,如果不存在createTime屬性的話,每次插入都會白白調(diào)用了,浪費資源,所以可以判斷是否存在該屬性
boolean?hasCreateTime?=?metaObject.hasSetter(“createTime”);
if?(hasCreateTime){
this.setInsertFieldValByName(“createTime”,?LocalDateTime.now(),?metaObject);
}
希望,當(dāng)更新時有設(shè)定時間,就用更新時設(shè)定的時間,當(dāng)沒有設(shè)定時就自動填充更新時間,可以這樣設(shè)置
Object?fieldValue?=?getFieldValByName(“updateTime”,?metaObject);
if?(fieldValue?==?null){
this.setUpdateFieldValByName(“updateTime”,?LocalDateTime.now(),?metaObject);/
}
粉絲福利:實戰(zhàn)springboot+CAS單點登錄系統(tǒng)視頻教程免費領(lǐng)取
???
?長按上方微信二維碼?2 秒 即可獲取資料
感謝點贊支持下哈?
