SpringBoot3(若依框架)集成Mybatis-Plus和單元測試功能,以及問題解決

一、Mybatis-Plus集成

  1. 新增依賴到父級pom.xml,原先的mybatis依賴可以不動
    在這里插入圖片描述
    需要注意 mybatis-plus與mybatis版本之間的沖突,不要輕易改動依賴,不然分頁也容易出現問題
    在這里插入圖片描述
分類頂級pom.xml下面,如果沒有引入還是出現報錯,在common的模塊下面再引入一份下面的依賴<!-- springboot3 / mybatis-plus 配置 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.16</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.10</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-jsqlparser</artifactId><version>3.5.10</version></dependency>
  1. 替換原來的 MyBatis 配置,修改application.yml文件,修改mybatis配置為mybatis-plus
# MyBatis Plus配置
mybatis-plus:# 搜索指定包別名typeAliasesPackage: com.ruoyi.**.domain# 配置mapper的掃描,找到所有的mapper.xml映射文件mapperLocations: classpath*:mapper/**/*Mapper.xml# 加載全局的配置文件configLocation: classpath:mybatis/mybatis-config.xml
  1. 刪除或者修改MyBatisConfig.java 配置 ,新增MybatisPlusConfig配置
@EnableTransactionManagement(proxyTargetClass = true)
@Configuration
public class MybatisPlusConfig {public static final ThreadLocal<String> TABLE_NAME = new ThreadLocal<>();@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 1. 動態表名配置 (兼容 MyBatis-Plus 3.5.5)DynamicTableNameInnerInterceptor dynamicTableNameInterceptor = new DynamicTableNameInnerInterceptor();// 創建表名處理器映射 (3.5.5 版本使用 setTableNameHandler 方法)Map<String, TableNameHandler> tableNameHandlerMap = new HashMap<>();BaseTableNameEnum.getAllBaseTableName().forEach(table ->tableNameHandlerMap.put(table, (sql, oldTable) ->Optional.ofNullable(TABLE_NAME.get()).orElse(oldTable)));// 3.5.5 版本設置表名處理器的方式dynamicTableNameInterceptor.setTableNameHandler((sql, tableName) -> {TableNameHandler handler = tableNameHandlerMap.get(tableName);return handler != null ? handler.dynamicTableName(sql, tableName) : tableName;});interceptor.addInnerInterceptor(dynamicTableNameInterceptor);// 2. 分頁插件配置interceptor.addInnerInterceptor(paginationInnerInterceptor());// 3. 添加自定義的動態創建表攔截器interceptor.addInnerInterceptor(new DynamicCreateTableInterceptor());// 4. 攻擊 SQL 阻斷插件interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());return interceptor;}/*** 分頁插件,自動識別數據庫類型*/public PaginationInnerInterceptor paginationInnerInterceptor(){PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();// 設置數據庫類型為mysqlpaginationInnerInterceptor.setDbType(DbType.MYSQL);// 設置最大單頁限制數量,默認 500 條,-1 不受限制paginationInnerInterceptor.setMaxLimit(-1L);return paginationInnerInterceptor;}/*** 樂觀鎖插件*/public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor(){return new OptimisticLockerInnerInterceptor();}/*** 如果是對全表的刪除或更新操作,就會終止該操作*/public BlockAttackInnerInterceptor blockAttackInnerInterceptor(){return new BlockAttackInnerInterceptor();}
}

可以不用參考我的,因為我新增了攔截分表功能,官網有配置參考,可以參考官網
https://doc.ruoyi.vip/ruoyi/document/cjjc.html#%E9%9B%86%E6%88%90mybatis-plus%E5%AE%9E%E7%8E%B0mybatis%E5%A2%9E%E5%BC%BA

  1. 僅供參考的分表功能 MybatisPlusUtils 和 DynamicCreateTableInterceptor
