javascript
SpringBoot集成MybatisPlus 涵盖了目前流行的知识点!!!即用即cv即可!!!学过的同学,也可以存储作为工具!!
知識點涵蓋:代碼自動生成、主鍵自增(雪花算法)、分頁、自動填充字段、LocalDateTime 序列化配置、druid數據源配置、SQL監控頁面、邏輯刪除、事務管理、多環境配置等等。
1、 可以無縫內嵌進項目,也可以保存下來,方便下次使用。
2、代碼中帶有很多注解,為方便對MybatisPlus了解不深的同學,也能夠快速看懂。👨?💻or🛌
3、不行的話一步一步復制,也是可以運行起來的,慢慢看更好。
地點:湖南邵陽
作者:喜
SpringBoot集成MybatisPlus 涵蓋了目前流行的知識點!!
- 一、前言
- 二、基礎環境搭建
- 2.1、數據庫環境搭建:
- 2.2、maven導入依賴:
- 2.3、yml配置文件
- 2.4、mybatis-plus 逆向工程生成代碼
- 2.4.1、初始化項目結構:
- 2.4.2、mybatisplus逆向共程代碼
- 2.4.3、啟動與示例
- 2.4.4、生成后的項目結構
- 2.4.5、生成代碼查看
- 三、配置類講解
- 3.1、MybatisPlusConfig
- 3.2、自動填充字段
- 3.3、主鍵自動生成
- 3.4、LocalDateTimeSerializerConfig(LocalDateTime序列化)
- 四、測試
- 4.1、增加:
- 4.2、刪除:
- 4.3、查找:(分頁查找)
- 4.4、修改:
- 4.5、事務回滾:
- 4.6、druid 監控頁面
- 五、自言自語
一、前言
最近在寫一個關于SpringBoot 系列的文章,在逐漸整理相關的知識,打算慢慢寫出來,作為了一個工具,隨拿隨用。👨???
本文寫的是SpringBoot-MybatisPlus,完整項目結構如下圖:
下面將會一一道來,有任何不懂的地方,都可以私信或留言評論,會及時給出回復。
若有寫的不對或不妥的地方,請您指教!!!非常感謝。🤶
二、基礎環境搭建
2.1、數據庫環境搭建:
DROP TABLE IF EXISTS `tb_user`; CREATE TABLE `tb_user` (`id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`passwrod` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`deleted` int(1) NOT NULL DEFAULT 0,`create_time` datetime(0) NOT NULL COMMENT '創建時間',`update_time` datetime(0) NOT NULL COMMENT '修改時間',PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;INSERT INTO `tb_user` VALUES ('1', '123456789', '123456', 0, '2021-07-23 14:32:46', '2021-07-24 10:51:11'); INSERT INTO `tb_user` VALUES ('2', '寧在春', 'qwerasd', 0, '2021-07-23 15:02:02', '2021-07-23 15:49:55');2.2、maven導入依賴:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.2</version><relativePath/> <!-- lookup parent from repository --> </parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.23</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.6</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.72</version></dependency><!--start mybatis-plus 逆向工程 自動生成代碼--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.4.1</version></dependency><!--逆向工程中的模板引擎--><dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.2</version></dependency><!--end--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency> </dependencies>2.3、yml配置文件
多配置😎
1、application.yml
spring:profiles:active: prod2、application-prod.yaml
server:port: 8081worker-id: 1data-center-id: 2 spring:application:name: springboot-mybatis-plus# 數據源配置datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driver# 阿里的數據庫連接池druid:username: rootpassword: 123456url: jdbc:mysql://localhost:3306/commons_utils?serverTimezone=UTC&useSSL=false&characterEncoding=utf8&serverTimezone=GMT# 初使化連接數(向數據庫要五個連接)initial-size: 5# 最小連接數(常住10個連接)min-idle: 10# 最大連接數(最多獲得10個連接,多到10個數據庫將進入一個阻塞狀態,等待其他連接釋放)max-active: 20# 獲取連接最長等待時間,單位毫秒max-wait: 10000# 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接,單位是毫秒timeBetweenEvictionRunsMillis: 60000# 配置一個連接在池中最小生存的時間,單位是毫秒minEvictableIdleTimeMillis: 300000# 配置一個連接在池中最大生存的時間,單位是毫秒maxEvictableIdleTimeMillis: 900000# 配置檢測連接是否有效validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: false#配置監控頁面stat-view-servlet:enabled: trueurl-pattern: /druid/*login-username: adminlogin-password: adminfilter:stat:enabled: truelog-slow-sql: true# 慢SQL記錄slow-sql-millis: 1000merge-sql: truewall:config:multi-statement-allow: trueslf4j:enabled: truekeep-alive: truejackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT+8 mybatis-plus:configuration:cache-enabled: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImpl #開啟sql日志mapper-locations: classpath:/mapper/**/*Mapper.xml #mapper.xml映射global-config:db-config:logic-delete-field: flag # 全局邏輯刪除的實體字段名(since 3.3.0,配置后可以忽略不配置步驟2)logic-delete-value: 1 # 邏輯已刪除值(默認為 1)logic-not-delete-value: 0 # 邏輯未刪除值(默認為 0) #logging: #日志打印、sql語句打印 # level: # root: info # com.crush.mybatispllus.mapper: debug2.4、mybatis-plus 逆向工程生成代碼
2.4.1、初始化項目結構:
2.4.2、mybatisplus逆向共程代碼
// 演示例子,執行 main 方法控制臺輸入模塊表名回車自動生成對應項目目錄中 public class CodeGenerator {/*** <p>* 讀取控制臺內容* </p>*/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.isNotBlank(ipt)) {return ipt;}}throw new MybatisPlusException("請輸入正確的" + tip + "!");}public static void main(String[] args) {// 代碼生成器AutoGenerator mpg = new AutoGenerator();// 全局配置GlobalConfig gc = new GlobalConfig();final String projectPath = System.getProperty("user.dir");gc.setOutputDir(projectPath + "/src/main/java");gc.setAuthor("crush");gc.setOpen(false);gc.setIdType(IdType.AUTO);// gc.setSwagger2(true); 實體屬性 Swagger2 注解mpg.setGlobalConfig(gc);// 數據源配置DataSourceConfig dsc = new DataSourceConfig();dsc.setUrl("jdbc:mysql://localhost:3306/commons_utils?useUnicode=true&useSSL=false&characterEncoding=utf8");// dsc.setSchemaName("public");dsc.setDriverName("com.mysql.cj.jdbc.Driver");dsc.setUsername("root");dsc.setPassword("123456");mpg.setDataSource(dsc);// 包配置final PackageConfig pc = new PackageConfig();pc.setModuleName(scanner("模塊名"));pc.setParent("com.crush");mpg.setPackageInfo(pc);// 自定義配置InjectionConfig cfg = new InjectionConfig() {@Overridepublic void initMap() {// to do nothing}};// 如果模板引擎是 freemarker//String templatePath = "/templates/mapper.xml.ftl";// 如果模板引擎是 velocityString templatePath = "/templates/mapper.xml.vm";// 自定義輸出配置List<FileOutConfig> focList = new ArrayList<>();// 自定義配置會被優先輸出focList.add(new FileOutConfig(templatePath) {@Overridepublic String outputFile(TableInfo tableInfo) {// 自定義輸出文件名 , 如果你 Entity 設置了前后綴、此處注意 xml 的名稱會跟著發生變化!!return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;}});/*cfg.setFileCreate(new IFileCreate() {@Overridepublic boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {// 判斷自定義文件夾是否需要創建checkDir("調用默認方法創建的目錄,自定義目錄用");if (fileType == FileType.MAPPER) {// 已經生成 mapper 文件判斷存在,不想重新生成返回 falsereturn !new File(filePath).exists();}// 允許生成模板文件return true;}});*/cfg.setFileOutConfigList(focList);mpg.setCfg(cfg);// 配置模板TemplateConfig templateConfig = new TemplateConfig();// 配置自定義輸出模板//指定自定義模板路徑,注意不要帶上.ftl/.vm, 會根據使用的模板引擎自動識別// 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.setEntityLombokModel(true);strategy.setRestControllerStyle(true);// 公共父類// 寫于父類中的公共字段strategy.setSuperEntityColumns("id");strategy.setInclude(scanner("表名,多個英文逗號分割").split(","));strategy.setControllerMappingHyphenStyle(true);// strategy.setTablePrefix(pc.getModuleName() + "_");//去掉 表前綴 "tb_" 需求變化的話 可以提取出來strategy.setTablePrefix("tb"+"_");mpg.setStrategy(strategy);mpg.setTemplateEngine(new VelocityTemplateEngine());mpg.execute();}}2.4.3、啟動與示例
模塊名 就是在已建立好的com.crush包下建一個新包 以這個為命名。==注意哈:我項目中的包實際為mybatisplus,這是寫文章時實時測試的。==😜
2.4.4、生成后的項目結構
對了,記得寫一個啟動類兄弟們,如果直接SpringBoot 項目請忽略。
2.4.5、生成代碼查看
基本注解都會給帶上,但是還是有一些需要手動完善一下的,還有很多可以玩的,我還沒有全部玩完👩?🚀👩?🚀。這里不多扯。😚
補充: 因為實體類上需要完善一些注解。所以將完整的實體類在此處寫出來了。
@EqualsAndHashCode(callSuper = false) //@Accessors 鏈式書寫 或 @AllArgsConstructor 全參構造 @Accessors(chain = true) @TableName("tb_user") @KeySequence("mybatisKeyGenerator") public class User implements Serializable {private static final long serialVersionUID = 1L;@TableId(type = IdType.INPUT)private String id;private String username;private String passwrod;/*** 邏輯刪除字段*/@TableLogicprivate Integer deleted;/*** 創建時間*/@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;/*** 修改時間*/@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime; }到此基本環境已基本搭建完畢,加一個啟動類、配置類即可開始測試。(后面都有的,莫慌👨?💻👨?💻)
三、配置類講解
3.1、MybatisPlusConfig
package com.crush.mybatisplus.config;import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.transaction.annotation.EnableTransactionManagement;/*** @EnableTransactionManagement :開啟事務* @MapperScan() 掃描包* @Author: crush* @Date: 2021-07-23 14:14* version 1.0*/ @Configuration @EnableTransactionManagement @MapperScan("com.crush.mybatisplus.mapper") public class MybatisPlusConfig {/*** 分頁 插件*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));// 注冊樂觀鎖 插件return mybatisPlusInterceptor;}/*** 配置數據源 druid*/@Bean@Primary@ConfigurationProperties("spring.datasource.druid")public DruidDataSource druidDataSource() {return DruidDataSourceBuilder.create().build();}}寫到這里即可以直接開測了,下面更多的是細節方面的處理。(我寫的測試在文末,知識點內的測試都有)😶
3.2、自動填充字段
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component;import java.time.LocalDateTime;/*** 填充創建和修改時間* @Author: crush* @Date: 2021-07-23 14:14*/ @Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {log.info(" 插入填充 start insert fill ....");// 我去看了一下介紹,其實這里是個通用填充,并不局限于填充時間哈 this.setFieldValByName("createTime", LocalDateTime.now(),metaObject);this.setFieldValByName("updateTime",LocalDateTime.now(),metaObject);}@Overridepublic void updateFill(MetaObject metaObject) {log.info("修改填充 start update fill ....");this.setFieldValByName("updateTime",LocalDateTime.now(),metaObject);} }注意: 需要在填充的字段上加上注解。🤗
/** * 創建時間 */ @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime;/** * 修改時間 */ @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime;3.3、主鍵自動生成
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;/*** 主鍵自動生成* @Author: crush* @Date: 2021-07-23 14:14*/ @Slf4j @Component public class MybatisKeyGenerator implements IKeyGenerator {@Value("${server.worker-id}")private Integer workerId;@Value("${server.data-center-id}")private Integer dataCenterId;@Overridepublic String executeSql(String incrementerName) {log.info("mybatis plus keyGenerator: " + incrementerName + "(" + workerId + "," + dataCenterId + ")");long uid = new SnowflakeIdWorker(workerId, dataCenterId).nextId();return "select " + uid + " from dual";} }注意: id 字段上需要有這個注解哈。因為我們是自定義了id 的生成,并不是使用的哈。😗🤑
@TableId(type = IdType.INPUT) // 如果使用默認的話 @TableId(type = IdType.AUTO) private String id;另外,使用自定義的還需 在實體類上 加上一個@KeySequence("mybatisKeyGenerator")注解。 mybatisKeyGenerator是bean注入時的名稱哈。
即
👨?💻👨?💻
SnowflakeIdWorker 是mybatisplus中官方文檔中說的 Id自增用的雪花算法。
簡介:SnowFlake是Twitter公司采用的一種算法,目的是在分布式系統中產生全局唯一且趨勢遞增的ID。
直接Copy就好,這里只是簡單使用,沒有詳講。好奇的朋友可以去查一查相關講雪花算法的文。😚
/*** 0 | 0001100 10100010 10111110 10001001 01011100 00 | 10001 | 00001 | 0000 00000000* <p>* 0 | 0001100 10100010 10111110 10001001 01011100 00 | 10001 | 00001 | 0000 00000000* 0 | timestamp |datacenterId| workerId | sequence* 正數(占位) | 時間戳二進制 | 數據中心ID | 機器ID | 同一機房同一機器相同時間產生的序列** @author crush*/ public class SnowflakeIdWorker {/*** 數據中心(機房) id*/private long datacenterId;/*** 機器ID*/private long workerId;/*** 同一時間的序列*/private long sequence;/*** 構造方法** @param workerId 工作ID(機器ID)* @param datacenterId 數據中心ID(機房ID)* sequence 從0開始*/public SnowflakeIdWorker(long workerId, long datacenterId){this(workerId, datacenterId, 0);}/*** 構造方法** @param workerId 工作ID(機器ID)* @param datacenterId 數據中心ID(機房ID)* @param sequence 序列號*/public SnowflakeIdWorker(long workerId, long datacenterId, long sequence){// sanity check for workerId and datacenterId// 機房id和機器id不能超過32,不能小于0if (workerId > maxWorkerId || workerId < 0){throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));}if (datacenterId > maxDatacenterId || datacenterId < 0){throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));}System.out.printf("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d",timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId);this.workerId = workerId;this.datacenterId = datacenterId;this.sequence = sequence;}/*** 開始的時間戳(2015-01-01)*/private long twepoch = 1420041600000L;/*** 數據中心(可以理解為機房)的ID所占的位數 5個bite 最大:11111(2進制)--> 31(10進制)*/private long datacenterIdBits = 5L;/*** 機器ID所占的位數 5個bit 最大:11111(2進制)--> 31(10進制)*/private long workerIdBits = 5L;/*** 這個是二進制運算,就是5 bit最多只能有31個數字,也就是說機器id最多只能是32以內* 11111(2進制)--> 31(10進制)*/private long maxWorkerId = -1L ^ (-1L << workerIdBits);/*** 5 bit最多只能有31個數字,機房id最多只能是32以內* 同上*/private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);/*** 同一時間的序列所占的位數 12個bit 111111111111 = 4095 最多就是同一毫秒生成4096個*/private long sequenceBits = 12L;// workerId的偏移量// 0 | 0001100 10100010 10111110 10001001 01011100 00 | 10001 | 00001 | 0000 00000000// 0 | timestamp |datacenterId| workerId | sequence// << sequenceBitsprivate long workerIdShift = sequenceBits;// datacenterId的偏移量// 0 | 0001100 10100010 10111110 10001001 01011100 00 | 10001 | 00001 | 0000 00000000// 0 | timestamp |datacenterId| workerId | sequence// << workerIdBits + sequenceBitsprivate long datacenterIdShift = sequenceBits + workerIdBits;// timestampLeft的偏移量// 0 | 0001100 10100010 10111110 10001001 01011100 00 | 10001 | 00001 | 0000 00000000// 0 | timestamp |datacenterId| workerId | sequence// << sequenceBits + workerIdBits + sequenceBitsprivate long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;/*** 序列號掩碼 4095 (0b111111111111=0xfff=4095)* // 用于序號的與運算,保證序號最大值在0-4095之間*/private long sequenceMask = -1L ^ (-1L << sequenceBits);/*** 最近一次獲取id的時間戳*/private long lastTimestamp = -1L;/*** 獲取工作ID(機器ID)** @return*/public long getWorkerId(){return workerId;}/*** 獲取數據中心ID(機房ID)** @return*/public long getDatacenterId(){return datacenterId;}/*** 獲取最新一次獲取的時間戳** @return*/public long getLastTimestamp(){return lastTimestamp;}/*** 獲取下一個隨機的ID** @return*/public synchronized long nextId(){// 這兒就是獲取當前時間戳,單位是毫秒long timestamp = timeGen();if (timestamp < lastTimestamp){System.err.printf("clock is moving backwards. Rejecting requests until %d.", lastTimestamp);throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",lastTimestamp - timestamp));}// 判斷本次的時間和前一次的時間是否一樣if (lastTimestamp == timestamp){// 如果一樣說明是同一時間獲取多次// 這個意思是說一個毫秒內最多只能有4096個數字,無論你傳遞多少進來,這個位運算保證始終就是在4096這個范圍內,避免你自己傳遞個sequence超過了4096這個范圍sequence = (sequence + 1) & sequenceMask;// 如果與運算得到了0 說明sequence序列已經大于看4095// 如4096 = 1000000000000// 1000000000000// & 111111111111// = 000000000000// = 0if (sequence == 0){// 調用到下一個時間戳的方法timestamp = tilNextMillis(lastTimestamp);}}else{// 如果是當前時間的第一次獲取,那么就置為0sequence = 0;}// 這兒記錄一下最近一次生成id的時間戳,單位是毫秒lastTimestamp = timestamp;// 按上面的偏移量進行左移動// 首位的0可以忽略// 時間戳 << 22 |// datacenterId << 17 |// workerId << 12 |// sequencereturn ((timestamp - twepoch) << timestampLeftShift) |(datacenterId << datacenterIdShift) |(workerId << workerIdShift) |sequence;}/*** 切到下一個時間戳* 作用是,當如果出現同一個時間戳內,獲取的次數超過了4095* 死循環至下一個時間戳,避免沖突** @param lastTimestamp* @return*/private long tilNextMillis(long lastTimestamp){// 獲取最新的時間戳long timestamp = timeGen();// 如果發現最新的時間戳小于或者等于序列號已經超4095的那個時間戳while (timestamp <= lastTimestamp){// 如果是小于或者等于的 那我們就繼續死循環獲取下一個時間戳// 指導切換到了下一個時間戳timestamp = timeGen();}// 返回新的時間戳return timestamp;}/*** 獲取當前時間戳** @return 返回時間戳的毫秒數*/private long timeGen(){return System.currentTimeMillis();}//---------------測試---------------public static void main(String[] args){SnowflakeIdWorker worker = new SnowflakeIdWorker(1, 1);long timer = System.currentTimeMillis();for (int i = 0 ; i < 260000 ; i++){worker.nextId();}System.out.println(System.currentTimeMillis());System.out.println(System.currentTimeMillis() - timer);}}(太占我篇幅了。👴)
3.4、LocalDateTimeSerializerConfig(LocalDateTime序列化)
簡單介紹:此類的作用就是將LocalDateTime 進行格式化的配置,另外注冊了兩個類型轉換器。😀
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.convert.converter.Converter;import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter;/*** LocalDateTime 序列化配置* @Author: crush* @Date: 2021-07-23 14:14*/ @Configuration public class LocalDateTimeSerializerConfig {@Value("${spring.jackson.date-format}")private String DATE_TIME_PATTERN;@Value("${spring.jackson.date-format}")private String DATE_PATTERN ;/*** string轉localdate*/@Beanpublic Converter<String, LocalDate> localDateConverter() {return new Converter<String, LocalDate>() {@Overridepublic LocalDate convert(String source) {if (source.trim().length() == 0) {return null;}try {return LocalDate.parse(source);} catch (Exception e) {return LocalDate.parse(source, DateTimeFormatter.ofPattern(DATE_PATTERN));}}};}/*** string轉localdatetime*/@Beanpublic Converter<String, LocalDateTime> localDateTimeConverter() {return new Converter<String, LocalDateTime>() {@Overridepublic LocalDateTime convert(String source) {if (source.trim().length() == 0) {return null;}// 先嘗試ISO格式: 2019-07-15T16:00:00try {return LocalDateTime.parse(source);} catch (Exception e) {return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DATE_TIME_PATTERN));}}};}/*** 統一配置 LocalDateTime 格式化 直接規定LocalDateTime的格式。*/@Beanpublic Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {JavaTimeModule module = new JavaTimeModule();LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);return builder -> {builder.simpleDateFormat(DATE_TIME_PATTERN);builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(DATE_PATTERN)));builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)));builder.modules(module);};} }終于整到這一步啦,剩下的就只剩測試和實用啦。兄弟,都到這里啦丫,看完吧。
四、測試
@SpringBootTestpublic class UserTest { @Autowired IUserService userService;}4.1、增加:
@Testpublic void testInsert(){ User crush = new User().setUsername("qqqq").setPasswrod("987456"); boolean b = userService.save(crush); System.out.println(b);}從結果,可以看到我們已經成功啦。
4.2、刪除:
補充:我們在這里的刪除,實際上是邏輯刪除,數據庫中數據仍在,并非物理刪除,這是為了防止誤刪而設置的。也是一種數據的保留方式。
@Testpublic void testDelete(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); // 將sql 語句中眾多的條件 換成了代碼 這里沒有細講,之后會出文章 講這個Wrapper。 // 此處意思是 拼成 sql 語句即為 username=qqqq (注:是更在where子句后) wrapper.eq("username","qqqq"); boolean remove = userService.remove(wrapper); System.out.println(remove);}此處執行的實質SQL語句也為修改語句,并非delete語句。
4.3、查找:(分頁查找)
@Testpublic void selectList(){ List<User> list = tbUserService.list(); // 查詢全部} @Testpublic void testPage(){ // 第一個參數 當前頁碼 第二個參數是 每一頁的大小 // 這里的 1,5 說的是查詢第一頁 ,每頁展示5條 Page<User> page = new Page<>(1,5); Page<User> tbUserPage = userService.page(page); // 傳給前臺時,并不需要這么讀取,這里是為了展示 getRecords() 是獲取查詢到的記錄。 List<User> records = tbUserPage.getRecords(); records.forEach(System.out::println);}從結果可以看出是沒有任何問題的哈。
4.4、修改:
@Testpublic void testUpdate(){ UpdateWrapper<User> wrapper = new UpdateWrapper<>(); // 將sql 語句中眾多的條件 換成了代碼 這里沒有細講,之后會出文章 講這個Wrapper。 // 此處意思是 拼成 sql 語句即為 username=qqqq (注:是更在where子句后) wrapper.eq("id",1); User crush = new User().setUsername("寧在春").setPasswrod("123456"); userService.update(crush,wrapper);}4.5、事務回滾:
/*** 事務回滾*/@Transactional@Testpublic void testWork(){ //start-------- delete from tb_user where username=寧在春; QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("username","寧在春"); tbUserService.remove(wrapper); //end //start-------- update set username="我是新手" where id99999=1; UpdateWrapper<User> wrapper1 = new UpdateWrapper<>(); // 在這里我故意將字段寫錯 那么這條SQL 語句 肯定會報錯。 wrapper1.eq("id99999",1); User crush = new User().setUsername("我是新手"); tbUserService.update(crush,wrapper1); //end---------- 這條sql 語句 ,我們知道肯定是不會生效的,那么上面生效的是否回回滾呢?}4.6、druid 監控頁面
druid 配置方式,我并沒有采取常見的bean注入方式,而是寫在了yml配置文件中。用bean也有好處,就是賬號密碼等等可以動態。
為了方便測試,我在controller層中稍微寫了點,并補充了啟動類哈。
/** * @author crush * @since 2021-07-23 */@RestControllerpublic class UserController { private final IUserService tbUserService; public UserController(IUserService tbUserService) { this.tbUserService = tbUserService; } @RequestMapping("/list") public List<User> list(){ return tbUserService.list(); }} @Slf4j@SpringBootApplicationpublic class MyBatisPlus { public static void main(String[] args) { SpringApplication.run(MyBatisPlus.class); log.info("druid 監控頁面:localhost:8081/druid"); }}druid 監控頁面鏈接:localhost:8081/druid 會直接去到登錄頁面,賬號密碼就是配置好的admin。
測試:
跑一下查詢全部的接口,然后在sql監控頁面已經可以看到sql信息啦。點進去的話,能看到詳細信息。
五、自言自語
不知道你有沒有收獲,如果能夠幫助到你,就讓我知道吧,讓我享受一下分享知識的快樂吧。
如果存有疑惑,就私信或留言吧,定會及時回復的。
如有不足之處,也請大家能夠及時指出!!👨?💻👨?💻
今天就到這里啦,明天接著更mybatis-plus結合redis做緩存哈。(使用緩存組件的方式)
共勉or🛌
總結
以上是生活随笔為你收集整理的SpringBoot集成MybatisPlus 涵盖了目前流行的知识点!!!即用即cv即可!!!学过的同学,也可以存储作为工具!!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 史上最详细Docker安装Mysql 带
- 下一篇: Docker 常用命令整合!!!带你一起