/*** MybatisPlus工具類**/
public class MybatisPlusUtils {/*** 獲取動態表名** @return*/public static String getDynamicTableName() {return MybatisPlusConfig.TABLE_NAME.get();}/*** 設置動態表名*/public static void setDynamicTableName(String tableName) {MybatisPlusConfig.TABLE_NAME.set(tableName);}/*** 清空當前線程設置的動態表名** @return* @author wk* @date 2022/2/9 10:37*/public static void emptyDynamicTableName() {MybatisPlusConfig.TABLE_NAME.remove();}/*** 獲取基礎表** @return*/public static String getBaseTableName(String dynamicTableName) {return BaseTableNameEnum.getBaseTableName(dynamicTableName);}
}
/*** 動態創建表攔截器**/
@Slf4j
public class DynamicCreateTableInterceptor implements InnerInterceptor {/*** 動態創建表** @param sh* @param connection* @param transactionTimeout*/@Overridepublic void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {String dynamicTableName = MybatisPlusUtils.getDynamicTableName();if (StringUtils.isBlank(dynamicTableName)) {return;}String baseTableName = MybatisPlusUtils.getBaseTableName(dynamicTableName);if (StringUtils.isNotBlank(baseTableName)&&!baseTableName.contains("null")) {try {String dataBase = connection.getCatalog();String sql = "SELECT count(1) FROM information_schema.tables WHERE table_schema=? AND table_name = ?";PreparedStatement preparedStatement = connection.prepareStatement(sql);preparedStatement.setString(1, dataBase);preparedStatement.setString(2, dynamicTableName);ResultSet resultSet = preparedStatement.executeQuery();if (resultSet.next()) {//獲取表是否存在int count = resultSet.getInt(1);close(preparedStatement, resultSet);//如果表不存在if (count == 0) {sql = "SHOW CREATE TABLE " + baseTableName;//獲取創建表語句preparedStatement = connection.prepareStatement(sql);resultSet = preparedStatement.executeQuery();if (resultSet.next()) {String createTableSql = resultSet.getString(2);close(preparedStatement, resultSet);//創建表sql = createTableSql.replaceFirst(baseTableName, dynamicTableName);preparedStatement = connection.prepareStatement(sql);preparedStatement.executeUpdate();close(preparedStatement, resultSet);log.info("【動態創建表成功】表名:{}", dynamicTableName);} else {close(preparedStatement, resultSet);}}} else {close(preparedStatement, resultSet);}} catch (Exception e) {log.info(String.format("【動態創建表失敗】表名: %s", dynamicTableName), e);}}}/*** 關閉資源** @param preparedStatement* @param resultSet*/private void close(PreparedStatement preparedStatement, ResultSet resultSet) {if (preparedStatement != null) {try {preparedStatement.close();} catch (SQLException e) {e.printStackTrace();}}if (resultSet != null) {try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}}}
  1. 使用方式在需要增刪改查的地方調用方法即可
 /*** 添加任務(使用動態表名)*/@Transactional@Overridepublic void addTaskWithDynamicTable(實體類 task) {task.setCreateTime(DateUtils.getNowDate());try {// 設置動態表名(按月份分表)String monthSuffix = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy"));String dynamicTable = "表名_" + monthSuffix;MybatisPlusUtils.setDynamicTableName(dynamicTable);// 插入數據(會自動使用動態表名)int result = 當前實現類的方法.insert(task);log.info("【動態表名插入】表名: {}, 結果: {}", dynamicTable, result);} finally {MybatisPlusUtils.emptyDynamicTableName();}}

二、集成單元測試

  1. 使用依賴,在ruoyi-admin的pom.xml下添加依賴
 <!-- 單元測試--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>

不需要指定版本,自動依賴,下面是錯誤案例,在其他模塊引入了單元測試版本不一樣,造成混亂

       <!-- 單元測試-->
<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-test</artifactId>-->
<!--            <scope>test</scope>-->
<!--        </dependency>-->
<!--        <dependency>-->
<!--            <groupId>org.junit.jupiter</groupId>-->
<!--            <artifactId>junit-jupiter</artifactId>-->
<!--            <scope>test</scope>-->
<!--        </dependency>-->
<!--        <dependency>-->
<!--            <groupId>org.springframework</groupId>-->
<!--            <artifactId>spring-test</artifactId>-->
<!--            <scope>test</scope>-->
<!--        </dependency>--><!--        <dependency>-->
<!--            <groupId>junit</groupId>-->
<!--            <artifactId>junit</artifactId>-->
<!--            <version>4.13.2</version>-->
<!--        </dependency>-->
  1. 簡簡單單才是最好的,不然容易出現錯誤,一直以為引入的是JUnit 5結果是JUnit 4導致運行失敗
    ,在ruoyi-admin的src下創建test模塊(與main同級),導入依賴后更新maven,確保依賴加入
/**1. @description 測試MybatisPlus和分表功能*/

//JUnit 4
//@SpringBootTest(classes = Application.class,
//        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
//@RunWith(SpringRunner.class)
//JUnit 5

("MybatisPlus測試")
public class MybatisPlusTest {//測試分頁功能private service方法 taskMapper;private ISysUserService sysUserService;private RuoYiConfig ruoYiConfig;public void testContextLoad() {assertNotNull("taskService 注入失敗", taskMapper);assertNotNull("sysUserService 注入失敗", sysUserService);log.info("服務注入測試通過:"+ruoYiConfig.getName());}/*** 添加任務(使用動態表名)*/("添加任務(使用動態表名)")public void addTaskWithDynamicTable() {try {實體類 task = new  實體類();task.settName("張三");task.setAge("18");task.setPatientSex(1);task.setMobile("13888888888");task.setIdCard("420000000000000000");// 插入數據(會自動使用動態表名)taskMapper.insertHosCollectTaskInfo(task);} finally {
//            MybatisPlusUtils.emptyDynamicTableName();}}("測試查詢功能")public void testContextLoads() {log.info("Spring上下文加載成功,taskMapper已注入");}("測試查詢功能")public void testSelect() {log.info("測試查詢功能");SysUser sysUser = sysUserService.selectUserById(1L);log.info("查詢結果:{}", sysUser);}
}

三、問題解決

  1. 在 JUnit 5 中,不需要 @RunWith(SpringRunner.class),直接使用 @SpringBootTest 即可
  2. 在 JUnit 4 中,通常需要顯式指定 @RunWith(SpringRunner.class),使用RunWith才能實例化到spring容器中
  3. JUnit 4如何沒有引入 @RunWith,就會出現 NullPointerExecption,是因為 Spring 的依賴注入沒有正確完成,或者相關的 Bean 沒有被正確加載。
  4. 如果添加完成還是沒有完成,還是服務注入失敗問題,就需要使用 @ComponentScan 顯式指定掃描包
// 正確配置啟動類
(scanBasePackages = "com.ruoyi")
("com.ruoyi.**.mapper")
  1. 動態表名導致自動填充失效,實體類字段未正確配置自動填充策略
public void addTaskWithDynamicTable(實體類 task) {// 先設置動態表名MybatisPlusUtils.setDynamicTableName("表名");// 再手動設置時間(雙重保障)task.setCreateTime(new Date());task.setUpdateTime(new Date());mapper類.insert(task);
}#避免措施:實體類字段使用正確注解
(fill = FieldFill.INSERT) 
private Date createTime;
  1. 分頁插件沖突問題,PageHelper 與 MyBatis-Plus 分頁不兼容
    原因:同時存在兩套分頁機制,最好是不要改動原來的依賴,然后引入新的mybatis-plus即可

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/916405.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/916405.shtml
英文地址,請注明出處:http://en.pswp.cn/news/916405.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

刪除遠程分支上非本分支的提交記錄

要刪除遠程分支上非本分支的提交記錄&#xff08;即主分支的提交歷史&#xff09;&#xff0c;需要使用 Git 的重寫歷史功能。以下是完整解決方案&#xff1a; 解決方案步驟&#xff1a; 創建干凈的新分支&#xff08;基于主分支最新提交&#xff09; # 切換到主分支并更新 git…

Flask input 和datalist結合

<input list"categories" name"category" id"category" class"form-control" placeholder"任務分類" required> 這段代碼是一個 HTML 輸入控件&#xff0c;結合了 <input> 和 <datalist>&#xff0c;用來…

嵌入式分享#27:原來GT911有兩個I2C地址(全志T527)

最近在調試全志T527的觸摸功能時&#xff0c;發現GT911觸摸芯片的I2C地址有時是0x5d&#xff0c;有時又識別成0x14&#xff0c;不知道大家有沒有遇到過類似這個情況。雖然最后使用0x5d地址調通了觸摸功能&#xff0c;但是一直還是很困惑&#xff0c;為什么會出現0x14和0x5d兩個…

Linux運維新人自用筆記(Rsync遠程傳輸備份,服務端、郵箱和客戶端配置、腳本)

內容全為個人理解和自查資料梳理&#xff0c;歡迎各位大神指點&#xff01;每天學習較為零散。day24一、Rsync傳輸文件#安裝rsync#-a遞歸同步&#xff08;包含子目錄&#xff09;保留文件權限、所有者、組、時間戳等元數據 #??-z傳輸時壓縮數據 #??-v顯示詳細同步過程 #??…

以 “有機” 重構增長:云集從電商平臺到健康生活社區的躍遷

當電商行業陷入流量爭奪的紅海&#xff0c;同質化運營模式難以突破增長瓶頸時&#xff0c;云集以從精選電商到有機生活平臺的戰略轉型&#xff0c;開辟出差異化發展路徑。其轉型并非憑經驗決斷的孤例&#xff0c;而是建立在對市場趨勢的精準研判、用戶需求的深度解碼&#xff0…

【2025最新版】midjourney小白零基礎入門到精通教程!人工智能繪圖+AI繪圖+AI畫圖,一鍵出圖教程 (持續更新)

前言 現在市面上相關的AI繪畫工具非常多&#xff0c;有6pen.art、Stable Diffusion、DALL.E、Midjourney等。 而MJ就目前而言&#xff0c;它是一款強大的人工智能工具&#xff0c;旨在幫助設計師和創意人員完成各種設計任務。 非常適合我們圖像工作者&#xff0c;從 UI 設計到…

2025年滲透測試面試題總結-2025年HW(護網面試) 70(題目+回答)

安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 2025年HW(護網面試) 70 一、自我介紹 二、同源策略 & 三大漏洞對比解析 1. 同源策略&#xff08;SOP&…

加權卡爾曼濾波

加權卡爾曼濾波融合&#xff0c;它通過給不同傳感器或估計結果分配不同的權重&#xff0c;來提高狀態估計的精度和可靠性。一、卡爾曼濾波1.狀態方程2.觀測方程其中&#xff1a;基本方程①狀態一步預測②狀態估計③濾波增益④一步預測均方差⑤估計均方誤差二、加權卡爾曼濾波對…

【世紀龍科技】新能源汽車維護與故障診斷-汽車專業數字課程資源

在職業院校汽車專業教學中&#xff0c;理論與實踐脫節、設備投入不足、學生實操能力薄弱等問題長期存在。如何讓學生在有限的教學資源下掌握新能源汽車核心技術&#xff1f;如何讓教師更高效地開展理實一體化教學&#xff1f;《新能源汽車維護與故障診斷》數字課程資源&#xf…

Windows Server系統安裝JDK,一直卡在“應用程序正在為首次使用作準備,請稍候”

一、背景 第二次遇到這個問題了&#xff0c;但是居然沒想起來之前遇到過&#xff0c;又問元寶給的答案不對&#xff0c;還沒想起來之前收藏過解決方案&#xff0c;這里特別記錄一下。 二、問題描述 操作系統是Windows Sever2019&#xff0c;安裝JDK時卡住一直過不去&#xff0…

機器學習入門:線性回歸詳解與實戰

線性回歸&#xff08;Linear Regression&#xff09;是機器學習中最基礎也最常用的算法之一&#xff0c;無論是初學者入門還是實際業務場景&#xff0c;都能看到它的身影。本文將從概念、原理到代碼實現&#xff0c;帶你全方位了解線性回歸。一、什么是線性回歸&#xff1f;簡單…

第3篇:軟鏈接 mklink /D 教程:輕量緩存目錄遷移利器

我們通過諸多實踐后將三種鏈接方案分別獨立成篇&#xff0c;可以讓不同需求場景的讀者精準獲取所需內容。下面是回顧我們文章系列策劃的三篇博客標題、定位和詳細大綱&#xff0c;每篇都圍繞一個核心方案展開&#xff0c;具備教學性、實用性和實操性&#xff1a; &#x1f4d8;…

力扣 hot100 Day52

124. 二叉樹中的最大路徑和 二叉樹中的 路徑 被定義為一條節點序列&#xff0c;序列中每對相鄰節點之間都存在一條邊。同一個節點在一條路徑序列中 至多出現一次 。該路徑 至少包含一個 節點&#xff0c;且不一定經過根節點。 路徑和 是路徑中各節點值的總和。 給你一個二叉…

數據存儲:OLAP vs OLTP

下面系統性地進行介紹,包括OLAP數據庫的基本概念、特點、常見產品,以及它們在實際工作中的典型應用場景,最后對比與關系型數據庫(OLTP)的區別。 一、OLAP數據庫是什么? OLAP(Online Analytical Processing,聯機分析處理)數據庫,主要用于大數據量、多維度、復雜查詢與…

云原生網絡策略自動化在微服務架構 API 安全防護與流量管理中的應用

云原生網絡策略自動化在微服務架構中的核心價值隨著微服務架構在金融、電商等領域的廣泛應用&#xff0c;API安全防護與流量管理已成為企業數字化轉型的關鍵挑戰。Gartner 2023年報告顯示&#xff0c;83%的分布式系統因網絡策略缺失導致安全事件&#xff0c;而傳統靜態策略配置…

無需云服務器的內網穿透方案 -- cloudflare tunnel

內網穿透 原文地址 https://docs.caolib.dpdns.org/network/cloudflare tunnel.html Cloudflare Tunnel 內網穿透工具 1.簡介 1.1 介紹 官方介紹&#xff1a;Cloudflare Tunnel 為您提供了一種安全的方式&#xff0c;無需公開路由的 IP 地址即可將資源連接到 Cloudflare。使用…

目前市面上arm64-v8a、armeabi-v7a設備的市占率有多少?為什么x86架構的手機越來越少?

deepseek回答&#xff1a; 當前全球范圍內&#xff0c;arm64-v8a 架構在安卓設備中的市占率已超過 64%&#xff0c;遠超其他架構版本。具體分布如下&#xff1a; &#x1f4ca; 各架構市場份額對比 架構類型市占率定位與趨勢arm64-v8a≥64%主流 64 位架構&#xff0c;性能最…

Java中配置兩個r2db連接不同的數據庫

Java中配置兩個r2db連接不同的數據庫在實際項目中不可避免的存在使用兩個數據庫的情況&#xff0c;下面將系統地講解相關配置方案&#xff0c;包含配置文件、數據庫配置類、注解原理、常見錯誤排查等維度&#x1f9e9; 一、配置文件說明&#xff08;application.yml&#xff09…

Swagger 配置及使用指南

Spring Boot 項目集成 Swagger 配置及使用指南 一、Swagger 簡介 Swagger 是一個用于設計、構建、文檔化和使用 RESTful API 的框架。通過集成 Swagger&#xff0c;開發者可以&#xff1a; 自動生成實時 API 文檔直接在瀏覽器中測試 API 接口減少手動編寫文檔的工作量支持團隊協…

什么是緩存雪崩?緩存擊穿?緩存穿透?分別如何解決?什么是緩存預熱?

緩存雪崩&#xff1a;在一個時間段內&#xff0c;有大量的key過期&#xff0c;或者Redis服務宕機&#xff0c;導致大量的請求到達數據庫,帶來巨大壓力- 給key設置不同的TTL、利用Redis集群提高服務的高可用性、添加多級緩存、添加降級流策略緩存擊穿&#xff1a;給某一個key設置…