From 098d3347a0df808908aab8c554cd7c4febc5e6d9 Mon Sep 17 00:00:00 2001
From: 疯狂的狮子Li <15040126243@163.com>
Date: 星期一, 26 八月 2024 11:43:59 +0800
Subject: [PATCH] !577 发布 5.2.2 正式版 安全性提升 Merge pull request !577 from 疯狂的狮子Li/dev

---
 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java                        |    4 
 ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java                           |   20 
 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java                                      |    1 
 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/MyBatisDataSourceMonitor.java                            |  105 ++
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java                                 |    5 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java                            |    4 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java                       |    8 
 ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java                                                        |   17 
 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/controller/SseController.java                                  |   87 ++
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java                         |    7 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java                               |   12 
 .run/ruoyi-snailjob-server.run.xml                                                                                                |    2 
 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java                  |   57 
 ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml                                              |  230 -----
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java                                 |    6 
 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java                               |   36 
 ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java                                                     |   36 
 ruoyi-common/ruoyi-common-web/pom.xml                                                                                             |   13 
 ruoyi-admin/src/main/resources/application.yml                                                                                    |   14 
 script/docker/nginx/conf/nginx.conf                                                                                               |    5 
 ruoyi-modules/ruoyi-generator/pom.xml                                                                                             |   32 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java                                |    5 
 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java                                     |   58 +
 ruoyi-admin/src/main/resources/application-prod.yml                                                                               |    3 
 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/dto/SseMessageDto.java                                         |   29 
 ruoyi-admin/src/main/resources/application-dev.yml                                                                                |    3 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java                |    6 
 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java                                |    7 
 ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java                                                    |   32 
 ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm                                                                |    6 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java                                  |    2 
 pom.xml                                                                                                                           |   71 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java                                          |    8 
 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/listener/SseTopicListener.java                                 |   48 +
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java                                              |    4 
 ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java                          |    2 
 ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm                                                         |    4 
 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java                                   |    4 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java                             |    4 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java                             |    4 
 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java                                |  129 ++
 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java                        |    8 
 script/docker/docker-compose.yml                                                                                                  |    8 
 ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java                 |    4 
 ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm                                                               |    7 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java                                  |   44 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java                              |   18 
 ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml                                                         |    3 
 ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java                               |    4 
 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java                                     |    9 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java                                |    5 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java                     |    8 
 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java                                         |    3 
 ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java                                       |    2 
 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java                                      |   16 
 ruoyi-common/ruoyi-common-sse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports |    1 
 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseProperties.java                                      |   21 
 .run/ruoyi-server.run.xml                                                                                                         |    6 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java                                  |   10 
 ruoyi-common/ruoyi-common-excel/pom.xml                                                                                           |    5 
 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java                                |   13 
 ruoyi-modules/ruoyi-system/pom.xml                                                                                                |    5 
 ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/SecurityConfig.java                    |   29 
 .run/ruoyi-monitor-admin.run.xml                                                                                                  |    2 
 ruoyi-extend/ruoyi-monitor-admin/pom.xml                                                                                          |   13 
 ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java                                                          |   12 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java                                   |    6 
 ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java                                                            |   22 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java                             |   11 
 script/sql/sqlserver/snail_job_sqlserver.sql                                                                                      |   70 +
 ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml                                                        |    3 
 README.md                                                                                                                         |    4 
 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java                                    |  160 +++
 ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java                                 |   44 
 script/sql/snail_job.sql                                                                                                          |   17 
 ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java                        |   52 +
 ruoyi-common/ruoyi-common-sse/pom.xml                                                                                             |   36 
 ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml                                        |   83 --
 ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/manager/TenantSpringCacheManager.java                    |    9 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java                   |   16 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java                       |   43 
 ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/ActuatorAuthFilter.java                |   64 +
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java                         |   12 
 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/IGenTableService.java                                   |    9 
 ruoyi-common/ruoyi-common-bom/pom.xml                                                                                             |    9 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java                           |    5 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java                 |   20 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java                                  |   11 
 ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm                                                              |    4 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java                            |    2 
 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java                            |   17 
 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java                             |    7 
 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java                                     |   16 
 ruoyi-admin/pom.xml                                                                                                               |   37 
 ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java                                         |   12 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java                              |    5 
 ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/notifier/CustomNotifier.java                             |   21 
 ruoyi-common/pom.xml                                                                                                              |    1 
 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java                                                |   13 
 /dev/null                                                                                                                         |   33 
 ruoyi-modules/ruoyi-workflow/pom.xml                                                                                              |    2 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java                           |    4 
 script/sql/postgres/snail_job_postgre.sql                                                                                         |   23 
 ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml                                                               |    3 
 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java                 |   11 
 ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java                                                  |   33 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java                                 |   11 
 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java                                  |    4 
 ruoyi-common/ruoyi-common-core/pom.xml                                                                                            |    5 
 script/sql/oracle/snail_job_oracle.sql                                                                                            |   31 
 ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java                                                       |   36 
 111 files changed, 1,692 insertions(+), 731 deletions(-)

diff --git a/.run/ruoyi-monitor-admin.run.xml b/.run/ruoyi-monitor-admin.run.xml
index 5b32519..478b4f3 100644
--- a/.run/ruoyi-monitor-admin.run.xml
+++ b/.run/ruoyi-monitor-admin.run.xml
@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.2.1" />
+        <option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.2.2" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
       </settings>
diff --git a/.run/ruoyi-server.run.xml b/.run/ruoyi-server.run.xml
index 9fefae6..541800d 100644
--- a/.run/ruoyi-server.run.xml
+++ b/.run/ruoyi-server.run.xml
@@ -1,12 +1,12 @@
 <component name="ProjectRunConfigurationManager">
-  <configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
+  <configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="婕旂ず鏈�">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-server:5.2.1" />
+        <option name="imageTag" value="ruoyi/ruoyi-server:5.2.2" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
       </settings>
     </deployment>
     <method v="2" />
   </configuration>
-</component>
+</component>
\ No newline at end of file
diff --git a/.run/ruoyi-snailjob-server.run.xml b/.run/ruoyi-snailjob-server.run.xml
index 914809d..5221eef 100644
--- a/.run/ruoyi-snailjob-server.run.xml
+++ b/.run/ruoyi-snailjob-server.run.xml
@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.2.1" />
+        <option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.2.2" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" />
       </settings>
diff --git a/README.md b/README.md
index ad9c2ce..eeb3f7b 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
 [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE)
 [![浣跨敤IntelliJ IDEA寮�鍙戠淮鎶(https://img.shields.io/badge/IntelliJ%20IDEA-鎻愪緵鏀寔-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
 <br>
-[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.2.1-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
+[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.2.2-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
 [![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.2-blue.svg)]()
 [![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]()
 [![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]()
@@ -61,6 +61,7 @@
 | 鏁版嵁搴撹繛鎺ユ睜      | 閲囩敤 HikariCP Spring瀹樻柟鍐呯疆杩炴帴姹� 閰嶇疆绠�鍗� 浠ユ�ц兘涓庣ǔ瀹氭�ч椈鍚嶅ぉ涓�                                                                        | 閲囩敤 druid bug浼楀 绀惧尯缁存姢宸� 娲昏穬搴︿綆 閰嶇疆浼楀绻佺悙鎬ц兘涓�鑸�                                               |
 | 鏁版嵁搴撲富閿�       | 閲囩敤 闆姳ID 鍩轰簬鏃堕棿鎴崇殑 鏈夊簭澧為暱 鍞竴ID 鍐嶄篃涓嶇敤涓哄垎搴撳垎琛� 鏁版嵁鍚堝苟涓婚敭鍐茬獊閲嶅鑰屽彂鎰�                                                                  | 閲囩敤 鏁版嵁搴撹嚜澧濱D 鏀寔鏁版嵁閲忔湁闄� 涓嶆敮鎸佸鏁版嵁婧愪富閿敮涓�                                                     |
 | WebSocket鍗忚 | 鍩轰簬 Spring 灏佽鐨� WebSocket 鍗忚 鎵╁睍浜員oken閴存潈涓庡垎甯冨紡浼氳瘽鍚屾 涓嶅啀鍙槸鍩轰簬鍗曟満鐨勫簾鐗�                                                         | 鏃�                                                                                  |
+| SSE鎺ㄩ��       | 閲囩敤 Spring SSE 瀹炵幇 鎵╁睍浜員oken閴存潈涓庡垎甯冨紡浼氳瘽鍚屾                                                                               | 鏃�                                                                                  |
 | 搴忓垪鍖�         | 閲囩敤 Jackson Spring瀹樻柟鍐呯疆搴忓垪鍖� 闈犺氨!!!                                                                                    | 閲囩敤 fastjson bugjson 杩滆繎闂诲悕                                                           | 
 | 鍒嗗竷寮忓箓绛�       | 鍙傝�冪編鍥TIS闃查噸绯荤粺绠�鍖栧疄鐜�(缁嗚妭鍙湅鏂囨。)                                                                                          | 鎵嬪姩缂栧啓娉ㄨВ鍩轰簬aop瀹炵幇                                                                      |
 | 鍒嗗竷寮忛攣        | 閲囩敤 Lock4j 搴曞眰鍩轰簬 Redisson                                                                                           | 鏃�                                                                                  |
@@ -72,6 +73,7 @@
 | 鎺ュ彛鏂囨。        | 閲囩敤 SpringDoc銆乯avadoc 鏃犳敞瑙i浂鍏ヤ镜鍩轰簬java娉ㄩ噴<br/>鍙渶鎶婃敞閲婂啓濂� 鏃犻渶鍐嶅啓涓�澶у爢鐨勬枃妗f敞瑙d簡                                                     | 閲囩敤 Springfox 宸插仠姝㈢淮鎶� 闇�瑕佺紪鍐欏ぇ閲忕殑娉ㄨВ鏉ユ敮鎸佹枃妗g敓鎴�                                                | 
 | 鏍¢獙妗嗘灦        | 閲囩敤 Validation 鏀寔娉ㄨВ涓庡伐鍏风被鏍¢獙 娉ㄨВ鏀寔鍥介檯鍖�                                                                                  | 浠呮敮鎸佹敞瑙� 涓旀敞瑙d笉鏀寔鍥介檯鍖�                                                                    |
 | Excel妗嗘灦     | 閲囩敤 Alibaba EasyExcel 鍩轰簬鎻掍欢鍖�<br/>妗嗘灦瀵瑰叾澧炲姞浜嗗緢澶氬姛鑳� 渚嬪 鑷姩鍚堝苟鐩稿悓鍐呭 鑷姩鎺掑垪甯冨眬 瀛楀吀缈昏瘧绛�                                               | 鍩轰簬 POI 鎵嬪啓瀹炵幇 鍔熻兘鏈夐檺 澶嶆潅 鎵╁睍鎬у樊                                                           |
+| 宸ヤ綔娴佹敮鎸�       | 鏀寔鍚勭澶嶆潅瀹℃壒 杞姙 濮旀淳 鍔犲噺绛� 浼氱 鎴栫 绁ㄧ 绛夊姛鑳�                                                                                   | 鏃�                                                                                  |
 | 宸ュ叿绫绘鏋�       | 閲囩敤 Hutool銆丩ombok 涓婄櫨绉嶅伐鍏疯鐩�90%鐨勪娇鐢ㄩ渶姹� 鍩轰簬娉ㄨВ鑷姩鐢熸垚 get set 绛夌畝鍖栨鏋跺ぇ閲忎唬鐮�                                                       | 鎵嬪啓宸ュ叿绋冲畾鎬у樊鏄撳嚭闂 宸ュ叿鏁伴噺鏈夐檺 浠g爜鑷冭偪闇�鑷繁鎵嬪啓 get set 绛�                                            | 
 | 鐩戞帶妗嗘灦        | 閲囩敤 SpringBoot-Admin 鍩轰簬SpringBoot瀹樻柟 actuator 鎺㈤拡鏈哄埗<br/>瀹炴椂鐩戞帶鏈嶅姟鐘舵�� 妗嗘灦杩樹负鍏舵墿灞曚簡鍦ㄧ嚎鏃ュ織鏌ョ湅鐩戞帶                                    | 鏃�                                                                                  | 
 | 閾捐矾杩借釜        | 閲囩敤 Apache SkyWalking 杩樺湪涓鸿姹備笉鐭ラ亾鍘诲摢浜� 鍒板摢鍑轰簡闂鑰岀儲鎭煎悧<br/>鐢ㄤ簡瀹冨嵆鍙疄鏃舵煡鐪嬭姹傜粡杩囩殑姣忎竴澶勬瘡涓�涓妭鐐�                                            | 鏃�                                                                                  |
diff --git a/pom.xml b/pom.xml
index 7094419..750673b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,45 +13,46 @@
     <description>RuoYi-Vue-Plus澶氱鎴风鐞嗙郴缁�</description>
 
     <properties>
-        <revision>5.2.1</revision>
-        <spring-boot.version>3.2.6</spring-boot.version>
+        <revision>5.2.2</revision>
+        <spring-boot.version>3.2.9</spring-boot.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <java.version>17</java.version>
         <mybatis.version>3.5.16</mybatis.version>
-        <springdoc.version>2.5.0</springdoc.version>
+        <springdoc.version>2.6.0</springdoc.version>
         <therapi-javadoc.version>0.15.0</therapi-javadoc.version>
-        <poi.version>5.2.3</poi.version>
-        <easyexcel.version>3.3.4</easyexcel.version>
+        <easyexcel.version>4.0.2</easyexcel.version>
         <velocity.version>2.3</velocity.version>
         <satoken.version>1.38.0</satoken.version>
         <mybatis-plus.version>3.5.7</mybatis-plus.version>
         <p6spy.version>3.9.1</p6spy.version>
-        <hutool.version>5.8.27</hutool.version>
+        <hutool.version>5.8.31</hutool.version>
         <okhttp.version>4.10.0</okhttp.version>
         <spring-boot-admin.version>3.2.3</spring-boot-admin.version>
-        <redisson.version>3.31.0</redisson.version>
+        <redisson.version>3.34.1</redisson.version>
         <lock4j.version>2.2.7</lock4j.version>
         <dynamic-ds.version>4.3.1</dynamic-ds.version>
-        <alibaba-ttl.version>2.14.4</alibaba-ttl.version>
-        <snailjob.version>1.0.1</snailjob.version>
-        <mapstruct-plus.version>1.3.6</mapstruct-plus.version>
+        <snailjob.version>1.1.2</snailjob.version>
+        <mapstruct-plus.version>1.4.4</mapstruct-plus.version>
         <mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
-        <lombok.version>1.18.32</lombok.version>
+        <lombok.version>1.18.34</lombok.version>
         <bouncycastle.version>1.76</bouncycastle.version>
         <justauth.version>1.16.6</justauth.version>
         <!-- 绂荤嚎IP鍦板潃瀹氫綅搴� -->
         <ip2region.version>2.7.0</ip2region.version>
+        <undertow.version>2.3.15.Final</undertow.version>
 
         <!-- OSS 閰嶇疆 -->
         <aws.sdk.version>2.25.15</aws.sdk.version>
         <aws.crt.version>0.29.13</aws.crt.version>
         <!-- SMS 閰嶇疆 -->
-        <sms4j.version>3.2.1</sms4j.version>
+        <sms4j.version>3.3.2</sms4j.version>
         <!-- 闄愬埗妗嗘灦涓殑fastjson鐗堟湰 -->
         <fastjson.version>1.2.83</fastjson.version>
+        <!-- 闈㈠悜杩愯鏃剁殑D-ORM渚濊禆 -->
+        <anyline.version>8.7.2-20240808</anyline.version>
         <!--宸ヤ綔娴侀厤缃�-->
-        <flowable.version>7.0.0</flowable.version>
+        <flowable.version>7.0.1</flowable.version>
 
         <!-- 鎻掍欢鐗堟湰 -->
         <maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
@@ -156,25 +157,9 @@
             </dependency>
 
             <dependency>
-                <groupId>org.apache.poi</groupId>
-                <artifactId>poi</artifactId>
-                <version>${poi.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.poi</groupId>
-                <artifactId>poi-ooxml</artifactId>
-                <version>${poi.version}</version>
-            </dependency>
-            <dependency>
                 <groupId>com.alibaba</groupId>
                 <artifactId>easyexcel</artifactId>
                 <version>${easyexcel.version}</version>
-                <exclusions>
-                    <exclusion>
-                        <groupId>org.apache.poi</groupId>
-                        <artifactId>poi-ooxml-schemas</artifactId>
-                    </exclusion>
-                </exclusions>
             </dependency>
 
             <!-- velocity浠g爜鐢熸垚浣跨敤妯℃澘 -->
@@ -307,12 +292,6 @@
                 <version>${snailjob.version}</version>
             </dependency>
 
-            <dependency>
-                <groupId>com.alibaba</groupId>
-                <artifactId>transmittable-thread-local</artifactId>
-                <version>${alibaba-ttl.version}</version>
-            </dependency>
-
             <!-- 鍔犲瘑鍖呭紩鍏� -->
             <dependency>
                 <groupId>org.bouncycastle</groupId>
@@ -334,6 +313,28 @@
             </dependency>
 
             <dependency>
+                <groupId>io.undertow</groupId>
+                <artifactId>undertow-core</artifactId>
+                <version>${undertow.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>io.undertow</groupId>
+                <artifactId>undertow-servlet</artifactId>
+                <version>${undertow.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>io.undertow</groupId>
+                <artifactId>undertow-websockets-jsr</artifactId>
+                <version>${undertow.version}</version>
+            </dependency>
+
+            <dependency>
+                <artifactId>commons-compress</artifactId>
+                <groupId>org.apache.commons</groupId>
+                <version>1.26.2</version>
+            </dependency>
+
+            <dependency>
                 <groupId>com.alibaba</groupId>
                 <artifactId>fastjson</artifactId>
                 <version>${fastjson.version}</version>
diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml
index 610e9d7..9e97804 100644
--- a/ruoyi-admin/pom.xml
+++ b/ruoyi-admin/pom.xml
@@ -22,21 +22,28 @@
             <groupId>com.mysql</groupId>
             <artifactId>mysql-connector-j</artifactId>
         </dependency>
-        <!-- Oracle -->
-        <dependency>
-            <groupId>com.oracle.database.jdbc</groupId>
-            <artifactId>ojdbc8</artifactId>
-        </dependency>
-        <!-- PostgreSql -->
-        <dependency>
-            <groupId>org.postgresql</groupId>
-            <artifactId>postgresql</artifactId>
-        </dependency>
-        <!-- SqlServer -->
-        <dependency>
-            <groupId>com.microsoft.sqlserver</groupId>
-            <artifactId>mssql-jdbc</artifactId>
-        </dependency>
+
+<!--        &lt;!&ndash; mp鏀寔鐨勬暟鎹簱鍧囨敮鎸� 鍙渶瑕佸鍔犲搴旂殑jdbc渚濊禆鍗冲彲 &ndash;&gt;-->
+<!--        &lt;!&ndash; Oracle &ndash;&gt;-->
+<!--        <dependency>-->
+<!--            <groupId>com.oracle.database.jdbc</groupId>-->
+<!--            <artifactId>ojdbc8</artifactId>-->
+<!--        </dependency>-->
+<!--        &lt;!&ndash; 鍏煎oracle浣庣増鏈� &ndash;&gt;-->
+<!--        <dependency>-->
+<!--            <groupId>com.oracle.database.nls</groupId>-->
+<!--            <artifactId>orai18n</artifactId>-->
+<!--        </dependency>-->
+<!--        &lt;!&ndash; PostgreSql &ndash;&gt;-->
+<!--        <dependency>-->
+<!--            <groupId>org.postgresql</groupId>-->
+<!--            <artifactId>postgresql</artifactId>-->
+<!--        </dependency>-->
+<!--        &lt;!&ndash; SqlServer &ndash;&gt;-->
+<!--        <dependency>-->
+<!--            <groupId>com.microsoft.sqlserver</groupId>-->
+<!--            <artifactId>mssql-jdbc</artifactId>-->
+<!--        </dependency>-->
 
         <dependency>
             <groupId>org.dromara</groupId>
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java
index 1db68f1..b561693 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java
@@ -24,9 +24,9 @@
 import org.dromara.common.social.config.properties.SocialLoginConfigProperties;
 import org.dromara.common.social.config.properties.SocialProperties;
 import org.dromara.common.social.utils.SocialUtils;
+import org.dromara.common.sse.dto.SseMessageDto;
+import org.dromara.common.sse.utils.SseMessageUtils;
 import org.dromara.common.tenant.helper.TenantHelper;
-import org.dromara.common.websocket.dto.WebSocketMessageDto;
-import org.dromara.common.websocket.utils.WebSocketUtils;
 import org.dromara.system.domain.bo.SysTenantBo;
 import org.dromara.system.domain.vo.SysClientVo;
 import org.dromara.system.domain.vo.SysTenantVo;
@@ -102,11 +102,11 @@
 
         Long userId = LoginHelper.getUserId();
         scheduledExecutorService.schedule(() -> {
-            WebSocketMessageDto dto = new WebSocketMessageDto();
+            SseMessageDto dto = new SseMessageDto();
             dto.setMessage("娆㈣繋鐧诲綍RuoYi-Vue-Plus鍚庡彴绠$悊绯荤粺");
-            dto.setSessionKeys(List.of(userId));
-            WebSocketUtils.publishMessage(dto);
-        }, 3, TimeUnit.SECONDS);
+            dto.setUserIds(List.of(userId));
+            SseMessageUtils.publishMessage(dto);
+        }, 5, TimeUnit.SECONDS);
         return R.ok(loginVo);
     }
 
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java b/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java
index a472404..07595e0 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java
@@ -3,6 +3,8 @@
 import cn.dev33.satoken.config.SaTokenConfig;
 import cn.dev33.satoken.listener.SaTokenListener;
 import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.convert.Convert;
 import cn.hutool.http.useragent.UserAgent;
 import cn.hutool.http.useragent.UserAgentUtil;
 import lombok.RequiredArgsConstructor;
@@ -81,7 +83,10 @@
      */
     @Override
     public void doLogout(String loginType, Object loginId, String tokenValue) {
-        RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+        String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
+        TenantHelper.dynamic(tenantId, () -> {
+            RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+        });
         log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue);
     }
 
@@ -90,7 +95,10 @@
      */
     @Override
     public void doKickout(String loginType, Object loginId, String tokenValue) {
-        RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+        String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
+        TenantHelper.dynamic(tenantId, () -> {
+            RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+        });
         log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue);
     }
 
@@ -99,7 +107,10 @@
      */
     @Override
     public void doReplaced(String loginType, Object loginId, String tokenValue) {
-        RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+        String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
+        TenantHelper.dynamic(tenantId, () -> {
+            RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+        });
         log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue);
     }
 
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java
index af6e7f5..c7ad917 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java
@@ -4,13 +4,14 @@
 import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Opt;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.lock.annotation.Lock4j;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import me.zhyd.oauth.model.AuthUser;
+import org.dromara.common.core.constant.CacheConstants;
 import org.dromara.common.core.constant.Constants;
-import org.dromara.common.core.constant.GlobalConstants;
 import org.dromara.common.core.constant.TenantConstants;
 import org.dromara.common.core.domain.dto.RoleDTO;
 import org.dromara.common.core.domain.model.LoginUser;
@@ -155,16 +156,13 @@
         loginUser.setUserType(user.getUserType());
         loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId()));
         loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId()));
-        TenantHelper.dynamic(user.getTenantId(), () -> {
-            SysDeptVo dept = null;
-            if (ObjectUtil.isNotNull(user.getDeptId())) {
-                dept = deptService.selectDeptById(user.getDeptId());
-            }
-            loginUser.setDeptName(ObjectUtil.isNull(dept) ? "" : dept.getDeptName());
-            loginUser.setDeptCategory(ObjectUtil.isNull(dept) ? "" : dept.getDeptCategory());
-            List<SysRoleVo> roles = roleService.selectRolesByUserId(user.getUserId());
-            loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class));
-        });
+        if (ObjectUtil.isNotNull(user.getDeptId())) {
+            Opt<SysDeptVo> deptOpt = Opt.of(user.getDeptId()).map(deptService::selectDeptById);
+            loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY));
+            loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY));
+        }
+        List<SysRoleVo> roles = roleService.selectRolesByUserId(user.getUserId());
+        loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class));
         return loginUser;
     }
 
@@ -186,7 +184,7 @@
      * 鐧诲綍鏍¢獙
      */
     public void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) {
-        String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username;
+        String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username;
         String loginFail = Constants.LOGIN_FAIL;
 
         // 鑾峰彇鐢ㄦ埛鐧诲綍閿欒娆℃暟锛岄粯璁や负0 (鍙嚜瀹氫箟闄愬埗绛栫暐 渚嬪: key + username + ip)
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java
index 38fdc44..b5a2497 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java
@@ -21,7 +21,6 @@
 import org.dromara.common.redis.utils.RedisUtils;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.common.tenant.helper.TenantHelper;
-import org.dromara.system.domain.SysClient;
 import org.dromara.system.domain.SysUser;
 import org.dromara.system.domain.vo.SysClientVo;
 import org.dromara.system.domain.vo.SysUserVo;
@@ -51,13 +50,12 @@
         String tenantId = loginBody.getTenantId();
         String email = loginBody.getEmail();
         String emailCode = loginBody.getEmailCode();
-
-        // 閫氳繃閭鏌ユ壘鐢ㄦ埛
-        SysUserVo user = loadUserByEmail(tenantId, email);
-
-        loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode));
-        // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
-        LoginUser loginUser = loginService.buildLoginUser(user);
+        LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
+            SysUserVo user = loadUserByEmail(email);
+            loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode));
+            // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
+            return loginService.buildLoginUser(user);
+        });
         loginUser.setClientKey(client.getClientKey());
         loginUser.setDeviceType(client.getDeviceType());
         SaLoginModel model = new SaLoginModel();
@@ -89,18 +87,16 @@
         return code.equals(emailCode);
     }
 
-    private SysUserVo loadUserByEmail(String tenantId, String email) {
-        return TenantHelper.dynamic(tenantId, () -> {
-            SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getEmail, email));
-            if (ObjectUtil.isNull(user)) {
-                log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", email);
-                throw new UserException("user.not.exists", email);
-            } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
-                log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", email);
-                throw new UserException("user.blocked", email);
-            }
-            return user;
-        });
+    private SysUserVo loadUserByEmail(String email) {
+        SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getEmail, email));
+        if (ObjectUtil.isNull(user)) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", email);
+            throw new UserException("user.not.exists", email);
+        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", email);
+            throw new UserException("user.blocked", email);
+        }
+        return user;
     }
 
 }
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java
index 5d3ebd7..f28024f 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java
@@ -62,11 +62,12 @@
         if (captchaEnabled) {
             validateCaptcha(tenantId, username, code, uuid);
         }
-
-        SysUserVo user = loadUserByUsername(tenantId, username);
-        loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword()));
-        // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser
-        LoginUser loginUser = loginService.buildLoginUser(user);
+        LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
+            SysUserVo user = loadUserByUsername(username);
+            loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword()));
+            // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser
+            return loginService.buildLoginUser(user);
+        });
         loginUser.setClientKey(client.getClientKey());
         loginUser.setDeviceType(client.getDeviceType());
         SaLoginModel model = new SaLoginModel();
@@ -107,18 +108,16 @@
         }
     }
 
-    private SysUserVo loadUserByUsername(String tenantId, String username) {
-        return TenantHelper.dynamic(tenantId, () -> {
-            SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, username));
-            if (ObjectUtil.isNull(user)) {
-                log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", username);
-                throw new UserException("user.not.exists", username);
-            } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
-                log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", username);
-                throw new UserException("user.blocked", username);
-            }
-            return user;
-        });
+    private SysUserVo loadUserByUsername(String username) {
+        SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, username));
+        if (ObjectUtil.isNull(user)) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", username);
+            throw new UserException("user.not.exists", username);
+        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", username);
+            throw new UserException("user.blocked", username);
+        }
+        return user;
     }
 
 }
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java
index f883632..89f8462 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java
@@ -21,7 +21,6 @@
 import org.dromara.common.redis.utils.RedisUtils;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.common.tenant.helper.TenantHelper;
-import org.dromara.system.domain.SysClient;
 import org.dromara.system.domain.SysUser;
 import org.dromara.system.domain.vo.SysClientVo;
 import org.dromara.system.domain.vo.SysUserVo;
@@ -51,13 +50,12 @@
         String tenantId = loginBody.getTenantId();
         String phonenumber = loginBody.getPhonenumber();
         String smsCode = loginBody.getSmsCode();
-
-        // 閫氳繃鎵嬫満鍙锋煡鎵剧敤鎴�
-        SysUserVo user = loadUserByPhonenumber(tenantId, phonenumber);
-
-        loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode));
-        // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
-        LoginUser loginUser = loginService.buildLoginUser(user);
+        LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
+            SysUserVo user = loadUserByPhonenumber(phonenumber);
+            loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode));
+            // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
+            return loginService.buildLoginUser(user);
+        });
         loginUser.setClientKey(client.getClientKey());
         loginUser.setDeviceType(client.getDeviceType());
         SaLoginModel model = new SaLoginModel();
@@ -89,18 +87,16 @@
         return code.equals(smsCode);
     }
 
-    private SysUserVo loadUserByPhonenumber(String tenantId, String phonenumber) {
-        return TenantHelper.dynamic(tenantId, () -> {
-            SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, phonenumber));
-            if (ObjectUtil.isNull(user)) {
-                log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", phonenumber);
-                throw new UserException("user.not.exists", phonenumber);
-            } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
-                log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", phonenumber);
-                throw new UserException("user.blocked", phonenumber);
-            }
-            return user;
-        });
+    private SysUserVo loadUserByPhonenumber(String phonenumber) {
+        SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, phonenumber));
+        if (ObjectUtil.isNull(user)) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", phonenumber);
+            throw new UserException("user.not.exists", phonenumber);
+        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", phonenumber);
+            throw new UserException("user.blocked", phonenumber);
+        }
+        return user;
     }
 
 }
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java
index 01db200..8463026 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java
@@ -92,11 +92,11 @@
         } else {
             social = list.get(0);
         }
-        // 鏌ユ壘鐢ㄦ埛
-        SysUserVo user = loadUser(social.getTenantId(), social.getUserId());
-
-        // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
-        LoginUser loginUser = loginService.buildLoginUser(user);
+        LoginUser loginUser = TenantHelper.dynamic(social.getTenantId(), () -> {
+            SysUserVo user = loadUser(social.getUserId());
+            // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
+            return loginService.buildLoginUser(user);
+        });
         loginUser.setClientKey(client.getClientKey());
         loginUser.setDeviceType(client.getDeviceType());
         SaLoginModel model = new SaLoginModel();
@@ -116,18 +116,16 @@
         return loginVo;
     }
 
-    private SysUserVo loadUser(String tenantId, Long userId) {
-        return TenantHelper.dynamic(tenantId, () -> {
-            SysUserVo user = userMapper.selectVoById(userId);
-            if (ObjectUtil.isNull(user)) {
-                log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", "");
-                throw new UserException("user.not.exists", "");
-            } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
-                log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", "");
-                throw new UserException("user.blocked", "");
-            }
-            return user;
-        });
+    private SysUserVo loadUser(Long userId) {
+        SysUserVo user = userMapper.selectVoById(userId);
+        if (ObjectUtil.isNull(user)) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", "");
+            throw new UserException("user.not.exists", "");
+        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", "");
+            throw new UserException("user.blocked", "");
+        }
+        return user;
     }
 
 }
diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml
index ea5cafa..5e20dae 100644
--- a/ruoyi-admin/src/main/resources/application-dev.yml
+++ b/ruoyi-admin/src/main/resources/application-dev.yml
@@ -5,6 +5,9 @@
   url: http://localhost:9090/admin
   instance:
     service-host-type: IP
+    metadata:
+      username: ${spring.boot.admin.client.username}
+      userpassword: ${spring.boot.admin.client.password}
   username: ruoyi
   password: 123456
 
diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml
index 2a4bc11..2823bba 100644
--- a/ruoyi-admin/src/main/resources/application-prod.yml
+++ b/ruoyi-admin/src/main/resources/application-prod.yml
@@ -8,6 +8,9 @@
   url: http://localhost:9090/admin
   instance:
     service-host-type: IP
+    metadata:
+      username: ${spring.boot.admin.client.username}
+      userpassword: ${spring.boot.admin.client.password}
   username: ruoyi
   password: 123456
 
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 27de286..5d94bef 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -121,9 +121,6 @@
     # swagger 鏂囨。閰嶇疆
     - /*/api-docs
     - /*/api-docs/**
-    # actuator 鐩戞帶閰嶇疆
-    - /actuator
-    - /actuator/**
 
 # 澶氱鎴烽厤缃�
 tenant:
@@ -259,10 +256,15 @@
     logfile:
       external-file: ./logs/sys-console.log
 
+--- # 榛樿/鎺ㄨ崘浣跨敤sse鎺ㄩ��
+sse:
+  enabled: true
+  path: /resource/sse
+
 --- # websocket
 websocket:
   # 濡傛灉鍏抽棴 闇�瑕佸拰鍓嶇寮�鍏充竴璧峰叧闂�
-  enabled: true
+  enabled: false
   # 璺緞
   path: /resource/websocket
   # 璁剧疆璁块棶婧愬湴鍧�
@@ -270,6 +272,10 @@
 
 --- #flowable閰嶇疆
 flowable:
+  # 寮�鍏� 鐢ㄤ簬鍚姩/鍋滅敤宸ヤ綔娴�
+  enabled: true
+  process.enabled: ${flowable.enabled}
+  eventregistry.enabled: ${flowable.enabled}
   async-executor-activate: false #鍏抽棴瀹氭椂浠诲姟JOB
   #  灏哾atabaseSchemaUpdate璁剧疆涓簍rue銆傚綋Flowable鍙戠幇搴撲笌鏁版嵁搴撹〃缁撴瀯涓嶄竴鑷存椂锛屼細鑷姩灏嗘暟鎹簱琛ㄧ粨鏋勫崌绾ц嚦鏂扮増鏈��
   database-schema-update: true
diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml
index 45493d3..2930fd0 100644
--- a/ruoyi-common/pom.xml
+++ b/ruoyi-common/pom.xml
@@ -33,6 +33,7 @@
         <module>ruoyi-common-encrypt</module>
         <module>ruoyi-common-tenant</module>
         <module>ruoyi-common-websocket</module>
+        <module>ruoyi-common-sse</module>
     </modules>
 
     <artifactId>ruoyi-common</artifactId>
diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml
index 5388d8c..455408d 100644
--- a/ruoyi-common/ruoyi-common-bom/pom.xml
+++ b/ruoyi-common/ruoyi-common-bom/pom.xml
@@ -14,7 +14,7 @@
     </description>
 
     <properties>
-        <revision>5.2.1</revision>
+        <revision>5.2.2</revision>
     </properties>
 
     <dependencyManagement>
@@ -172,6 +172,13 @@
                 <version>${revision}</version>
             </dependency>
 
+            <!-- SSE妯″潡 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-sse</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>
 
diff --git a/ruoyi-common/ruoyi-common-core/pom.xml b/ruoyi-common/ruoyi-common-core/pom.xml
index 5925c9b..ad37e90 100644
--- a/ruoyi-common/ruoyi-common-core/pom.xml
+++ b/ruoyi-common/ruoyi-common-core/pom.xml
@@ -94,11 +94,6 @@
             <artifactId>ip2region</artifactId>
         </dependency>
 
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>transmittable-thread-local</artifactId>
-        </dependency>
-
     </dependencies>
 
 </project>
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java
index 67bc8e4..ceb8370 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java
@@ -22,4 +22,9 @@
      */
     String SYS_DICT_KEY = "sys_dict:";
 
+    /**
+     * 鐧诲綍璐︽埛瀵嗙爜閿欒娆℃暟 redis key
+     */
+    String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
+
 }
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java
index ae9bc2e..5352b11 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java
@@ -28,11 +28,6 @@
     String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:";
 
     /**
-     * 鐧诲綍璐︽埛瀵嗙爜閿欒娆℃暟 redis key
-     */
-    String PWD_ERR_CNT_KEY = GLOBAL_REDIS_KEY + "pwd_err_cnt:";
-
-    /**
      * 涓夋柟璁よ瘉 redis key
      */
     String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:";
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java
index 6f3b0b9..76f6dd4 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java
@@ -68,6 +68,16 @@
     String DICT_NORMAL = "0";
 
     /**
+     * 閫氱敤瀛樺湪鏍囧織
+     */
+    String DEL_FLAG_NORMAL = "0";
+
+    /**
+     * 閫氱敤鍒犻櫎鏍囧織
+     */
+    String DEL_FLAG_REMOVED  = "2";
+
+    /**
      * 鏄惁涓虹郴缁熼粯璁わ紙鏄級
      */
     String YES = "Y";
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java
index 0f2878d..43aef28 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java
@@ -66,4 +66,20 @@
      * @return 鐢ㄦ埛ids
      */
     List<Long> selectUserIdsByRoleIds(List<Long> roleIds);
+
+    /**
+     * 閫氳繃瑙掕壊ID鏌ヨ鐢ㄦ埛
+     *
+     * @param roleIds 瑙掕壊ids
+     * @return 鐢ㄦ埛
+     */
+    List<UserDTO> selectUsersByRoleIds(List<Long> roleIds);
+
+    /**
+     * 閫氳繃閮ㄩ棬ID鏌ヨ鐢ㄦ埛
+     *
+     * @param deptIds 閮ㄩ棬ids
+     * @return 鐢ㄦ埛
+     */
+    List<UserDTO> selectUsersByDeptIds(List<Long> deptIds);
 }
diff --git a/ruoyi-common/ruoyi-common-excel/pom.xml b/ruoyi-common/ruoyi-common-excel/pom.xml
index dd4a5ee..14b9410 100644
--- a/ruoyi-common/ruoyi-common-excel/pom.xml
+++ b/ruoyi-common/ruoyi-common-excel/pom.xml
@@ -25,6 +25,11 @@
             <groupId>com.alibaba</groupId>
             <artifactId>easyexcel</artifactId>
         </dependency>
+        <dependency>
+            <artifactId>commons-compress</artifactId>
+            <groupId>org.apache.commons</groupId>
+            <version>1.26.2</version>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java
index 7c0a48b..7c7721c 100644
--- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java
@@ -107,7 +107,7 @@
                     }
 
                     if (!cellValue.equals(val)) {
-                        if ((i - repeatCell.getCurrent() > 1) && isMerge(list, i, field)) {
+                        if ((i - repeatCell.getCurrent() > 1)) {
                             cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum));
                         }
                         map.put(field, new RepeatCell(val, i));
@@ -115,6 +115,11 @@
                         if (i > repeatCell.getCurrent() && isMerge(list, i, field)) {
                             cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum));
                         }
+                    } else if (!isMerge(list, i, field)) {
+                        if ((i - repeatCell.getCurrent() > 1)) {
+                            cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum));
+                        }
+                        map.put(field, new RepeatCell(val, i));
                     }
                 }
             }
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java
index 1b51c27..0ea3007 100644
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java
+++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java
@@ -1,7 +1,7 @@
 package org.dromara.common.mail.config;
 
+import cn.hutool.extra.mail.MailAccount;
 import org.dromara.common.mail.config.properties.MailProperties;
-import org.dromara.common.mail.utils.MailAccount;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/GlobalMailAccount.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/GlobalMailAccount.java
deleted file mode 100644
index fdae869..0000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/GlobalMailAccount.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import cn.hutool.core.io.IORuntimeException;
-
-/**
- * 鍏ㄥ眬閭欢甯愭埛锛屼緷璧栦簬閭欢閰嶇疆鏂囦欢{@link MailAccount#MAIL_SETTING_PATHS}
- *
- * @author looly
- */
-public enum GlobalMailAccount {
-    INSTANCE;
-
-    private final MailAccount mailAccount;
-
-    /**
-     * 鏋勯��
-     */
-    GlobalMailAccount() {
-        mailAccount = createDefaultAccount();
-    }
-
-    /**
-     * 鑾峰緱閭欢甯愭埛
-     *
-     * @return 閭欢甯愭埛
-     */
-    public MailAccount getAccount() {
-        return this.mailAccount;
-    }
-
-    /**
-     * 鍒涘缓榛樿甯愭埛
-     *
-     * @return MailAccount
-     */
-    private MailAccount createDefaultAccount() {
-        for (String mailSettingPath : MailAccount.MAIL_SETTING_PATHS) {
-            try {
-                return new MailAccount(mailSettingPath);
-            } catch (IORuntimeException ignore) {
-                //ignore
-            }
-        }
-        return null;
-    }
-}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/InternalMailUtil.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/InternalMailUtil.java
deleted file mode 100644
index b755e73..0000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/InternalMailUtil.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import cn.hutool.core.util.ArrayUtil;
-import jakarta.mail.internet.AddressException;
-import jakarta.mail.internet.InternetAddress;
-import jakarta.mail.internet.MimeUtility;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * 閭欢鍐呴儴宸ュ叿绫�
- *
- * @author looly
- * @since 3.2.3
- */
-public class InternalMailUtil {
-
-    /**
-     * 灏嗗涓瓧绗︿覆閭欢鍦板潃杞负{@link InternetAddress}鍒楄〃<br>
-     * 鍗曚釜瀛楃涓插湴鍧�鍙互鏄涓湴鍧�鍚堝苟鐨勫瓧绗︿覆
-     *
-     * @param addrStrs 鍦板潃鏁扮粍
-     * @param charset  缂栫爜锛堜富瑕佺敤浜庝腑鏂囩敤鎴峰悕鐨勭紪鐮侊級
-     * @return 鍦板潃鏁扮粍
-     * @since 4.0.3
-     */
-    public static InternetAddress[] parseAddressFromStrs(String[] addrStrs, Charset charset) {
-        final List<InternetAddress> resultList = new ArrayList<>(addrStrs.length);
-        InternetAddress[] addrs;
-        for (String addrStr : addrStrs) {
-            addrs = parseAddress(addrStr, charset);
-            if (ArrayUtil.isNotEmpty(addrs)) {
-                Collections.addAll(resultList, addrs);
-            }
-        }
-        return resultList.toArray(new InternetAddress[0]);
-    }
-
-    /**
-     * 瑙f瀽绗竴涓湴鍧�
-     *
-     * @param address 鍦板潃瀛楃涓�
-     * @param charset 缂栫爜锛寋@code null}琛ㄧず浣跨敤绯荤粺灞炴�у畾涔夌殑缂栫爜鎴栫郴缁熺紪鐮�
-     * @return 鍦板潃鍒楄〃
-     */
-    public static InternetAddress parseFirstAddress(String address, Charset charset) {
-        final InternetAddress[] internetAddresses = parseAddress(address, charset);
-        if (ArrayUtil.isEmpty(internetAddresses)) {
-            try {
-                return new InternetAddress(address);
-            } catch (AddressException e) {
-                throw new MailException(e);
-            }
-        }
-        return internetAddresses[0];
-    }
-
-    /**
-     * 灏嗕竴涓湴鍧�瀛楃涓茶В鏋愪负澶氫釜鍦板潃<br>
-     * 鍦板潃闂翠娇鐢�" "銆�","銆�";"鍒嗛殧
-     *
-     * @param address 鍦板潃瀛楃涓�
-     * @param charset 缂栫爜锛寋@code null}琛ㄧず浣跨敤绯荤粺灞炴�у畾涔夌殑缂栫爜鎴栫郴缁熺紪鐮�
-     * @return 鍦板潃鍒楄〃
-     */
-    public static InternetAddress[] parseAddress(String address, Charset charset) {
-        InternetAddress[] addresses;
-        try {
-            addresses = InternetAddress.parse(address);
-        } catch (AddressException e) {
-            throw new MailException(e);
-        }
-        //缂栫爜鐢ㄦ埛鍚�
-        if (ArrayUtil.isNotEmpty(addresses)) {
-            final String charsetStr = null == charset ? null : charset.name();
-            for (InternetAddress internetAddress : addresses) {
-                try {
-                    internetAddress.setPersonal(internetAddress.getPersonal(), charsetStr);
-                } catch (UnsupportedEncodingException e) {
-                    throw new MailException(e);
-                }
-            }
-        }
-
-        return addresses;
-    }
-
-    /**
-     * 缂栫爜涓枃瀛楃<br>
-     * 缂栫爜澶辫触杩斿洖鍘熷瓧绗︿覆
-     *
-     * @param text    琚紪鐮佺殑鏂囨湰
-     * @param charset 缂栫爜
-     * @return 缂栫爜鍚庣殑缁撴灉
-     */
-    public static String encodeText(String text, Charset charset) {
-        try {
-            return MimeUtility.encodeText(text, charset.name(), null);
-        } catch (UnsupportedEncodingException e) {
-            // ignore
-        }
-        return text;
-    }
-}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/Mail.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/Mail.java
deleted file mode 100644
index 6ca4b69..0000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/Mail.java
+++ /dev/null
@@ -1,483 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import cn.hutool.core.builder.Builder;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.io.IORuntimeException;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import jakarta.activation.DataHandler;
-import jakarta.activation.DataSource;
-import jakarta.activation.FileDataSource;
-import jakarta.activation.FileTypeMap;
-import jakarta.mail.*;
-import jakarta.mail.internet.MimeBodyPart;
-import jakarta.mail.internet.MimeMessage;
-import jakarta.mail.internet.MimeMultipart;
-import jakarta.mail.internet.MimeUtility;
-import jakarta.mail.util.ByteArrayDataSource;
-
-import java.io.*;
-import java.nio.charset.Charset;
-import java.util.Date;
-
-/**
- * 閭欢鍙戦�佸鎴风
- *
- * @author looly
- * @since 3.2.0
- */
-public class Mail implements Builder<MimeMessage> {
-    @Serial
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 閭甯愭埛淇℃伅浠ュ強涓�浜涘鎴风閰嶇疆淇℃伅
-     */
-    private final MailAccount mailAccount;
-    /**
-     * 鏀朵欢浜哄垪琛�
-     */
-    private String[] tos;
-    /**
-     * 鎶勯�佷汉鍒楄〃锛坈arbon copy锛�
-     */
-    private String[] ccs;
-    /**
-     * 瀵嗛�佷汉鍒楄〃锛坆lind carbon copy锛�
-     */
-    private String[] bccs;
-    /**
-     * 鍥炲鍦板潃(reply-to)
-     */
-    private String[] reply;
-    /**
-     * 鏍囬
-     */
-    private String title;
-    /**
-     * 鍐呭
-     */
-    private String content;
-    /**
-     * 鏄惁涓篐TML
-     */
-    private boolean isHtml;
-    /**
-     * 姝f枃銆侀檮浠跺拰鍥剧墖鐨勬贩鍚堥儴鍒�
-     */
-    private final Multipart multipart = new MimeMultipart();
-    /**
-     * 鏄惁浣跨敤鍏ㄥ眬浼氳瘽锛岄粯璁や负false
-     */
-    private boolean useGlobalSession = false;
-
-    /**
-     * debug杈撳嚭浣嶇疆锛屽彲浠ヨ嚜瀹氫箟debug鏃ュ織
-     */
-    private PrintStream debugOutput;
-
-    /**
-     * 鍒涘缓閭欢瀹㈡埛绔�
-     *
-     * @param mailAccount 閭欢甯愬彿
-     * @return Mail
-     */
-    public static Mail create(MailAccount mailAccount) {
-        return new Mail(mailAccount);
-    }
-
-    /**
-     * 鍒涘缓閭欢瀹㈡埛绔紝浣跨敤鍏ㄥ眬閭欢甯愭埛
-     *
-     * @return Mail
-     */
-    public static Mail create() {
-        return new Mail();
-    }
-
-    // --------------------------------------------------------------- Constructor start
-
-    /**
-     * 鏋勯�狅紝浣跨敤鍏ㄥ眬閭欢甯愭埛
-     */
-    public Mail() {
-        this(GlobalMailAccount.INSTANCE.getAccount());
-    }
-
-    /**
-     * 鏋勯��
-     *
-     * @param mailAccount 閭欢甯愭埛锛屽鏋滀负null浣跨敤榛樿閰嶇疆鏂囦欢鐨勫叏灞�閭欢閰嶇疆
-     */
-    public Mail(MailAccount mailAccount) {
-        mailAccount = (null != mailAccount) ? mailAccount : GlobalMailAccount.INSTANCE.getAccount();
-        this.mailAccount = mailAccount.defaultIfEmpty();
-    }
-    // --------------------------------------------------------------- Constructor end
-
-    // --------------------------------------------------------------- Getters and Setters start
-
-    /**
-     * 璁剧疆鏀朵欢浜�
-     *
-     * @param tos 鏀朵欢浜哄垪琛�
-     * @return this
-     * @see #setTos(String...)
-     */
-    public Mail to(String... tos) {
-        return setTos(tos);
-    }
-
-    /**
-     * 璁剧疆澶氫釜鏀朵欢浜�
-     *
-     * @param tos 鏀朵欢浜哄垪琛�
-     * @return this
-     */
-    public Mail setTos(String... tos) {
-        this.tos = tos;
-        return this;
-    }
-
-    /**
-     * 璁剧疆澶氫釜鎶勯�佷汉锛坈arbon copy锛�
-     *
-     * @param ccs 鎶勯�佷汉鍒楄〃
-     * @return this
-     * @since 4.0.3
-     */
-    public Mail setCcs(String... ccs) {
-        this.ccs = ccs;
-        return this;
-    }
-
-    /**
-     * 璁剧疆澶氫釜瀵嗛�佷汉锛坆lind carbon copy锛�
-     *
-     * @param bccs 瀵嗛�佷汉鍒楄〃
-     * @return this
-     * @since 4.0.3
-     */
-    public Mail setBccs(String... bccs) {
-        this.bccs = bccs;
-        return this;
-    }
-
-    /**
-     * 璁剧疆澶氫釜鍥炲鍦板潃(reply-to)
-     *
-     * @param reply 鍥炲鍦板潃(reply-to)鍒楄〃
-     * @return this
-     * @since 4.6.0
-     */
-    public Mail setReply(String... reply) {
-        this.reply = reply;
-        return this;
-    }
-
-    /**
-     * 璁剧疆鏍囬
-     *
-     * @param title 鏍囬
-     * @return this
-     */
-    public Mail setTitle(String title) {
-        this.title = title;
-        return this;
-    }
-
-    /**
-     * 璁剧疆姝f枃<br>
-     * 姝f枃鍙互鏄櫘閫氭枃鏈篃鍙互鏄疕TML锛堥粯璁ゆ櫘閫氭枃鏈級锛屽彲浠ラ�氳繃璋冪敤{@link #setHtml(boolean)} 璁剧疆鏄惁涓篐TML
-     *
-     * @param content 姝f枃
-     * @return this
-     */
-    public Mail setContent(String content) {
-        this.content = content;
-        return this;
-    }
-
-    /**
-     * 璁剧疆鏄惁鏄疕TML
-     *
-     * @param isHtml 鏄惁涓篐TML
-     * @return this
-     */
-    public Mail setHtml(boolean isHtml) {
-        this.isHtml = isHtml;
-        return this;
-    }
-
-    /**
-     * 璁剧疆姝f枃
-     *
-     * @param content 姝f枃鍐呭
-     * @param isHtml  鏄惁涓篐TML
-     * @return this
-     */
-    public Mail setContent(String content, boolean isHtml) {
-        setContent(content);
-        return setHtml(isHtml);
-    }
-
-    /**
-     * 璁剧疆鏂囦欢绫诲瀷闄勪欢锛屾枃浠跺彲浠ユ槸鍥剧墖鏂囦欢锛屾鏃惰嚜鍔ㄨ缃甤id锛堟鏂囦腑寮曠敤鍥剧墖锛夛紝榛樿cid涓烘枃浠跺悕
-     *
-     * @param files 闄勪欢鏂囦欢鍒楄〃
-     * @return this
-     */
-    public Mail setFiles(File... files) {
-        if (ArrayUtil.isEmpty(files)) {
-            return this;
-        }
-
-        final DataSource[] attachments = new DataSource[files.length];
-        for (int i = 0; i < files.length; i++) {
-            attachments[i] = new FileDataSource(files[i]);
-        }
-        return setAttachments(attachments);
-    }
-
-    /**
-     * 澧炲姞闄勪欢鎴栧浘鐗囷紝闄勪欢浣跨敤{@link DataSource} 褰㈠紡琛ㄧず锛屽彲浠ヤ娇鐢▄@link FileDataSource}鍖呰鏂囦欢琛ㄧず鏂囦欢闄勪欢
-     *
-     * @param attachments 闄勪欢鍒楄〃
-     * @return this
-     * @since 4.0.9
-     */
-    public Mail setAttachments(DataSource... attachments) {
-        if (ArrayUtil.isNotEmpty(attachments)) {
-            final Charset charset = this.mailAccount.getCharset();
-            MimeBodyPart bodyPart;
-            String nameEncoded;
-            try {
-                for (DataSource attachment : attachments) {
-                    bodyPart = new MimeBodyPart();
-                    bodyPart.setDataHandler(new DataHandler(attachment));
-                    nameEncoded = attachment.getName();
-                    if (this.mailAccount.isEncodefilename()) {
-                        nameEncoded = InternalMailUtil.encodeText(nameEncoded, charset);
-                    }
-                    // 鏅�氶檮浠舵枃浠跺悕
-                    bodyPart.setFileName(nameEncoded);
-                    if (StrUtil.startWith(attachment.getContentType(), "image/")) {
-                        // 鍥剧墖闄勪欢锛岀敤浜庢鏂囦腑寮曠敤鍥剧墖
-                        bodyPart.setContentID(nameEncoded);
-                    }
-                    this.multipart.addBodyPart(bodyPart);
-                }
-            } catch (MessagingException e) {
-                throw new MailException(e);
-            }
-        }
-        return this;
-    }
-
-    /**
-     * 澧炲姞鍥剧墖锛屽浘鐗囩殑閿搴斿埌閭欢妯℃澘涓殑鍗犱綅瀛楃涓诧紝鍥剧墖绫诲瀷榛樿涓�"image/jpeg"
-     *
-     * @param cid         鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:${cid}
-     * @param imageStream 鍥剧墖鏂囦欢
-     * @return this
-     * @since 4.6.3
-     */
-    public Mail addImage(String cid, InputStream imageStream) {
-        return addImage(cid, imageStream, null);
-    }
-
-    /**
-     * 澧炲姞鍥剧墖锛屽浘鐗囩殑閿搴斿埌閭欢妯℃澘涓殑鍗犱綅瀛楃涓�
-     *
-     * @param cid         鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:${cid}
-     * @param imageStream 鍥剧墖娴侊紝涓嶅叧闂�
-     * @param contentType 鍥剧墖绫诲瀷锛宯ull璧嬪�奸粯璁ょ殑"image/jpeg"
-     * @return this
-     * @since 4.6.3
-     */
-    public Mail addImage(String cid, InputStream imageStream, String contentType) {
-        ByteArrayDataSource imgSource;
-        try {
-            imgSource = new ByteArrayDataSource(imageStream, ObjectUtil.defaultIfNull(contentType, "image/jpeg"));
-        } catch (IOException e) {
-            throw new IORuntimeException(e);
-        }
-        imgSource.setName(cid);
-        return setAttachments(imgSource);
-    }
-
-    /**
-     * 澧炲姞鍥剧墖锛屽浘鐗囩殑閿搴斿埌閭欢妯℃澘涓殑鍗犱綅瀛楃涓�
-     *
-     * @param cid       鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:${cid}
-     * @param imageFile 鍥剧墖鏂囦欢
-     * @return this
-     * @since 4.6.3
-     */
-    public Mail addImage(String cid, File imageFile) {
-        InputStream in = null;
-        try {
-            in = FileUtil.getInputStream(imageFile);
-            return addImage(cid, in, FileTypeMap.getDefaultFileTypeMap().getContentType(imageFile));
-        } finally {
-            IoUtil.close(in);
-        }
-    }
-
-    /**
-     * 璁剧疆瀛楃闆嗙紪鐮�
-     *
-     * @param charset 瀛楃闆嗙紪鐮�
-     * @return this
-     * @see MailAccount#setCharset(Charset)
-     */
-    public Mail setCharset(Charset charset) {
-        this.mailAccount.setCharset(charset);
-        return this;
-    }
-
-    /**
-     * 璁剧疆鏄惁浣跨敤鍏ㄥ眬浼氳瘽锛岄粯璁や负true
-     *
-     * @param isUseGlobalSession 鏄惁浣跨敤鍏ㄥ眬浼氳瘽锛岄粯璁や负true
-     * @return this
-     * @since 4.0.2
-     */
-    public Mail setUseGlobalSession(boolean isUseGlobalSession) {
-        this.useGlobalSession = isUseGlobalSession;
-        return this;
-    }
-
-    /**
-     * 璁剧疆debug杈撳嚭浣嶇疆锛屽彲浠ヨ嚜瀹氫箟debug鏃ュ織
-     *
-     * @param debugOutput debug杈撳嚭浣嶇疆
-     * @return this
-     * @since 5.5.6
-     */
-    public Mail setDebugOutput(PrintStream debugOutput) {
-        this.debugOutput = debugOutput;
-        return this;
-    }
-    // --------------------------------------------------------------- Getters and Setters end
-
-    @Override
-    public MimeMessage build() {
-        try {
-            return buildMsg();
-        } catch (MessagingException e) {
-            throw new MailException(e);
-        }
-    }
-
-    /**
-     * 鍙戦��
-     *
-     * @return message-id
-     * @throws MailException 閭欢鍙戦�佸紓甯�
-     */
-    public String send() throws MailException {
-        try {
-            return doSend();
-        } catch (MessagingException e) {
-            if (e instanceof SendFailedException) {
-                // 褰撳湴鍧�鏃犳晥鏃讹紝鏄剧ず鏇村姞璇︾粏鐨勬棤鏁堝湴鍧�淇℃伅
-                final Address[] invalidAddresses = ((SendFailedException) e).getInvalidAddresses();
-                final String msg = StrUtil.format("Invalid Addresses: {}", ArrayUtil.toString(invalidAddresses));
-                throw new MailException(msg, e);
-            }
-            throw new MailException(e);
-        }
-    }
-
-    // --------------------------------------------------------------- Private method start
-
-    /**
-     * 鎵ц鍙戦��
-     *
-     * @return message-id
-     * @throws MessagingException 鍙戦�佸紓甯�
-     */
-    private String doSend() throws MessagingException {
-        final MimeMessage mimeMessage = buildMsg();
-        Transport.send(mimeMessage);
-        return mimeMessage.getMessageID();
-    }
-
-    /**
-     * 鏋勫缓娑堟伅
-     *
-     * @return {@link MimeMessage}娑堟伅
-     * @throws MessagingException 娑堟伅寮傚父
-     */
-    private MimeMessage buildMsg() throws MessagingException {
-        final Charset charset = this.mailAccount.getCharset();
-        final MimeMessage msg = new MimeMessage(getSession());
-        // 鍙戜欢浜�
-        final String from = this.mailAccount.getFrom();
-        if (StrUtil.isEmpty(from)) {
-            // 鐢ㄦ埛鏈彁渚涘彂閫佹柟锛屽垯浠嶴ession涓嚜鍔ㄨ幏鍙�
-            msg.setFrom();
-        } else {
-            msg.setFrom(InternalMailUtil.parseFirstAddress(from, charset));
-        }
-        // 鏍囬
-        msg.setSubject(this.title, (null == charset) ? null : charset.name());
-        // 鍙戦�佹椂闂�
-        msg.setSentDate(new Date());
-        // 鍐呭鍜岄檮浠�
-        msg.setContent(buildContent(charset));
-        // 鏀朵欢浜�
-        msg.setRecipients(MimeMessage.RecipientType.TO, InternalMailUtil.parseAddressFromStrs(this.tos, charset));
-        // 鎶勯�佷汉
-        if (ArrayUtil.isNotEmpty(this.ccs)) {
-            msg.setRecipients(MimeMessage.RecipientType.CC, InternalMailUtil.parseAddressFromStrs(this.ccs, charset));
-        }
-        // 瀵嗛�佷汉
-        if (ArrayUtil.isNotEmpty(this.bccs)) {
-            msg.setRecipients(MimeMessage.RecipientType.BCC, InternalMailUtil.parseAddressFromStrs(this.bccs, charset));
-        }
-        // 鍥炲鍦板潃(reply-to)
-        if (ArrayUtil.isNotEmpty(this.reply)) {
-            msg.setReplyTo(InternalMailUtil.parseAddressFromStrs(this.reply, charset));
-        }
-
-        return msg;
-    }
-
-    /**
-     * 鏋勫缓閭欢淇℃伅涓讳綋
-     *
-     * @param charset 缂栫爜锛寋@code null}鍒欎娇鐢▄@link MimeUtility#getDefaultJavaCharset()}
-     * @return 閭欢淇℃伅涓讳綋
-     * @throws MessagingException 娑堟伅寮傚父
-     */
-    private Multipart buildContent(Charset charset) throws MessagingException {
-        final String charsetStr = null != charset ? charset.name() : MimeUtility.getDefaultJavaCharset();
-        // 姝f枃
-        final MimeBodyPart body = new MimeBodyPart();
-        body.setContent(content, StrUtil.format("text/{}; charset={}", isHtml ? "html" : "plain", charsetStr));
-        this.multipart.addBodyPart(body);
-
-        return this.multipart;
-    }
-
-    /**
-     * 鑾峰彇榛樿閭欢浼氳瘽<br>
-     * 濡傛灉涓哄叏灞�鍗曚緥鐨勪細璇濓紝鍒欏叏灞�鍙厑璁镐竴涓偖浠跺笎鍙凤紝鍚﹀垯姣忔鍙戦�侀偖浠朵細鏂板缓涓�涓柊鐨勪細璇�
-     *
-     * @return 閭欢浼氳瘽 {@link Session}
-     */
-    private Session getSession() {
-        final Session session = MailUtils.getSession(this.mailAccount, this.useGlobalSession);
-
-        if (null != this.debugOutput) {
-            session.setDebugOut(debugOutput);
-        }
-
-        return session;
-    }
-    // --------------------------------------------------------------- Private method end
-}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailAccount.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailAccount.java
deleted file mode 100644
index 2a732a1..0000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailAccount.java
+++ /dev/null
@@ -1,659 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.setting.Setting;
-
-import java.io.Serial;
-import java.io.Serializable;
-import java.nio.charset.Charset;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-
-/**
- * 閭欢璐︽埛瀵硅薄
- *
- * @author Luxiaolei
- */
-public class MailAccount implements Serializable {
-    @Serial
-    private static final long serialVersionUID = -6937313421815719204L;
-
-    private static final String MAIL_PROTOCOL = "mail.transport.protocol";
-    private static final String SMTP_HOST = "mail.smtp.host";
-    private static final String SMTP_PORT = "mail.smtp.port";
-    private static final String SMTP_AUTH = "mail.smtp.auth";
-    private static final String SMTP_TIMEOUT = "mail.smtp.timeout";
-    private static final String SMTP_CONNECTION_TIMEOUT = "mail.smtp.connectiontimeout";
-    private static final String SMTP_WRITE_TIMEOUT = "mail.smtp.writetimeout";
-
-    // SSL
-    private static final String STARTTLS_ENABLE = "mail.smtp.starttls.enable";
-    private static final String SSL_ENABLE = "mail.smtp.ssl.enable";
-    private static final String SSL_PROTOCOLS = "mail.smtp.ssl.protocols";
-    private static final String SOCKET_FACTORY = "mail.smtp.socketFactory.class";
-    private static final String SOCKET_FACTORY_FALLBACK = "mail.smtp.socketFactory.fallback";
-    private static final String SOCKET_FACTORY_PORT = "smtp.socketFactory.port";
-
-    // System Properties
-    private static final String SPLIT_LONG_PARAMS = "mail.mime.splitlongparameters";
-    //private static final String ENCODE_FILE_NAME = "mail.mime.encodefilename";
-    //private static final String CHARSET = "mail.mime.charset";
-
-    // 鍏朵粬
-    private static final String MAIL_DEBUG = "mail.debug";
-
-    public static final String[] MAIL_SETTING_PATHS = new String[]{"config/mail.setting", "config/mailAccount.setting", "mail.setting"};
-
-    /**
-     * SMTP鏈嶅姟鍣ㄥ煙鍚�
-     */
-    private String host;
-    /**
-     * SMTP鏈嶅姟绔彛
-     */
-    private Integer port;
-    /**
-     * 鏄惁闇�瑕佺敤鎴峰悕瀵嗙爜楠岃瘉
-     */
-    private Boolean auth;
-    /**
-     * 鐢ㄦ埛鍚�
-     */
-    private String user;
-    /**
-     * 瀵嗙爜
-     */
-    private String pass;
-    /**
-     * 鍙戦�佹柟锛岄伒寰猂FC-822鏍囧噯
-     */
-    private String from;
-
-    /**
-     * 鏄惁鎵撳紑璋冭瘯妯″紡锛岃皟璇曟ā寮忎細鏄剧ず涓庨偖浠舵湇鍔″櫒閫氫俊杩囩▼锛岄粯璁や笉寮�鍚�
-     */
-    private boolean debug;
-    /**
-     * 缂栫爜鐢ㄤ簬缂栫爜閭欢姝f枃鍜屽彂閫佷汉銆佹敹浠朵汉绛変腑鏂�
-     */
-    private Charset charset = CharsetUtil.CHARSET_UTF_8;
-    /**
-     * 瀵逛簬瓒呴暱鍙傛暟鏄惁鍒囧垎涓哄浠斤紝榛樿涓篺alse锛堝浗鍐呴偖绠遍檮浠朵笉鏀寔鍒囧垎鐨勯檮浠跺悕锛�
-     */
-    private boolean splitlongparameters = false;
-    /**
-     * 瀵逛簬鏂囦欢鍚嶆槸鍚︿娇鐢▄@link #charset}缂栫爜锛岄粯璁や负 {@code true}
-     */
-    private boolean encodefilename = true;
-
-    /**
-     * 浣跨敤 STARTTLS瀹夊叏杩炴帴锛孲TARTTLS鏄绾枃鏈�氫俊鍗忚鐨勬墿灞曘�傚畠灏嗙函鏂囨湰杩炴帴鍗囩骇涓哄姞瀵嗚繛鎺ワ紙TLS鎴朣SL锛夛紝 鑰屼笉鏄娇鐢ㄤ竴涓崟鐙殑鍔犲瘑閫氫俊绔彛銆�
-     */
-    private boolean starttlsEnable = false;
-    /**
-     * 浣跨敤 SSL瀹夊叏杩炴帴
-     */
-    private Boolean sslEnable;
-
-    /**
-     * SSL鍗忚锛屽涓崗璁敤绌烘牸鍒嗛殧
-     */
-    private String sslProtocols;
-
-    /**
-     * 鎸囧畾瀹炵幇javax.net.SocketFactory鎺ュ彛鐨勭被鐨勫悕绉�,杩欎釜绫诲皢琚敤浜庡垱寤篠MTP鐨勫鎺ュ瓧
-     */
-    private String socketFactoryClass = "javax.net.ssl.SSLSocketFactory";
-    /**
-     * 濡傛灉璁剧疆涓簍rue,鏈兘鍒涘缓涓�涓鎺ュ瓧浣跨敤鎸囧畾鐨勫鎺ュ瓧宸ュ巶绫诲皢瀵艰嚧浣跨敤java.net.Socket鍒涘缓鐨勫鎺ュ瓧绫�, 榛樿鍊间负true
-     */
-    private boolean socketFactoryFallback;
-    /**
-     * 鎸囧畾鐨勭鍙h繛鎺ュ埌鍦ㄤ娇鐢ㄦ寚瀹氱殑濂楁帴瀛楀伐鍘傘�傚鏋滄病鏈夎缃�,灏嗕娇鐢ㄩ粯璁ょ鍙�
-     */
-    private int socketFactoryPort = 465;
-
-    /**
-     * SMTP瓒呮椂鏃堕暱锛屽崟浣嶆绉掞紝缂虹渷鍊间笉瓒呮椂
-     */
-    private long timeout;
-    /**
-     * Socket杩炴帴瓒呮椂鍊硷紝鍗曚綅姣锛岀己鐪佸�间笉瓒呮椂
-     */
-    private long connectionTimeout;
-    /**
-     * Socket鍐欏嚭瓒呮椂鍊硷紝鍗曚綅姣锛岀己鐪佸�间笉瓒呮椂
-     */
-    private long writeTimeout;
-
-    /**
-     * 鑷畾涔夌殑鍏朵粬灞炴�э紝姝よ嚜瀹氫箟灞炴�т細瑕嗙洊榛樿灞炴��
-     */
-    private final Map<String, Object> customProperty = new HashMap<>();
-
-    // -------------------------------------------------------------- Constructor start
-
-    /**
-     * 鏋勯��,鎵�鏈夊弬鏁伴渶鑷瀹氫箟鎴栦繚鎸侀粯璁ゅ��
-     */
-    public MailAccount() {
-    }
-
-    /**
-     * 鏋勯��
-     *
-     * @param settingPath 閰嶇疆鏂囦欢璺緞
-     */
-    public MailAccount(String settingPath) {
-        this(new Setting(settingPath));
-    }
-
-    /**
-     * 鏋勯��
-     *
-     * @param setting 閰嶇疆鏂囦欢
-     */
-    public MailAccount(Setting setting) {
-        setting.toBean(this);
-    }
-
-    // -------------------------------------------------------------- Constructor end
-
-    /**
-     * 鑾峰緱SMTP鏈嶅姟鍣ㄥ煙鍚�
-     *
-     * @return SMTP鏈嶅姟鍣ㄥ煙鍚�
-     */
-    public String getHost() {
-        return host;
-    }
-
-    /**
-     * 璁剧疆SMTP鏈嶅姟鍣ㄥ煙鍚�
-     *
-     * @param host SMTP鏈嶅姟鍣ㄥ煙鍚�
-     * @return this
-     */
-    public MailAccount setHost(String host) {
-        this.host = host;
-        return this;
-    }
-
-    /**
-     * 鑾峰緱SMTP鏈嶅姟绔彛
-     *
-     * @return SMTP鏈嶅姟绔彛
-     */
-    public Integer getPort() {
-        return port;
-    }
-
-    /**
-     * 璁剧疆SMTP鏈嶅姟绔彛
-     *
-     * @param port SMTP鏈嶅姟绔彛
-     * @return this
-     */
-    public MailAccount setPort(Integer port) {
-        this.port = port;
-        return this;
-    }
-
-    /**
-     * 鏄惁闇�瑕佺敤鎴峰悕瀵嗙爜楠岃瘉
-     *
-     * @return 鏄惁闇�瑕佺敤鎴峰悕瀵嗙爜楠岃瘉
-     */
-    public Boolean isAuth() {
-        return auth;
-    }
-
-    /**
-     * 璁剧疆鏄惁闇�瑕佺敤鎴峰悕瀵嗙爜楠岃瘉
-     *
-     * @param isAuth 鏄惁闇�瑕佺敤鎴峰悕瀵嗙爜楠岃瘉
-     * @return this
-     */
-    public MailAccount setAuth(boolean isAuth) {
-        this.auth = isAuth;
-        return this;
-    }
-
-    /**
-     * 鑾峰彇鐢ㄦ埛鍚�
-     *
-     * @return 鐢ㄦ埛鍚�
-     */
-    public String getUser() {
-        return user;
-    }
-
-    /**
-     * 璁剧疆鐢ㄦ埛鍚�
-     *
-     * @param user 鐢ㄦ埛鍚�
-     * @return this
-     */
-    public MailAccount setUser(String user) {
-        this.user = user;
-        return this;
-    }
-
-    /**
-     * 鑾峰彇瀵嗙爜
-     *
-     * @return 瀵嗙爜
-     */
-    public String getPass() {
-        return pass;
-    }
-
-    /**
-     * 璁剧疆瀵嗙爜
-     *
-     * @param pass 瀵嗙爜
-     * @return this
-     */
-    public MailAccount setPass(String pass) {
-        this.pass = pass;
-        return this;
-    }
-
-    /**
-     * 鑾峰彇鍙戦�佹柟锛岄伒寰猂FC-822鏍囧噯
-     *
-     * @return 鍙戦�佹柟锛岄伒寰猂FC-822鏍囧噯
-     */
-    public String getFrom() {
-        return from;
-    }
-
-    /**
-     * 璁剧疆鍙戦�佹柟锛岄伒寰猂FC-822鏍囧噯<br>
-     * 鍙戜欢浜哄彲浠ユ槸浠ヤ笅褰㈠紡锛�
-     *
-     * <pre>
-     * 1. user@xxx.xx
-     * 2.  name &lt;user@xxx.xx&gt;
-     * </pre>
-     *
-     * @param from 鍙戦�佹柟锛岄伒寰猂FC-822鏍囧噯
-     * @return this
-     */
-    public MailAccount setFrom(String from) {
-        this.from = from;
-        return this;
-    }
-
-    /**
-     * 鏄惁鎵撳紑璋冭瘯妯″紡锛岃皟璇曟ā寮忎細鏄剧ず涓庨偖浠舵湇鍔″櫒閫氫俊杩囩▼锛岄粯璁や笉寮�鍚�
-     *
-     * @return 鏄惁鎵撳紑璋冭瘯妯″紡锛岃皟璇曟ā寮忎細鏄剧ず涓庨偖浠舵湇鍔″櫒閫氫俊杩囩▼锛岄粯璁や笉寮�鍚�
-     * @since 4.0.2
-     */
-    public boolean isDebug() {
-        return debug;
-    }
-
-    /**
-     * 璁剧疆鏄惁鎵撳紑璋冭瘯妯″紡锛岃皟璇曟ā寮忎細鏄剧ず涓庨偖浠舵湇鍔″櫒閫氫俊杩囩▼锛岄粯璁や笉寮�鍚�
-     *
-     * @param debug 鏄惁鎵撳紑璋冭瘯妯″紡锛岃皟璇曟ā寮忎細鏄剧ず涓庨偖浠舵湇鍔″櫒閫氫俊杩囩▼锛岄粯璁や笉寮�鍚�
-     * @return this
-     * @since 4.0.2
-     */
-    public MailAccount setDebug(boolean debug) {
-        this.debug = debug;
-        return this;
-    }
-
-    /**
-     * 鑾峰彇瀛楃闆嗙紪鐮�
-     *
-     * @return 缂栫爜锛屽彲鑳戒负{@code null}
-     */
-    public Charset getCharset() {
-        return charset;
-    }
-
-    /**
-     * 璁剧疆瀛楃闆嗙紪鐮侊紝姝ら�夐」涓嶄細淇敼鍏ㄥ眬閰嶇疆锛岃嫢淇敼鍏ㄥ眬閰嶇疆锛岃璁剧疆姝ら」涓簕@code null}骞惰缃細
-     * <pre>
-     * 	System.setProperty("mail.mime.charset", charset);
-     * </pre>
-     *
-     * @param charset 瀛楃闆嗙紪鐮侊紝{@code null} 鍒欒〃绀轰娇鐢ㄥ叏灞�璁剧疆鐨勯粯璁ょ紪鐮侊紝鍏ㄥ眬缂栫爜涓簃ail.mime.charset绯荤粺灞炴��
-     * @return this
-     */
-    public MailAccount setCharset(Charset charset) {
-        this.charset = charset;
-        return this;
-    }
-
-    /**
-     * 瀵逛簬瓒呴暱鍙傛暟鏄惁鍒囧垎涓哄浠斤紝榛樿涓篺alse锛堝浗鍐呴偖绠遍檮浠朵笉鏀寔鍒囧垎鐨勯檮浠跺悕锛�
-     *
-     * @return 瀵逛簬瓒呴暱鍙傛暟鏄惁鍒囧垎涓哄浠�
-     */
-    public boolean isSplitlongparameters() {
-        return splitlongparameters;
-    }
-
-    /**
-     * 璁剧疆瀵逛簬瓒呴暱鍙傛暟鏄惁鍒囧垎涓哄浠斤紝榛樿涓篺alse锛堝浗鍐呴偖绠遍檮浠朵笉鏀寔鍒囧垎鐨勯檮浠跺悕锛�<br>
-     * 娉ㄦ剰姝ら」涓哄叏灞�璁剧疆锛屾椤逛細璋冪敤
-     * <pre>
-     * System.setProperty("mail.mime.splitlongparameters", true)
-     * </pre>
-     *
-     * @param splitlongparameters 瀵逛簬瓒呴暱鍙傛暟鏄惁鍒囧垎涓哄浠�
-     */
-    public void setSplitlongparameters(boolean splitlongparameters) {
-        this.splitlongparameters = splitlongparameters;
-    }
-
-    /**
-     * 瀵逛簬鏂囦欢鍚嶆槸鍚︿娇鐢▄@link #charset}缂栫爜锛岄粯璁や负 {@code true}
-     *
-     * @return 瀵逛簬鏂囦欢鍚嶆槸鍚︿娇鐢▄@link #charset}缂栫爜锛岄粯璁や负 {@code true}
-     * @since 5.7.16
-     */
-    public boolean isEncodefilename() {
-
-        return encodefilename;
-    }
-
-    /**
-     * 璁剧疆瀵逛簬鏂囦欢鍚嶆槸鍚︿娇鐢▄@link #charset}缂栫爜锛屾閫夐」涓嶄細淇敼鍏ㄥ眬閰嶇疆<br>
-     * 濡傛灉姝ら�夐」璁剧疆涓簕@code false}锛屽垯鏄惁缂栫爜鍙栧喅浜庝袱涓郴缁熷睘鎬э細
-     * <ul>
-     *     <li>mail.mime.encodefilename  鏄惁缂栫爜闄勪欢鏂囦欢鍚�</li>
-     *     <li>mail.mime.charset         缂栫爜鏂囦欢鍚嶇殑缂栫爜</li>
-     * </ul>
-     *
-     * @param encodefilename 瀵逛簬鏂囦欢鍚嶆槸鍚︿娇鐢▄@link #charset}缂栫爜
-     * @since 5.7.16
-     */
-    public void setEncodefilename(boolean encodefilename) {
-        this.encodefilename = encodefilename;
-    }
-
-    /**
-     * 鏄惁浣跨敤 STARTTLS瀹夊叏杩炴帴锛孲TARTTLS鏄绾枃鏈�氫俊鍗忚鐨勬墿灞曘�傚畠灏嗙函鏂囨湰杩炴帴鍗囩骇涓哄姞瀵嗚繛鎺ワ紙TLS鎴朣SL锛夛紝 鑰屼笉鏄娇鐢ㄤ竴涓崟鐙殑鍔犲瘑閫氫俊绔彛銆�
-     *
-     * @return 鏄惁浣跨敤 STARTTLS瀹夊叏杩炴帴
-     */
-    public boolean isStarttlsEnable() {
-        return this.starttlsEnable;
-    }
-
-    /**
-     * 璁剧疆鏄惁浣跨敤STARTTLS瀹夊叏杩炴帴锛孲TARTTLS鏄绾枃鏈�氫俊鍗忚鐨勬墿灞曘�傚畠灏嗙函鏂囨湰杩炴帴鍗囩骇涓哄姞瀵嗚繛鎺ワ紙TLS鎴朣SL锛夛紝 鑰屼笉鏄娇鐢ㄤ竴涓崟鐙殑鍔犲瘑閫氫俊绔彛銆�
-     *
-     * @param startttlsEnable 鏄惁浣跨敤STARTTLS瀹夊叏杩炴帴
-     * @return this
-     */
-    public MailAccount setStarttlsEnable(boolean startttlsEnable) {
-        this.starttlsEnable = startttlsEnable;
-        return this;
-    }
-
-    /**
-     * 鏄惁浣跨敤 SSL瀹夊叏杩炴帴
-     *
-     * @return 鏄惁浣跨敤 SSL瀹夊叏杩炴帴
-     */
-    public Boolean isSslEnable() {
-        return this.sslEnable;
-    }
-
-    /**
-     * 璁剧疆鏄惁浣跨敤SSL瀹夊叏杩炴帴
-     *
-     * @param sslEnable 鏄惁浣跨敤SSL瀹夊叏杩炴帴
-     * @return this
-     */
-    public MailAccount setSslEnable(Boolean sslEnable) {
-        this.sslEnable = sslEnable;
-        return this;
-    }
-
-    /**
-     * 鑾峰彇SSL鍗忚锛屽涓崗璁敤绌烘牸鍒嗛殧
-     *
-     * @return SSL鍗忚锛屽涓崗璁敤绌烘牸鍒嗛殧
-     * @since 5.5.7
-     */
-    public String getSslProtocols() {
-        return sslProtocols;
-    }
-
-    /**
-     * 璁剧疆SSL鍗忚锛屽涓崗璁敤绌烘牸鍒嗛殧
-     *
-     * @param sslProtocols SSL鍗忚锛屽涓崗璁敤绌烘牸鍒嗛殧
-     * @since 5.5.7
-     */
-    public void setSslProtocols(String sslProtocols) {
-        this.sslProtocols = sslProtocols;
-    }
-
-    /**
-     * 鑾峰彇鎸囧畾瀹炵幇javax.net.SocketFactory鎺ュ彛鐨勭被鐨勫悕绉�,杩欎釜绫诲皢琚敤浜庡垱寤篠MTP鐨勫鎺ュ瓧
-     *
-     * @return 鎸囧畾瀹炵幇javax.net.SocketFactory鎺ュ彛鐨勭被鐨勫悕绉�, 杩欎釜绫诲皢琚敤浜庡垱寤篠MTP鐨勫鎺ュ瓧
-     */
-    public String getSocketFactoryClass() {
-        return socketFactoryClass;
-    }
-
-    /**
-     * 璁剧疆鎸囧畾瀹炵幇javax.net.SocketFactory鎺ュ彛鐨勭被鐨勫悕绉�,杩欎釜绫诲皢琚敤浜庡垱寤篠MTP鐨勫鎺ュ瓧
-     *
-     * @param socketFactoryClass 鎸囧畾瀹炵幇javax.net.SocketFactory鎺ュ彛鐨勭被鐨勫悕绉�,杩欎釜绫诲皢琚敤浜庡垱寤篠MTP鐨勫鎺ュ瓧
-     * @return this
-     */
-    public MailAccount setSocketFactoryClass(String socketFactoryClass) {
-        this.socketFactoryClass = socketFactoryClass;
-        return this;
-    }
-
-    /**
-     * 濡傛灉璁剧疆涓簍rue,鏈兘鍒涘缓涓�涓鎺ュ瓧浣跨敤鎸囧畾鐨勫鎺ュ瓧宸ュ巶绫诲皢瀵艰嚧浣跨敤java.net.Socket鍒涘缓鐨勫鎺ュ瓧绫�, 榛樿鍊间负true
-     *
-     * @return 濡傛灉璁剧疆涓簍rue, 鏈兘鍒涘缓涓�涓鎺ュ瓧浣跨敤鎸囧畾鐨勫鎺ュ瓧宸ュ巶绫诲皢瀵艰嚧浣跨敤java.net.Socket鍒涘缓鐨勫鎺ュ瓧绫�, 榛樿鍊间负true
-     */
-    public boolean isSocketFactoryFallback() {
-        return socketFactoryFallback;
-    }
-
-    /**
-     * 濡傛灉璁剧疆涓簍rue,鏈兘鍒涘缓涓�涓鎺ュ瓧浣跨敤鎸囧畾鐨勫鎺ュ瓧宸ュ巶绫诲皢瀵艰嚧浣跨敤java.net.Socket鍒涘缓鐨勫鎺ュ瓧绫�, 榛樿鍊间负true
-     *
-     * @param socketFactoryFallback 濡傛灉璁剧疆涓簍rue,鏈兘鍒涘缓涓�涓鎺ュ瓧浣跨敤鎸囧畾鐨勫鎺ュ瓧宸ュ巶绫诲皢瀵艰嚧浣跨敤java.net.Socket鍒涘缓鐨勫鎺ュ瓧绫�, 榛樿鍊间负true
-     * @return this
-     */
-    public MailAccount setSocketFactoryFallback(boolean socketFactoryFallback) {
-        this.socketFactoryFallback = socketFactoryFallback;
-        return this;
-    }
-
-    /**
-     * 鑾峰彇鎸囧畾鐨勭鍙h繛鎺ュ埌鍦ㄤ娇鐢ㄦ寚瀹氱殑濂楁帴瀛楀伐鍘傘�傚鏋滄病鏈夎缃�,灏嗕娇鐢ㄩ粯璁ょ鍙�
-     *
-     * @return 鎸囧畾鐨勭鍙h繛鎺ュ埌鍦ㄤ娇鐢ㄦ寚瀹氱殑濂楁帴瀛楀伐鍘傘�傚鏋滄病鏈夎缃�,灏嗕娇鐢ㄩ粯璁ょ鍙�
-     */
-    public int getSocketFactoryPort() {
-        return socketFactoryPort;
-    }
-
-    /**
-     * 鎸囧畾鐨勭鍙h繛鎺ュ埌鍦ㄤ娇鐢ㄦ寚瀹氱殑濂楁帴瀛楀伐鍘傘�傚鏋滄病鏈夎缃�,灏嗕娇鐢ㄩ粯璁ょ鍙�
-     *
-     * @param socketFactoryPort 鎸囧畾鐨勭鍙h繛鎺ュ埌鍦ㄤ娇鐢ㄦ寚瀹氱殑濂楁帴瀛楀伐鍘傘�傚鏋滄病鏈夎缃�,灏嗕娇鐢ㄩ粯璁ょ鍙�
-     * @return this
-     */
-    public MailAccount setSocketFactoryPort(int socketFactoryPort) {
-        this.socketFactoryPort = socketFactoryPort;
-        return this;
-    }
-
-    /**
-     * 璁剧疆SMTP瓒呮椂鏃堕暱锛屽崟浣嶆绉掞紝缂虹渷鍊间笉瓒呮椂
-     *
-     * @param timeout SMTP瓒呮椂鏃堕暱锛屽崟浣嶆绉掞紝缂虹渷鍊间笉瓒呮椂
-     * @return this
-     * @since 4.1.17
-     */
-    public MailAccount setTimeout(long timeout) {
-        this.timeout = timeout;
-        return this;
-    }
-
-    /**
-     * 璁剧疆Socket杩炴帴瓒呮椂鍊硷紝鍗曚綅姣锛岀己鐪佸�间笉瓒呮椂
-     *
-     * @param connectionTimeout Socket杩炴帴瓒呮椂鍊硷紝鍗曚綅姣锛岀己鐪佸�间笉瓒呮椂
-     * @return this
-     * @since 4.1.17
-     */
-    public MailAccount setConnectionTimeout(long connectionTimeout) {
-        this.connectionTimeout = connectionTimeout;
-        return this;
-    }
-
-    /**
-     * 璁剧疆Socket鍐欏嚭瓒呮椂鍊硷紝鍗曚綅姣锛岀己鐪佸�间笉瓒呮椂
-     *
-     * @param writeTimeout Socket鍐欏嚭瓒呮椂鍊硷紝鍗曚綅姣锛岀己鐪佸�间笉瓒呮椂
-     * @return this
-     * @since 5.8.3
-     */
-    public MailAccount setWriteTimeout(long writeTimeout) {
-        this.writeTimeout = writeTimeout;
-        return this;
-    }
-
-    /**
-     * 鑾峰彇鑷畾涔夊睘鎬у垪琛�
-     *
-     * @return 鑷畾涔夊弬鏁板垪琛�
-     * @since 5.6.4
-     */
-    public Map<String, Object> getCustomProperty() {
-        return customProperty;
-    }
-
-    /**
-     * 璁剧疆鑷畾涔夊睘鎬э紝濡俶ail.smtp.ssl.socketFactory
-     *
-     * @param key   灞炴�у悕锛岀┖鐧借蹇界暐
-     * @param value 灞炴�у�硷紝 null琚拷鐣�
-     * @return this
-     * @since 5.6.4
-     */
-    public MailAccount setCustomProperty(String key, Object value) {
-        if (StrUtil.isNotBlank(key) && ObjectUtil.isNotNull(value)) {
-            this.customProperty.put(key, value);
-        }
-        return this;
-    }
-
-    /**
-     * 鑾峰緱SMTP鐩稿叧淇℃伅
-     *
-     * @return {@link Properties}
-     */
-    public Properties getSmtpProps() {
-        //鍏ㄥ眬绯荤粺鍙傛暟
-        System.setProperty(SPLIT_LONG_PARAMS, String.valueOf(this.splitlongparameters));
-
-        final Properties p = new Properties();
-        p.put(MAIL_PROTOCOL, "smtp");
-        p.put(SMTP_HOST, this.host);
-        p.put(SMTP_PORT, String.valueOf(this.port));
-        p.put(SMTP_AUTH, String.valueOf(this.auth));
-        if (this.timeout > 0) {
-            p.put(SMTP_TIMEOUT, String.valueOf(this.timeout));
-        }
-        if (this.connectionTimeout > 0) {
-            p.put(SMTP_CONNECTION_TIMEOUT, String.valueOf(this.connectionTimeout));
-        }
-        // issue#2355
-        if (this.writeTimeout > 0) {
-            p.put(SMTP_WRITE_TIMEOUT, String.valueOf(this.writeTimeout));
-        }
-
-        p.put(MAIL_DEBUG, String.valueOf(this.debug));
-
-        if (this.starttlsEnable) {
-            //STARTTLS鏄绾枃鏈�氫俊鍗忚鐨勬墿灞曘�傚畠灏嗙函鏂囨湰杩炴帴鍗囩骇涓哄姞瀵嗚繛鎺ワ紙TLS鎴朣SL锛夛紝 鑰屼笉鏄娇鐢ㄤ竴涓崟鐙殑鍔犲瘑閫氫俊绔彛銆�
-            p.put(STARTTLS_ENABLE, "true");
-
-            if (null == this.sslEnable) {
-                //涓轰簡鍏煎鏃х増鏈紝褰撶敤鎴锋病鏈夋椤归厤缃椂锛屾寜鐓tarttlsEnable寮�鍚姸鎬佹椂瀵瑰緟
-                this.sslEnable = true;
-            }
-        }
-
-        // SSL
-        if (null != this.sslEnable && this.sslEnable) {
-            p.put(SSL_ENABLE, "true");
-            p.put(SOCKET_FACTORY, socketFactoryClass);
-            p.put(SOCKET_FACTORY_FALLBACK, String.valueOf(this.socketFactoryFallback));
-            p.put(SOCKET_FACTORY_PORT, String.valueOf(this.socketFactoryPort));
-            // issue#IZN95@Gitee锛屽湪Linux涓嬮渶鑷畾涔塖SL鍗忚鐗堟湰
-            if (StrUtil.isNotBlank(this.sslProtocols)) {
-                p.put(SSL_PROTOCOLS, this.sslProtocols);
-            }
-        }
-
-        // 琛ュ厖鑷畾涔夊睘鎬э紝鍏佽鑷畾灞炴�ц鐩栧凡缁忚缃殑鍊�
-        p.putAll(this.customProperty);
-
-        return p;
-    }
-
-    /**
-     * 濡傛灉鏌愪簺鍊间负null锛屼娇鐢ㄩ粯璁ゅ��
-     *
-     * @return this
-     */
-    public MailAccount defaultIfEmpty() {
-        // 鍘绘帀鍙戜欢浜虹殑濮撳悕閮ㄥ垎
-        final String fromAddress = InternalMailUtil.parseFirstAddress(this.from, this.charset).getAddress();
-
-        if (StrUtil.isBlank(this.host)) {
-            // 濡傛灉SMTP鍦板潃涓虹┖锛岄粯璁や娇鐢╯mtp.<鍙戜欢浜洪偖绠卞悗缂�>
-            this.host = StrUtil.format("smtp.{}", StrUtil.subSuf(fromAddress, fromAddress.indexOf('@') + 1));
-        }
-        if (StrUtil.isBlank(user)) {
-            // 濡傛灉鐢ㄦ埛鍚嶄负绌猴紝榛樿涓哄彂浠朵汉锛坕ssue#I4FYVY@Gitee锛�
-            //this.user = StrUtil.subPre(fromAddress, fromAddress.indexOf('@'));
-            this.user = fromAddress;
-        }
-        if (null == this.auth) {
-            // 濡傛灉瀵嗙爜闈炵┖鐧斤紝鍒欎娇鐢ㄨ璇佹ā寮�
-            this.auth = (false == StrUtil.isBlank(this.pass));
-        }
-        if (null == this.port) {
-            // 绔彛鍦⊿SL鐘舵�佷笅榛樿涓巗ocketFactoryPort涓�鑷达紝闈濻SL鐘舵�佷笅榛樿涓�25
-            this.port = (null != this.sslEnable && this.sslEnable) ? this.socketFactoryPort : 25;
-        }
-        if (null == this.charset) {
-            // 榛樿UTF-8缂栫爜
-            this.charset = CharsetUtil.CHARSET_UTF_8;
-        }
-
-        return this;
-    }
-
-    @Override
-    public String toString() {
-        return "MailAccount [host=" + host + ", port=" + port + ", auth=" + auth + ", user=" + user + ", pass=" + (StrUtil.isEmpty(this.pass) ? "" : "******") + ", from=" + from + ", startttlsEnable="
-            + starttlsEnable + ", socketFactoryClass=" + socketFactoryClass + ", socketFactoryFallback=" + socketFactoryFallback + ", socketFactoryPort=" + socketFactoryPort + "]";
-    }
-}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailException.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailException.java
deleted file mode 100644
index cc199d4..0000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import cn.hutool.core.exceptions.ExceptionUtil;
-import cn.hutool.core.util.StrUtil;
-
-import java.io.Serial;
-
-/**
- * 閭欢寮傚父
- *
- * @author xiaoleilu
- */
-public class MailException extends RuntimeException {
-    @Serial
-    private static final long serialVersionUID = 8247610319171014183L;
-
-    public MailException(Throwable e) {
-        super(ExceptionUtil.getMessage(e), e);
-    }
-
-    public MailException(String message) {
-        super(message);
-    }
-
-    public MailException(String messageTemplate, Object... params) {
-        super(StrUtil.format(messageTemplate, params));
-    }
-
-    public MailException(String message, Throwable throwable) {
-        super(message, throwable);
-    }
-
-    public MailException(String message, Throwable throwable, boolean enableSuppression, boolean writableStackTrace) {
-        super(message, throwable, enableSuppression, writableStackTrace);
-    }
-
-    public MailException(Throwable throwable, String messageTemplate, Object... params) {
-        super(StrUtil.format(messageTemplate, params), throwable);
-    }
-}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java
index 040cc57..a28701f 100644
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java
+++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java
@@ -5,6 +5,9 @@
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.CharUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.mail.JakartaMail;
+import cn.hutool.extra.mail.JakartaUserPassAuthenticator;
+import cn.hutool.extra.mail.MailAccount;
 import jakarta.mail.Authenticator;
 import jakarta.mail.Session;
 import lombok.AccessLevel;
@@ -17,7 +20,7 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-
+import java.util.Map.Entry;
 
 /**
  * 閭欢宸ュ叿绫�
@@ -385,7 +388,7 @@
     public static Session getSession(MailAccount mailAccount, boolean isSingleton) {
         Authenticator authenticator = null;
         if (mailAccount.isAuth()) {
-            authenticator = new UserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass());
+            authenticator = new JakartaUserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass());
         }
 
         return isSingleton ? Session.getDefaultInstance(mailAccount.getSmtpProps(), authenticator) //
@@ -412,7 +415,7 @@
      */
     private static String send(MailAccount mailAccount, boolean useGlobalSession, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content,
                                Map<String, InputStream> imageMap, boolean isHtml, File... files) {
-        final Mail mail = Mail.create(mailAccount).setUseGlobalSession(useGlobalSession);
+        final JakartaMail mail = JakartaMail.create(mailAccount).setUseGlobalSession(useGlobalSession);
 
         // 鍙�夋妱閫佷汉
         if (CollUtil.isNotEmpty(ccs)) {
@@ -431,7 +434,7 @@
 
         // 鍥剧墖
         if (MapUtil.isNotEmpty(imageMap)) {
-            for (Map.Entry<String, InputStream> entry : imageMap.entrySet()) {
+            for (Entry<String, InputStream> entry : imageMap.entrySet()) {
                 mail.addImage(entry.getKey(), entry.getValue());
                 // 鍏抽棴娴�
                 IoUtil.close(entry.getValue());
@@ -463,5 +466,4 @@
         return result;
     }
     // ------------------------------------------------------------------------------------------------------------------------ Private method end
-
 }
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/UserPassAuthenticator.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/UserPassAuthenticator.java
deleted file mode 100644
index fbbe5e3..0000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/UserPassAuthenticator.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import jakarta.mail.Authenticator;
-import jakarta.mail.PasswordAuthentication;
-
-/**
- * 鐢ㄦ埛鍚嶅瘑鐮侀獙璇佸櫒
- *
- * @author looly
- * @since 3.1.2
- */
-public class UserPassAuthenticator extends Authenticator {
-
-    private final String user;
-    private final String pass;
-
-    /**
-     * 鏋勯��
-     *
-     * @param user 鐢ㄦ埛鍚�
-     * @param pass 瀵嗙爜
-     */
-    public UserPassAuthenticator(String user, String pass) {
-        this.user = user;
-        this.pass = pass;
-    }
-
-    @Override
-    protected PasswordAuthentication getPasswordAuthentication() {
-        return new PasswordAuthentication(this.user, this.pass);
-    }
-
-}
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java
index f8c5cd0..2879b9d 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java
@@ -30,4 +30,11 @@
      */
     String[] value() default "dept_id";
 
+    /**
+     * 鏉冮檺鏍囪瘑绗� 鐢ㄤ簬閫氳繃鑿滃崟鏉冮檺鏍囪瘑绗︽潵鑾峰彇鏁版嵁鏉冮檺
+     * 鎷ユ湁姝ゆ爣璇嗙鐨勮鑹� 灏嗕笉浼氭嫾鎺ユ瑙掕壊鐨勬暟鎹繃婊ql
+     *
+     * @return 鏉冮檺鏍囪瘑绗�
+     */
+    String permission() default "";
 }
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java
index 6fd3c3e..f5f22d5 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java
@@ -20,4 +20,11 @@
      */
     DataColumn[] value();
 
+    /**
+     * 鏉冮檺鎷兼帴鏍囪瘑绗�(鐢ㄤ簬鎸囧畾杩炴帴璇彞鐨剆ql绗﹀彿)
+     * 濡備笉濉� 榛樿 select 鐢� OR 鍏朵粬璇彞鐢� AND
+     * 鍐呭 OR 鎴栬�� AND
+     */
+    String joinStr() default "";
+
 }
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java
index 455cecb..981bd42 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java
@@ -13,9 +13,9 @@
  * 鍐呯疆鏁版嵁锛�
  * - {@code user}: 褰撳墠鐧诲綍鐢ㄦ埛淇℃伅锛屽弬鑰� {@link LoginUser}
  * 鍐呯疆鏈嶅姟锛�
- * - {@code sdss}: 绯荤粺鏁版嵁鏉冮檺鏈嶅姟锛屽弬鑰� {@link ISysDataScopeService}
+ * - {@code sdss}: 绯荤粺鏁版嵁鏉冮檺鏈嶅姟锛屽弬鑰� ISysDataScopeService
  * 濡傞渶鎵╁睍鏁版嵁锛屽彲浠ラ�氳繃 {@link DataPermissionHelper} 杩涜鎿嶄綔
- * 濡傞渶鎵╁睍鏈嶅姟锛屽彲浠ラ�氳繃 {@link ISysDataScopeService} 鑷缂栧啓
+ * 濡傞渶鎵╁睍鏈嶅姟锛屽彲浠ラ�氳繃 ISysDataScopeService 鑷缂栧啓
  * </p>
  *
  * @author Lion Li
@@ -32,29 +32,21 @@
 
     /**
      * 鑷畾鏁版嵁鏉冮檺
-     * 浣跨敤 SpEL 琛ㄨ揪寮忥細`#{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} )`
-     * 濡傛灉涓嶆弧瓒虫潯浠讹紝鍒欎娇鐢ㄩ粯璁� SQL 琛ㄨ揪寮忥細`1 = 0`
      */
     CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", " 1 = 0 "),
 
     /**
      * 閮ㄩ棬鏁版嵁鏉冮檺
-     * 浣跨敤 SpEL 琛ㄨ揪寮忥細`#{#deptName} = #{#user.deptId}`
-     * 濡傛灉涓嶆弧瓒虫潯浠讹紝鍒欎娇鐢ㄩ粯璁� SQL 琛ㄨ揪寮忥細`1 = 0`
      */
     DEPT("3", " #{#deptName} = #{#user.deptId} ", " 1 = 0 "),
 
     /**
      * 閮ㄩ棬鍙婁互涓嬫暟鎹潈闄�
-     * 浣跨敤 SpEL 琛ㄨ揪寮忥細`#{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )}`
-     * 濡傛灉涓嶆弧瓒虫潯浠讹紝鍒欎娇鐢ㄩ粯璁� SQL 琛ㄨ揪寮忥細`1 = 0`
      */
     DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", " 1 = 0 "),
 
     /**
      * 浠呮湰浜烘暟鎹潈闄�
-     * 浣跨敤 SpEL 琛ㄨ揪寮忥細`#{#userName} = #{#user.userId}`
-     * 濡傛灉涓嶆弧瓒虫潯浠讹紝鍒欎娇鐢ㄩ粯璁� SQL 琛ㄨ揪寮忥細`1 = 0`
      */
     SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 ");
 
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java
index 99e6b38..7d44d26 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java
@@ -48,6 +48,10 @@
                             ? baseEntity.getCreateDept() : loginUser.getDeptId());
                     }
                 }
+            } else {
+                Date date = new Date();
+                this.strictInsertFill(metaObject, "createTime", Date.class, date);
+                this.strictInsertFill(metaObject, "updateTime", Date.class, date);
             }
         } catch (Exception e) {
             throw new ServiceException("鑷姩娉ㄥ叆寮傚父 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
@@ -72,6 +76,8 @@
                 if (ObjectUtil.isNotNull(userId)) {
                     baseEntity.setUpdateBy(userId);
                 }
+            } else {
+                this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
             }
         } catch (Exception e) {
             throw new ServiceException("鑷姩娉ㄥ叆寮傚父 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
index 74279bd..5ac74c3 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
@@ -99,7 +99,7 @@
             return where;
         }
         // 鏋勯�犳暟鎹繃婊ゆ潯浠剁殑 SQL 鐗囨
-        String dataFilterSql = buildDataFilter(dataPermission.value(), isSelect);
+        String dataFilterSql = buildDataFilter(dataPermission, isSelect);
         if (StringUtils.isBlank(dataFilterSql)) {
             return where;
         }
@@ -120,14 +120,17 @@
     /**
      * 鏋勫缓鏁版嵁杩囨护鏉′欢鐨� SQL 璇彞
      *
-     * @param dataColumns 鏁版嵁鏉冮檺娉ㄨВ涓殑鍒椾俊鎭�
-     * @param isSelect    鏍囧織褰撳墠鎿嶄綔鏄惁涓烘煡璇㈡搷浣滐紝鏌ヨ鎿嶄綔鍜屾洿鏂版垨鍒犻櫎鎿嶄綔鍦ㄥ鐞嗚繃婊ゆ潯浠舵椂浼氭湁涓嶅悓鐨勫鐞嗘柟寮�
+     * @param dataPermission 鏁版嵁鏉冮檺娉ㄨВ
+     * @param isSelect       鏍囧織褰撳墠鎿嶄綔鏄惁涓烘煡璇㈡搷浣滐紝鏌ヨ鎿嶄綔鍜屾洿鏂版垨鍒犻櫎鎿嶄綔鍦ㄥ鐞嗚繃婊ゆ潯浠舵椂浼氭湁涓嶅悓鐨勫鐞嗘柟寮�
      * @return 鏋勫缓鐨勬暟鎹繃婊ゆ潯浠剁殑 SQL 璇彞
      * @throws ServiceException 濡傛灉瑙掕壊鐨勬暟鎹寖鍥村紓甯告垨鑰� key 涓� value 鐨勯暱搴︿笉鍖归厤锛屽垯鎶涘嚭 ServiceException 寮傚父
      */
-    private String buildDataFilter(DataColumn[] dataColumns, boolean isSelect) {
+    private String buildDataFilter(DataPermission dataPermission, boolean isSelect) {
         // 鏇存柊鎴栧垹闄ら渶婊¤冻鎵�鏈夋潯浠�
         String joinStr = isSelect ? " OR " : " AND ";
+        if (StringUtils.isNotBlank(dataPermission.joinStr())) {
+            joinStr = " " + dataPermission.joinStr() + " ";
+        }
         LoginUser user = DataPermissionHelper.getVariable("user");
         StandardEvaluationContext context = new StandardEvaluationContext();
         context.setBeanResolver(beanResolver);
@@ -145,7 +148,7 @@
                 return "";
             }
             boolean isSuccess = false;
-            for (DataColumn dataColumn : dataColumns) {
+            for (DataColumn dataColumn : dataPermission.value()) {
                 if (dataColumn.key().length != dataColumn.value().length) {
                     throw new ServiceException("瑙掕壊鏁版嵁鑼冨洿寮傚父 => key涓巚alue闀垮害涓嶅尮閰�");
                 }
@@ -155,6 +158,13 @@
                 )) {
                     continue;
                 }
+                // 鍖呭惈鏉冮檺鏍囪瘑绗� 杩欑洿鎺ヨ烦杩�
+                if (StringUtils.isNotBlank(dataColumn.permission()) &&
+                    CollUtil.contains(user.getMenuPermission(), dataColumn.permission())
+                ) {
+                    isSuccess = true;
+                    continue;
+                }
                 // 璁剧疆娉ㄨВ鍙橀噺 key 涓鸿〃杈惧紡鍙橀噺 value 涓哄彉閲忓��
                 for (int i = 0; i < dataColumn.key().length; i++) {
                     context.setVariable(dataColumn.key()[i], dataColumn.value()[i]);
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java
index 2afe9ee..932f173 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java
@@ -2,14 +2,17 @@
 
 import cn.dev33.satoken.context.SaHolder;
 import cn.dev33.satoken.context.model.SaStorage;
+import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
 import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Stack;
 import java.util.function.Supplier;
 
 /**
@@ -23,6 +26,8 @@
 public class DataPermissionHelper {
 
     private static final String DATA_PERMISSION_KEY = "data:permission";
+
+    private static final ThreadLocal<Stack<Integer>> REENTRANT_IGNORE = ThreadLocal.withInitial(Stack::new);
 
     /**
      * 浠庝笂涓嬫枃涓幏鍙栨寚瀹氶敭鐨勫彉閲忓�硷紝骞跺皢鍏惰浆鎹负鎸囧畾鐨勭被鍨�
@@ -66,23 +71,54 @@
         throw new NullPointerException("data permission context type exception");
     }
 
+    private static IgnoreStrategy getIgnoreStrategy() {
+        Object ignoreStrategyLocal = ReflectUtils.getStaticFieldValue(ReflectUtils.getField(InterceptorIgnoreHelper.class, "IGNORE_STRATEGY_LOCAL"));
+        if (ignoreStrategyLocal instanceof ThreadLocal<?> IGNORE_STRATEGY_LOCAL) {
+            if (IGNORE_STRATEGY_LOCAL.get() instanceof IgnoreStrategy ignoreStrategy) {
+                return ignoreStrategy;
+            }
+        }
+        return null;
+    }
+
     /**
      * 寮�鍚拷鐣ユ暟鎹潈闄�(寮�鍚悗闇�鎵嬪姩璋冪敤 {@link #disableIgnore()} 鍏抽棴)
      */
     public static void enableIgnore() {
-        InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build());
+        IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
+        if (ObjectUtil.isNull(ignoreStrategy)) {
+            InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build());
+        } else {
+            ignoreStrategy.setDataPermission(true);
+        }
+        Stack<Integer> reentrantStack = REENTRANT_IGNORE.get();
+        reentrantStack.push(reentrantStack.size() + 1);
     }
 
     /**
      * 鍏抽棴蹇界暐鏁版嵁鏉冮檺
      */
     public static void disableIgnore() {
-        InterceptorIgnoreHelper.clearIgnoreStrategy();
+        IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
+        if (ObjectUtil.isNotNull(ignoreStrategy)) {
+            boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName())
+                && !Boolean.TRUE.equals(ignoreStrategy.getBlockAttack())
+                && !Boolean.TRUE.equals(ignoreStrategy.getIllegalSql())
+                && !Boolean.TRUE.equals(ignoreStrategy.getTenantLine())
+                && CollectionUtil.isEmpty(ignoreStrategy.getOthers());
+            Stack<Integer> reentrantStack = REENTRANT_IGNORE.get();
+            boolean empty = reentrantStack.isEmpty() || reentrantStack.pop() == 1;
+            if (noOtherIgnoreStrategy && empty) {
+                InterceptorIgnoreHelper.clearIgnoreStrategy();
+            } else if (empty) {
+                ignoreStrategy.setDataPermission(false);
+            }
+
+        }
     }
 
     /**
      * 鍦ㄥ拷鐣ユ暟鎹潈闄愪腑鎵ц
-     * <p>绂佹鍦ㄥ拷鐣ユ暟鎹潈闄愪腑鎵ц蹇界暐鏁版嵁鏉冮檺</p>
      *
      * @param handle 澶勭悊鎵ц鏂规硶
      */
@@ -97,7 +133,6 @@
 
     /**
      * 鍦ㄥ拷鐣ユ暟鎹潈闄愪腑鎵ц
-     * <p>绂佹鍦ㄥ拷鐣ユ暟鎹潈闄愪腑鎵ц蹇界暐鏁版嵁鏉冮檺</p>
      *
      * @param handle 澶勭悊鎵ц鏂规硶
      */
diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java
index 02735b0..1f4904a 100644
--- a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java
+++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java
@@ -80,11 +80,11 @@
 
     private String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {
         String key = rateLimiter.key();
-        if (StringUtils.isNotBlank(key)) {
+        // 鍒ゆ柇 key 涓嶄负绌� 鍜� 涓嶆槸琛ㄨ揪寮�
+        if (StringUtils.isNotBlank(key) && StringUtils.containsAny(key, "#")) {
             MethodSignature signature = (MethodSignature) point.getSignature();
             Method targetMethod = signature.getMethod();
             Object[] args = point.getArgs();
-            //noinspection DataFlowIssue
             MethodBasedEvaluationContext context =
                 new MethodBasedEvaluationContext(null, targetMethod, args, pnd);
             context.setBeanResolver(new BeanFactoryResolver(SpringUtils.getBeanFactory()));
diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java
index ee1d405..793e21f 100644
--- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java
+++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java
@@ -15,15 +15,17 @@
     private static final com.github.benmanes.caffeine.cache.Cache<Object, Object>
         CAFFEINE = SpringUtils.getBean("caffeine");
 
+    private final String name;
     private final Cache cache;
 
-    public CaffeineCacheDecorator(Cache cache) {
+    public CaffeineCacheDecorator(String name, Cache cache) {
+        this.name = name;
         this.cache = cache;
     }
 
     @Override
     public String getName() {
-        return cache.getName();
+        return name;
     }
 
     @Override
@@ -32,7 +34,7 @@
     }
 
     public String getUniqueKey(Object key) {
-        return cache.getName() + ":" + key;
+        return name + ":" + key;
     }
 
     @Override
diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java
index a48cb14..740e2a1 100644
--- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java
+++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java
@@ -156,7 +156,7 @@
     private Cache createMap(String name, CacheConfig config) {
         RMap<Object, Object> map = RedisUtils.getClient().getMap(name);
 
-        Cache cache = new CaffeineCacheDecorator(new RedissonCache(map, allowNullValues));
+        Cache cache = new CaffeineCacheDecorator(name, new RedissonCache(map, allowNullValues));
         if (transactionAware) {
             cache = new TransactionAwareCacheDecorator(cache);
         }
@@ -170,7 +170,7 @@
     private Cache createMapCache(String name, CacheConfig config) {
         RMapCache<Object, Object> map = RedisUtils.getClient().getMapCache(name);
 
-        Cache cache = new CaffeineCacheDecorator(new RedissonCache(map, config, allowNullValues));
+        Cache cache = new CaffeineCacheDecorator(name, new RedissonCache(map, config, allowNullValues));
         if (transactionAware) {
             cache = new TransactionAwareCacheDecorator(cache);
         }
diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java
index b9283e0..5fd49d1 100644
--- a/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java
+++ b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java
@@ -1,11 +1,15 @@
 package org.dromara.common.security.config;
 
 import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.filter.SaServletFilter;
+import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil;
 import cn.dev33.satoken.interceptor.SaInterceptor;
 import cn.dev33.satoken.router.SaRouter;
 import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.util.SaResult;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.HttpStatus;
 import org.dromara.common.core.utils.ServletUtils;
 import org.dromara.common.core.utils.SpringUtils;
 import org.dromara.common.core.utils.StringUtils;
@@ -14,6 +18,7 @@
 import org.dromara.common.security.handler.AllUrlHandler;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
@@ -71,4 +76,19 @@
             .excludePathPatterns(securityProperties.getExcludes());
     }
 
+    /**
+     * 瀵� actuator 鍋ュ悍妫�鏌ユ帴鍙� 鍋氳处鍙峰瘑鐮侀壌鏉�
+     */
+    @Bean
+    public SaServletFilter getSaServletFilter() {
+        String username = SpringUtils.getProperty("spring.boot.admin.client.username");
+        String password = SpringUtils.getProperty("spring.boot.admin.client.password");
+        return new SaServletFilter()
+            .addInclude("/actuator", "/actuator/**")
+            .setAuth(obj -> {
+                SaHttpBasicUtil.check(username + ":" + password);
+            })
+            .setError(e -> SaResult.error(e.getMessage()).setCode(HttpStatus.UNAUTHORIZED));
+    }
+
 }
diff --git a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java
index 9d1978a..995dcbd 100644
--- a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java
+++ b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java
@@ -37,7 +37,57 @@
     /**
      * 閾惰鍗�
      */
-    BANK_CARD(DesensitizedUtil::bankCard);
+    BANK_CARD(DesensitizedUtil::bankCard),
+
+    /**
+     * 涓枃鍚�
+     */
+    CHINESE_NAME(DesensitizedUtil::chineseName),
+
+    /**
+     * 鍥哄畾鐢佃瘽
+     */
+    FIXED_PHONE(DesensitizedUtil::fixedPhone),
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    USER_ID(s -> String.valueOf(DesensitizedUtil.userId())),
+
+    /**
+     * 瀵嗙爜
+     */
+    PASSWORD(DesensitizedUtil::password),
+
+    /**
+     * ipv4
+     */
+    IPV4(DesensitizedUtil::ipv4),
+
+    /**
+     * ipv6
+     */
+    IPV6(DesensitizedUtil::ipv6),
+
+    /**
+     * 涓浗澶ч檰杞︾墝锛屽寘鍚櫘閫氳溅杈嗐�佹柊鑳芥簮杞﹁締
+     */
+    CAR_LICENSE(DesensitizedUtil::carLicense),
+
+    /**
+     * 鍙樉绀虹涓�涓瓧绗�
+     */
+    FIRST_MASK(DesensitizedUtil::firstMask),
+
+    /**
+     * 娓呯┖涓簄ull
+     */
+    CLEAR(s -> DesensitizedUtil.clear()),
+
+    /**
+     * 娓呯┖涓�""
+     */
+    CLEAR_TO_NULL(s -> DesensitizedUtil.clearToNull());
 
     //鍙嚜琛屾坊鍔犲叾浠栬劚鏁忕瓥鐣�
 
diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java
index 04f6214..9191fca 100644
--- a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java
+++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java
@@ -58,9 +58,9 @@
             case "linkedin" -> new AuthLinkedinRequest(builder.build(), STATE_CACHE);
             case "microsoft" -> new AuthMicrosoftRequest(builder.build(), STATE_CACHE);
             case "renren" -> new AuthRenrenRequest(builder.build(), STATE_CACHE);
-            case "stack_overflow" -> new AuthStackOverflowRequest(builder.stackOverflowKey("").build(), STATE_CACHE);
+            case "stack_overflow" -> new AuthStackOverflowRequest(builder.build(), STATE_CACHE);
             case "huawei" -> new AuthHuaweiRequest(builder.build(), STATE_CACHE);
-            case "wechat_enterprise" -> new AuthWeChatEnterpriseQrcodeRequest(builder.agentId("").build(), STATE_CACHE);
+            case "wechat_enterprise" -> new AuthWeChatEnterpriseQrcodeRequest(builder.build(), STATE_CACHE);
             case "gitlab" -> new AuthGitlabRequest(builder.build(), STATE_CACHE);
             case "wechat_mp" -> new AuthWeChatMpRequest(builder.build(), STATE_CACHE);
             case "aliyun" -> new AuthAliyunRequest(builder.build(), STATE_CACHE);
diff --git a/ruoyi-common/ruoyi-common-sse/pom.xml b/ruoyi-common/ruoyi-common-sse/pom.xml
new file mode 100644
index 0000000..ae44c98
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-sse/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-sse</artifactId>
+
+    <description>
+        ruoyi-common-sse 妯″潡
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-satoken</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-json</artifactId>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java
new file mode 100644
index 0000000..0cf8054
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java
@@ -0,0 +1,36 @@
+package org.dromara.common.sse.config;
+
+import org.dromara.common.sse.controller.SseController;
+import org.dromara.common.sse.core.SseEmitterManager;
+import org.dromara.common.sse.listener.SseTopicListener;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * SSE 鑷姩瑁呴厤
+ *
+ * @author Lion Li
+ */
+@AutoConfiguration
+@ConditionalOnProperty(value = "sse.enabled", havingValue = "true")
+@EnableConfigurationProperties(SseProperties.class)
+public class SseAutoConfiguration {
+
+    @Bean
+    public SseEmitterManager sseEmitterManager() {
+        return new SseEmitterManager();
+    }
+
+    @Bean
+    public SseTopicListener sseTopicListener() {
+        return new SseTopicListener();
+    }
+
+    @Bean
+    public SseController sseController(SseEmitterManager sseEmitterManager) {
+        return new SseController(sseEmitterManager);
+    }
+
+}
diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseProperties.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseProperties.java
new file mode 100644
index 0000000..ce4e173
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseProperties.java
@@ -0,0 +1,21 @@
+package org.dromara.common.sse.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * SSE 閰嶇疆椤�
+ *
+ * @author Lion Li
+ */
+@Data
+@ConfigurationProperties("sse")
+public class SseProperties {
+
+    private Boolean enabled;
+
+    /**
+     * 璺緞
+     */
+    private String path;
+}
diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/controller/SseController.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/controller/SseController.java
new file mode 100644
index 0000000..e5331e4
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/controller/SseController.java
@@ -0,0 +1,87 @@
+package org.dromara.common.sse.controller;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import cn.dev33.satoken.stp.StpUtil;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.sse.core.SseEmitterManager;
+import org.dromara.common.sse.dto.SseMessageDto;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.util.List;
+
+/**
+ * SSE 鎺у埗鍣�
+ *
+ * @author Lion Li
+ */
+@RestController
+@ConditionalOnProperty(value = "sse.enabled", havingValue = "true")
+@RequiredArgsConstructor
+public class SseController implements DisposableBean {
+
+    private final SseEmitterManager sseEmitterManager;
+
+    /**
+     * 寤虹珛 SSE 杩炴帴
+     */
+    @GetMapping(value = "${sse.path}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
+    public SseEmitter connect() {
+        String tokenValue = StpUtil.getTokenValue();
+        Long userId = LoginHelper.getUserId();
+        return sseEmitterManager.connect(userId, tokenValue);
+    }
+
+    /**
+     * 鍏抽棴 SSE 杩炴帴
+     */
+    @SaIgnore
+    @GetMapping(value = "${sse.path}/close")
+    public R<Void> close() {
+        String tokenValue = StpUtil.getTokenValue();
+        Long userId = LoginHelper.getUserId();
+        sseEmitterManager.disconnect(userId, tokenValue);
+        return R.ok();
+    }
+
+    /**
+     * 鍚戠壒瀹氱敤鎴峰彂閫佹秷鎭�
+     *
+     * @param userId 鐩爣鐢ㄦ埛鐨� ID
+     * @param msg    瑕佸彂閫佺殑娑堟伅鍐呭
+     */
+    @GetMapping(value = "${sse.path}/send")
+    public R<Void> send(Long userId, String msg) {
+        SseMessageDto dto = new SseMessageDto();
+        dto.setUserIds(List.of(userId));
+        dto.setMessage(msg);
+        sseEmitterManager.publishMessage(dto);
+        return R.ok();
+    }
+
+    /**
+     * 鍚戞墍鏈夌敤鎴峰彂閫佹秷鎭�
+     *
+     * @param msg 瑕佸彂閫佺殑娑堟伅鍐呭
+     */
+    @GetMapping(value = "${sse.path}/sendAll")
+    public R<Void> send(String msg) {
+        sseEmitterManager.publishAll(msg);
+        return R.ok();
+    }
+
+    /**
+     * 娓呯悊璧勬簮銆傛鏂规硶鐩墠涓嶆墽琛屼换浣曟搷浣滐紝浣嗛伩鍏嶅洜鏈疄鐜拌�屽鑷撮敊璇�
+     */
+    @Override
+    public void destroy() throws Exception {
+        // 閿�姣佹椂涓嶉渶瑕佸仛浠�涔� 姝ゆ柟娉曢伩鍏嶆棤鐢ㄦ搷浣滄姤閿�
+    }
+
+}
diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java
new file mode 100644
index 0000000..1d37a27
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java
@@ -0,0 +1,160 @@
+package org.dromara.common.sse.core;
+
+import cn.hutool.core.collection.CollUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.sse.dto.SseMessageDto;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
+
+/**
+ * 绠$悊 Server-Sent Events (SSE) 杩炴帴
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class SseEmitterManager {
+
+    /**
+     * 璁㈤槄鐨勯閬�
+     */
+    private final static String SSE_TOPIC = "global:sse";
+
+    private final static Map<Long, Map<String, SseEmitter>> USER_TOKEN_EMITTERS = new ConcurrentHashMap<>();
+
+    /**
+     * 寤虹珛涓庢寚瀹氱敤鎴风殑 SSE 杩炴帴
+     *
+     * @param userId 鐢ㄦ埛鐨勫敮涓�鏍囪瘑绗︼紝鐢ㄤ簬鍖哄垎涓嶅悓鐢ㄦ埛鐨勮繛鎺�
+     * @param token  鐢ㄦ埛鐨勫敮涓�浠ょ墝锛岀敤浜庤瘑鍒叿浣撶殑杩炴帴
+     * @return 杩斿洖涓�涓� SseEmitter 瀹炰緥锛屽鎴风鍙互閫氳繃璇ュ疄渚嬫帴鏀� SSE 浜嬩欢
+     */
+    public SseEmitter connect(Long userId, String token) {
+        // 浠� USER_TOKEN_EMITTERS 涓幏鍙栨垨鍒涘缓褰撳墠鐢ㄦ埛鐨� SseEmitter 鏄犲皠琛紙ConcurrentHashMap锛�
+        // 姣忎釜鐢ㄦ埛鍙互鏈夊涓� SSE 杩炴帴锛岄�氳繃 token 杩涜鍖哄垎
+        Map<String, SseEmitter> emitters = USER_TOKEN_EMITTERS.computeIfAbsent(userId, k -> new ConcurrentHashMap<>());
+
+        // 鍒涘缓涓�涓柊鐨� SseEmitter 瀹炰緥锛岃秴鏃舵椂闂磋缃负 0 琛ㄧず鏃犻檺鍒�
+        SseEmitter emitter = new SseEmitter(0L);
+
+        emitters.put(token, emitter);
+
+        // 褰� emitter 瀹屾垚銆佽秴鏃舵垨鍙戠敓閿欒鏃讹紝浠庢槧灏勮〃涓Щ闄ゅ搴旂殑 token
+        emitter.onCompletion(() -> emitters.remove(token));
+        emitter.onTimeout(() -> emitters.remove(token));
+        emitter.onError((e) -> emitters.remove(token));
+
+        try {
+            // 鍚戝鎴风鍙戦�佷竴鏉¤繛鎺ユ垚鍔熺殑浜嬩欢
+            emitter.send(SseEmitter.event().comment("connected"));
+        } catch (IOException e) {
+            // 濡傛灉鍙戦�佹秷鎭け璐ワ紝鍒欎粠鏄犲皠琛ㄤ腑绉婚櫎 emitter
+            emitters.remove(token);
+        }
+        return emitter;
+    }
+
+    /**
+     * 鏂紑鎸囧畾鐢ㄦ埛鐨� SSE 杩炴帴
+     *
+     * @param userId 鐢ㄦ埛鐨勫敮涓�鏍囪瘑绗︼紝鐢ㄤ簬鍖哄垎涓嶅悓鐢ㄦ埛鐨勮繛鎺�
+     * @param token  鐢ㄦ埛鐨勫敮涓�浠ょ墝锛岀敤浜庤瘑鍒叿浣撶殑杩炴帴
+     */
+    public void disconnect(Long userId, String token) {
+        Map<String, SseEmitter> emitters = USER_TOKEN_EMITTERS.get(userId);
+        if (emitters != null) {
+            try {
+                emitters.get(token).send(SseEmitter.event().comment("disconnected"));
+            } catch (Exception ignore) {
+            }
+            emitters.remove(token);
+        }
+    }
+
+    /**
+     * 璁㈤槄SSE娑堟伅涓婚锛屽苟鎻愪緵涓�涓秷璐硅�呭嚱鏁版潵澶勭悊鎺ユ敹鍒扮殑娑堟伅
+     *
+     * @param consumer 澶勭悊SSE娑堟伅鐨勬秷璐硅�呭嚱鏁�
+     */
+    public void subscribeMessage(Consumer<SseMessageDto> consumer) {
+        RedisUtils.subscribe(SSE_TOPIC, SseMessageDto.class, consumer);
+    }
+
+    /**
+     * 鍚戞寚瀹氱殑鐢ㄦ埛浼氳瘽鍙戦�佹秷鎭�
+     *
+     * @param userId  瑕佸彂閫佹秷鎭殑鐢ㄦ埛id
+     * @param message 瑕佸彂閫佺殑娑堟伅鍐呭
+     */
+    public void sendMessage(Long userId, String message) {
+        Map<String, SseEmitter> emitters = USER_TOKEN_EMITTERS.get(userId);
+        if (emitters != null) {
+            for (Map.Entry<String, SseEmitter> entry : emitters.entrySet()) {
+                try {
+                    entry.getValue().send(SseEmitter.event()
+                        .name("message")
+                        .data(message));
+                } catch (Exception e) {
+                    emitters.remove(entry.getKey());
+                }
+            }
+        }
+    }
+
+    /**
+     * 鏈満鍏ㄧ敤鎴蜂細璇濆彂閫佹秷鎭�
+     *
+     * @param message 瑕佸彂閫佺殑娑堟伅鍐呭
+     */
+    public void sendMessage(String message) {
+        for (Long userId : USER_TOKEN_EMITTERS.keySet()) {
+            sendMessage(userId, message);
+        }
+    }
+
+    /**
+     * 鍙戝竷SSE璁㈤槄娑堟伅
+     *
+     * @param sseMessageDto 瑕佸彂甯冪殑SSE娑堟伅瀵硅薄
+     */
+    public void publishMessage(SseMessageDto sseMessageDto) {
+        List<Long> unsentUserIds = new ArrayList<>();
+        // 褰撳墠鏈嶅姟鍐呯敤鎴�,鐩存帴鍙戦�佹秷鎭�
+        for (Long userId : sseMessageDto.getUserIds()) {
+            if (USER_TOKEN_EMITTERS.containsKey(userId)) {
+                sendMessage(userId, sseMessageDto.getMessage());
+                continue;
+            }
+            unsentUserIds.add(userId);
+        }
+        // 涓嶅湪褰撳墠鏈嶅姟鍐呯敤鎴�,鍙戝竷璁㈤槄娑堟伅
+        if (CollUtil.isNotEmpty(unsentUserIds)) {
+            SseMessageDto broadcastMessage = new SseMessageDto();
+            broadcastMessage.setMessage(sseMessageDto.getMessage());
+            broadcastMessage.setUserIds(unsentUserIds);
+            RedisUtils.publish(SSE_TOPIC, broadcastMessage, consumer -> {
+                log.info("SSE鍙戦�佷富棰樿闃呮秷鎭痶opic:{} session keys:{} message:{}",
+                    SSE_TOPIC, unsentUserIds, sseMessageDto.getMessage());
+            });
+        }
+    }
+
+    /**
+     * 鍚戞墍鏈夌殑鐢ㄦ埛鍙戝竷璁㈤槄鐨勬秷鎭�(缇ゅ彂)
+     *
+     * @param message 瑕佸彂甯冪殑娑堟伅鍐呭
+     */
+    public void publishAll(String message) {
+        SseMessageDto broadcastMessage = new SseMessageDto();
+        broadcastMessage.setMessage(message);
+        RedisUtils.publish(SSE_TOPIC, broadcastMessage, consumer -> {
+            log.info("SSE鍙戦�佷富棰樿闃呮秷鎭痶opic:{} message:{}", SSE_TOPIC, message);
+        });
+    }
+}
diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/dto/SseMessageDto.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/dto/SseMessageDto.java
new file mode 100644
index 0000000..a2e1210
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/dto/SseMessageDto.java
@@ -0,0 +1,29 @@
+package org.dromara.common.sse.dto;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 娑堟伅鐨刣to
+ *
+ * @author zendwang
+ */
+@Data
+public class SseMessageDto implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 闇�瑕佹帹閫佸埌鐨剆ession key 鍒楄〃
+     */
+    private List<Long> userIds;
+
+    /**
+     * 闇�瑕佸彂閫佺殑娑堟伅
+     */
+    private String message;
+}
diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/listener/SseTopicListener.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/listener/SseTopicListener.java
new file mode 100644
index 0000000..7a4dff1
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/listener/SseTopicListener.java
@@ -0,0 +1,48 @@
+package org.dromara.common.sse.listener;
+
+import cn.hutool.core.collection.CollUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.sse.core.SseEmitterManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.core.Ordered;
+
+/**
+ * SSE 涓婚璁㈤槄鐩戝惉鍣�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class SseTopicListener implements ApplicationRunner, Ordered {
+
+    @Autowired
+    private SseEmitterManager sseEmitterManager;
+
+    /**
+     * 鍦⊿pring Boot搴旂敤绋嬪簭鍚姩鏃跺垵濮嬪寲SSE涓婚璁㈤槄鐩戝惉鍣�
+     *
+     * @param args 搴旂敤绋嬪簭鍙傛暟
+     * @throws Exception 鍒濆鍖栬繃绋嬩腑鍙兘鎶涘嚭鐨勫紓甯�
+     */
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+        sseEmitterManager.subscribeMessage((message) -> {
+            log.info("SSE涓婚璁㈤槄鏀跺埌娑堟伅session keys={} message={}", message.getUserIds(), message.getMessage());
+            // 濡傛灉key涓嶄负绌哄氨鎸夌収key鍙戞秷鎭� 濡傛灉涓虹┖灏辩兢鍙�
+            if (CollUtil.isNotEmpty(message.getUserIds())) {
+                message.getUserIds().forEach(key -> {
+                    sseEmitterManager.sendMessage(key, message.getMessage());
+                });
+            } else {
+                sseEmitterManager.sendMessage(message.getMessage());
+            }
+        });
+        log.info("鍒濆鍖朣SE涓婚璁㈤槄鐩戝惉鍣ㄦ垚鍔�");
+    }
+
+    @Override
+    public int getOrder() {
+        return -1;
+    }
+}
diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java
new file mode 100644
index 0000000..c6abdc8
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java
@@ -0,0 +1,58 @@
+package org.dromara.common.sse.utils;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.sse.core.SseEmitterManager;
+import org.dromara.common.sse.dto.SseMessageDto;
+
+/**
+ * SSE宸ュ叿绫�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class SseMessageUtils {
+
+    private final static SseEmitterManager MANAGER = SpringUtils.getBean(SseEmitterManager.class);
+
+    /**
+     * 鍚戞寚瀹氱殑WebSocket浼氳瘽鍙戦�佹秷鎭�
+     *
+     * @param userId  瑕佸彂閫佹秷鎭殑鐢ㄦ埛id
+     * @param message 瑕佸彂閫佺殑娑堟伅鍐呭
+     */
+    public static void sendMessage(Long userId, String message) {
+        MANAGER.sendMessage(userId, message);
+    }
+
+    /**
+     * 鏈満鍏ㄧ敤鎴蜂細璇濆彂閫佹秷鎭�
+     *
+     * @param message 瑕佸彂閫佺殑娑堟伅鍐呭
+     */
+    public static void sendMessage(String message) {
+        MANAGER.sendMessage(message);
+    }
+
+    /**
+     * 鍙戝竷SSE璁㈤槄娑堟伅
+     *
+     * @param sseMessageDto 瑕佸彂甯冪殑SSE娑堟伅瀵硅薄
+     */
+    public static void publishMessage(SseMessageDto sseMessageDto) {
+        MANAGER.publishMessage(sseMessageDto);
+    }
+
+    /**
+     * 鍚戞墍鏈夌殑鐢ㄦ埛鍙戝竷璁㈤槄鐨勬秷鎭�(缇ゅ彂)
+     *
+     * @param message 瑕佸彂甯冪殑娑堟伅鍐呭
+     */
+    public static void publishAll(String message) {
+        MANAGER.publishAll(message);
+    }
+
+}
diff --git a/ruoyi-common/ruoyi-common-sse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-sse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..b809713
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-sse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.sse.config.SseAutoConfiguration
diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java
index 9d087e1..b185612 100644
--- a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java
+++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java
@@ -1,8 +1,9 @@
 package org.dromara.common.tenant.helper;
 
 import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.convert.Convert;
-import com.alibaba.ttl.TransmittableThreadLocal;
+import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
 import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
 import lombok.AccessLevel;
@@ -11,9 +12,11 @@
 import org.dromara.common.core.constant.GlobalConstants;
 import org.dromara.common.core.utils.SpringUtils;
 import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
 import org.dromara.common.redis.utils.RedisUtils;
 import org.dromara.common.satoken.utils.LoginHelper;
 
+import java.util.Stack;
 import java.util.function.Supplier;
 
 /**
@@ -27,7 +30,9 @@
 
     private static final String DYNAMIC_TENANT_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "dynamicTenant";
 
-    private static final ThreadLocal<String> TEMP_DYNAMIC_TENANT = new TransmittableThreadLocal<>();
+    private static final ThreadLocal<String> TEMP_DYNAMIC_TENANT = new ThreadLocal<>();
+
+    private static final ThreadLocal<Stack<Integer>> REENTRANT_IGNORE = ThreadLocal.withInitial(Stack::new);
 
     /**
      * 绉熸埛鍔熻兘鏄惁鍚敤
@@ -36,18 +41,49 @@
         return Convert.toBool(SpringUtils.getProperty("tenant.enable"), false);
     }
 
+    private static IgnoreStrategy getIgnoreStrategy() {
+        Object ignoreStrategyLocal = ReflectUtils.getStaticFieldValue(ReflectUtils.getField(InterceptorIgnoreHelper.class, "IGNORE_STRATEGY_LOCAL"));
+        if (ignoreStrategyLocal instanceof ThreadLocal<?> IGNORE_STRATEGY_LOCAL) {
+            if (IGNORE_STRATEGY_LOCAL.get() instanceof IgnoreStrategy ignoreStrategy) {
+                return ignoreStrategy;
+            }
+        }
+        return null;
+    }
+
     /**
      * 寮�鍚拷鐣ョ鎴�(寮�鍚悗闇�鎵嬪姩璋冪敤 {@link #disableIgnore()} 鍏抽棴)
      */
     public static void enableIgnore() {
-        InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build());
+        IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
+        if (ObjectUtil.isNull(ignoreStrategy)) {
+            InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build());
+        } else {
+            ignoreStrategy.setTenantLine(true);
+        }
+        Stack<Integer> reentrantStack = REENTRANT_IGNORE.get();
+        reentrantStack.push(reentrantStack.size() + 1);
     }
 
     /**
      * 鍏抽棴蹇界暐绉熸埛
      */
     public static void disableIgnore() {
-        InterceptorIgnoreHelper.clearIgnoreStrategy();
+        IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
+        if (ObjectUtil.isNotNull(ignoreStrategy)) {
+            boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName())
+                && !Boolean.TRUE.equals(ignoreStrategy.getBlockAttack())
+                && !Boolean.TRUE.equals(ignoreStrategy.getIllegalSql())
+                && !Boolean.TRUE.equals(ignoreStrategy.getDataPermission())
+                && CollectionUtil.isEmpty(ignoreStrategy.getOthers());
+            Stack<Integer> reentrantStack = REENTRANT_IGNORE.get();
+            boolean empty = reentrantStack.isEmpty() || reentrantStack.pop() == 1;
+            if (noOtherIgnoreStrategy && empty) {
+                InterceptorIgnoreHelper.clearIgnoreStrategy();
+            } else if (empty) {
+                ignoreStrategy.setTenantLine(false);
+            }
+        }
     }
 
     /**
diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/manager/TenantSpringCacheManager.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/manager/TenantSpringCacheManager.java
index d230afc..346e36f 100644
--- a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/manager/TenantSpringCacheManager.java
+++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/manager/TenantSpringCacheManager.java
@@ -1,5 +1,7 @@
 package org.dromara.common.tenant.manager;
 
+import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
+import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.constant.GlobalConstants;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.redis.manager.PlusSpringCacheManager;
@@ -11,6 +13,7 @@
  *
  * @author Lion Li
  */
+@Slf4j
 public class TenantSpringCacheManager extends PlusSpringCacheManager {
 
     public TenantSpringCacheManager() {
@@ -18,10 +21,16 @@
 
     @Override
     public Cache getCache(String name) {
+        if (InterceptorIgnoreHelper.willIgnoreTenantLine("")) {
+            return super.getCache(name);
+        }
         if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) {
             return super.getCache(name);
         }
         String tenantId = TenantHelper.getTenantId();
+        if (StringUtils.isBlank(tenantId)) {
+            log.error("鏃犳硶鑾峰彇鏈夋晥鐨勭鎴穒d -> Null");
+        }
         if (StringUtils.startsWith(name, tenantId)) {
             // 濡傛灉瀛樺湪鍒欑洿鎺ヨ繑鍥�
             return super.getCache(name);
diff --git a/ruoyi-common/ruoyi-common-web/pom.xml b/ruoyi-common/ruoyi-common-web/pom.xml
index b250fa9..5e366bc 100644
--- a/ruoyi-common/ruoyi-common-web/pom.xml
+++ b/ruoyi-common/ruoyi-common-web/pom.xml
@@ -44,6 +44,19 @@
         </dependency>
 
         <dependency>
+            <groupId>io.undertow</groupId>
+            <artifactId>undertow-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.undertow</groupId>
+            <artifactId>undertow-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.undertow</groupId>
+            <artifactId>undertow-websockets-jsr</artifactId>
+        </dependency>
+
+        <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-actuator</artifactId>
         </dependency>
diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java
index bd47c18..061d3aa 100644
--- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java
+++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java
@@ -16,9 +16,12 @@
 import org.springframework.web.bind.MethodArgumentNotValidException;
 import org.springframework.web.bind.MissingPathVariableException;
 import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
 import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
 import org.springframework.web.servlet.NoHandlerFoundException;
+
+import java.io.IOException;
 
 /**
  * 鍏ㄥ眬寮傚父澶勭悊鍣�
@@ -92,6 +95,20 @@
     /**
      * 鎷︽埅鏈煡鐨勮繍琛屾椂寮傚父
      */
+    @ResponseStatus(org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR)
+    @ExceptionHandler(IOException.class)
+    public void handleRuntimeException(IOException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        if (requestURI.contains("sse")) {
+            // sse 缁忓父鎬ц繛鎺ヤ腑鏂� 渚嬪鍏抽棴娴忚鍣� 鐩存帴灞忚斀
+            return;
+        }
+        log.error("璇锋眰鍦板潃'{}',杩炴帴涓柇", requestURI, e);
+    }
+
+    /**
+     * 鎷︽埅鏈煡鐨勮繍琛屾椂寮傚父
+     */
     @ExceptionHandler(RuntimeException.class)
     public R<Void> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
         String requestURI = request.getRequestURI();
diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java
index 12c8086..614a559 100644
--- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java
+++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java
@@ -6,7 +6,6 @@
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.time.StopWatch;
-import org.dromara.common.core.utils.SpringUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.json.utils.JsonUtils;
 import org.dromara.common.web.filter.RepeatedlyRequestWrapper;
@@ -19,7 +18,6 @@
 
 /**
  * web鐨勮皟鐢ㄦ椂闂寸粺璁℃嫤鎴櫒
- * dev鐜鏈夋晥
  *
  * @author Lion Li
  * @since 3.3.0
@@ -27,37 +25,34 @@
 @Slf4j
 public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
 
-    private final String prodProfile = "prod";
-
     private final static ThreadLocal<StopWatch> KEY_CACHE = new ThreadLocal<>();
 
     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
-        if (!prodProfile.equals(SpringUtils.getActiveProfile())) {
-            String url = request.getMethod() + " " + request.getRequestURI();
+        String url = request.getMethod() + " " + request.getRequestURI();
 
-            // 鎵撳嵃璇锋眰鍙傛暟
-            if (isJsonRequest(request)) {
-                String jsonParam = "";
-                if (request instanceof RepeatedlyRequestWrapper) {
-                    BufferedReader reader = request.getReader();
-                    jsonParam = IoUtil.read(reader);
-                }
-                log.info("[PLUS]寮�濮嬭姹� => URL[{}],鍙傛暟绫诲瀷[json],鍙傛暟:[{}]", url, jsonParam);
-            } else {
-                Map<String, String[]> parameterMap = request.getParameterMap();
-                if (MapUtil.isNotEmpty(parameterMap)) {
-                    String parameters = JsonUtils.toJsonString(parameterMap);
-                    log.info("[PLUS]寮�濮嬭姹� => URL[{}],鍙傛暟绫诲瀷[param],鍙傛暟:[{}]", url, parameters);
-                } else {
-                    log.info("[PLUS]寮�濮嬭姹� => URL[{}],鏃犲弬鏁�", url);
-                }
+        // 鎵撳嵃璇锋眰鍙傛暟
+        if (isJsonRequest(request)) {
+            String jsonParam = "";
+            if (request instanceof RepeatedlyRequestWrapper) {
+                BufferedReader reader = request.getReader();
+                jsonParam = IoUtil.read(reader);
             }
-
-            StopWatch stopWatch = new StopWatch();
-            KEY_CACHE.set(stopWatch);
-            stopWatch.start();
+            log.info("[PLUS]寮�濮嬭姹� => URL[{}],鍙傛暟绫诲瀷[json],鍙傛暟:[{}]", url, jsonParam);
+        } else {
+            Map<String, String[]> parameterMap = request.getParameterMap();
+            if (MapUtil.isNotEmpty(parameterMap)) {
+                String parameters = JsonUtils.toJsonString(parameterMap);
+                log.info("[PLUS]寮�濮嬭姹� => URL[{}],鍙傛暟绫诲瀷[param],鍙傛暟:[{}]", url, parameters);
+            } else {
+                log.info("[PLUS]寮�濮嬭姹� => URL[{}],鏃犲弬鏁�", url);
+            }
         }
+
+        StopWatch stopWatch = new StopWatch();
+        KEY_CACHE.set(stopWatch);
+        stopWatch.start();
+
         return true;
     }
 
@@ -68,12 +63,10 @@
 
     @Override
     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
-        if (!prodProfile.equals(SpringUtils.getActiveProfile())) {
-            StopWatch stopWatch = KEY_CACHE.get();
-            stopWatch.stop();
-            log.info("[PLUS]缁撴潫璇锋眰 => URL[{}],鑰楁椂:[{}]姣", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime());
-            KEY_CACHE.remove();
-        }
+        StopWatch stopWatch = KEY_CACHE.get();
+        stopWatch.stop();
+        log.info("[PLUS]缁撴潫璇锋眰 => URL[{}],鑰楁椂:[{}]姣", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime());
+        KEY_CACHE.remove();
     }
 
     /**
diff --git a/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java b/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java
index afe76e0..8c4170a 100644
--- a/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java
+++ b/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java
@@ -113,7 +113,7 @@
      * @param session WebSocket浼氳瘽
      * @param message 瑕佸彂閫佺殑WebSocket娑堟伅瀵硅薄
      */
-    private static void sendMessage(WebSocketSession session, WebSocketMessage<?> message) {
+    private synchronized static void sendMessage(WebSocketSession session, WebSocketMessage<?> message) {
         if (session == null || !session.isOpen()) {
             log.warn("[send] session浼氳瘽宸茬粡鍏抽棴");
         } else {
diff --git a/ruoyi-extend/ruoyi-monitor-admin/pom.xml b/ruoyi-extend/ruoyi-monitor-admin/pom.xml
index 91194c6..77c9eb7 100644
--- a/ruoyi-extend/ruoyi-monitor-admin/pom.xml
+++ b/ruoyi-extend/ruoyi-monitor-admin/pom.xml
@@ -12,10 +12,21 @@
     <artifactId>ruoyi-monitor-admin</artifactId>
 
     <dependencies>
-        <!-- SpringWeb妯″潡 -->
+        <!-- SpringBoot Web瀹瑰櫒 -->
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                    <groupId>org.springframework.boot</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <!-- web 瀹瑰櫒浣跨敤 undertow 鎬ц兘鏇村己 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-undertow</artifactId>
         </dependency>
 
         <!-- spring security 瀹夊叏璁よ瘉 -->
diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java
index 3f5dec8..3458cc9 100644
--- a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java
+++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java
@@ -39,9 +39,7 @@
             .authorizeHttpRequests((authorize) ->
                 authorize.requestMatchers(
                         new AntPathRequestMatcher(adminContextPath + "/assets/**"),
-                        new AntPathRequestMatcher(adminContextPath + "/login"),
-                        new AntPathRequestMatcher("/actuator"),
-                        new AntPathRequestMatcher("/actuator/**")
+                        new AntPathRequestMatcher(adminContextPath + "/login")
                     ).permitAll()
                     .anyRequest().authenticated())
             .formLogin((formLogin) ->
diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/notifier/CustomNotifier.java b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/notifier/CustomNotifier.java
index 477a598..838eefc 100644
--- a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/notifier/CustomNotifier.java
+++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/notifier/CustomNotifier.java
@@ -9,6 +9,8 @@
 import org.springframework.stereotype.Component;
 import reactor.core.publisher.Mono;
 
+import static de.codecentric.boot.admin.server.domain.values.StatusInfo.*;
+
 /**
  * 鑷畾涔変簨浠堕�氱煡澶勭悊
  *
@@ -28,13 +30,26 @@
         return Mono.fromRunnable(() -> {
             // 瀹炰緥鐘舵�佹敼鍙樹簨浠�
             if (event instanceof InstanceStatusChangedEvent) {
+                // 鑾峰彇瀹炰緥娉ㄥ唽鍚嶇О
                 String registName = instance.getRegistration().getName();
+                // 鑾峰彇瀹炰緥ID
                 String instanceId = event.getInstance().getValue();
+                // 鑾峰彇瀹炰緥鐘舵��
                 String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus();
-                log.info("Instance Status Change: [{}],[{}],[{}]", registName, instanceId, status);
+                // 鑾峰彇鏈嶅姟URL
+                String serviceUrl = instance.getRegistration().getServiceUrl();
+                String statusName = switch (status) {
+                    case STATUS_UP -> "鏈嶅姟涓婄嚎"; // 瀹炰緥鎴愬姛鍚姩骞跺彲浠ユ甯稿鐞嗚姹�
+                    case STATUS_OFFLINE -> "鏈嶅姟绂荤嚎"; //瀹炰緥琚墜鍔ㄦ垨鑷姩鍦颁粠鏈嶅姟涓Щ闄�
+                    case STATUS_RESTRICTED -> "鏈嶅姟鍙楅檺"; //琛ㄧず瀹炰緥鍦ㄦ煇浜涙柟闈㈠彈闄愶紝鍙兘鏃犳硶瀹屽叏鎻愪緵鎵�鏈夋湇鍔�
+                    case STATUS_OUT_OF_SERVICE -> "鍋滄鏈嶅姟鐘舵��"; //琛ㄧず瀹炰緥宸茶鏍囪涓哄仠姝㈡彁渚涙湇鍔★紝鍙兘鏄鍒掑唴缁存姢鎴栨祴璇�
+                    case STATUS_DOWN -> "鏈嶅姟涓嬬嚎"; //瀹炰緥鍥犲穿婧冦�侀敊璇垨鍏朵粬鍘熷洜鍋滄杩愯
+                    case STATUS_UNKNOWN -> "鏈嶅姟鏈煡寮傚父"; //鐩戞帶绯荤粺鏃犳硶纭畾瀹炰緥鐨勫綋鍓嶇姸鎬�
+                    default -> "鏈煡鐘舵��"; //娌℃湁鍖归厤鐨勭姸鎬�
+                };
+                log.info("Instance Status Change: 鐘舵�佸悕绉般�恵}銆�, 娉ㄥ唽鍚嶇О銆恵}銆�, 瀹炰緥ID銆恵}銆�, 鐘舵�併�恵}銆�, 鏈嶅姟URL銆恵}銆�",
+                    statusName, registName, instanceId, status, serviceUrl);
             }
-
         });
     }
-
 }
diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml
index 1b729ef..beee587 100644
--- a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml
+++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml
@@ -41,5 +41,8 @@
   url: http://localhost:9090/admin
   instance:
     service-host-type: IP
+    metadata:
+      username: ${spring.boot.admin.client.username}
+      userpassword: ${spring.boot.admin.client.password}
   username: ruoyi
   password: 123456
diff --git a/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/ActuatorAuthFilter.java b/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/ActuatorAuthFilter.java
new file mode 100644
index 0000000..e3a6892
--- /dev/null
+++ b/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/ActuatorAuthFilter.java
@@ -0,0 +1,64 @@
+package com.aizuda.snailjob.server.starter.filter;
+
+import jakarta.servlet.*;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+
+public class ActuatorAuthFilter implements Filter {
+
+    private final String username;
+    private final String password;
+
+    public ActuatorAuthFilter(String username, String password) {
+        this.username = username;
+        this.password = password;
+    }
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+        HttpServletRequest request = (HttpServletRequest) servletRequest;
+        HttpServletResponse response = (HttpServletResponse) servletResponse;
+
+        // 鑾峰彇 Authorization 澶�
+        String authHeader = request.getHeader("Authorization");
+
+        if (authHeader == null || !authHeader.startsWith("Basic ")) {
+            // 濡傛灉娌℃湁鎻愪緵 Authorization 鎴栬�呮牸寮忎笉瀵癸紝鍒欒繑鍥� 401
+            response.setHeader("WWW-Authenticate", "Basic realm=\"realm\"");
+            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
+            return;
+        }
+
+        // 瑙g爜 Base64 缂栫爜鐨勭敤鎴峰悕鍜屽瘑鐮�
+        String base64Credentials = authHeader.substring("Basic ".length());
+        byte[] credDecoded = Base64.getDecoder().decode(base64Credentials);
+        String credentials = new String(credDecoded, StandardCharsets.UTF_8);
+        String[] split = credentials.split(":");
+        if (split.length != 2) {
+            response.setHeader("WWW-Authenticate", "Basic realm=\"realm\"");
+            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
+            return;
+        }
+        // 楠岃瘉鐢ㄦ埛鍚嶅拰瀵嗙爜
+        if (!username.equals(split[0]) && password.equals(split[1])) {
+            response.setHeader("WWW-Authenticate", "Basic realm=\"realm\"");
+            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
+            return;
+        }
+        // 濡傛灉璁よ瘉鎴愬姛锛岀户缁鐞嗚姹�
+        filterChain.doFilter(request, response);
+    }
+
+    @Override
+    public void init(FilterConfig filterConfig) {
+    }
+
+    @Override
+    public void destroy() {
+    }
+
+}
diff --git a/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/SecurityConfig.java b/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/SecurityConfig.java
new file mode 100644
index 0000000..3cae8f5
--- /dev/null
+++ b/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/SecurityConfig.java
@@ -0,0 +1,29 @@
+package com.aizuda.snailjob.server.starter.filter;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 鏉冮檺瀹夊叏閰嶇疆
+ *
+ * @author Lion Li
+ */
+@Configuration
+public class SecurityConfig {
+
+    @Value("${spring.boot.admin.client.username}")
+    private String username;
+    @Value("${spring.boot.admin.client.password}")
+    private String password;
+
+    @Bean
+    public FilterRegistrationBean<ActuatorAuthFilter> actuatorFilterRegistrationBean() {
+        FilterRegistrationBean<ActuatorAuthFilter> registrationBean = new FilterRegistrationBean<>();
+        registrationBean.setFilter(new ActuatorAuthFilter(username, password));
+        registrationBean.addUrlPatterns("/actuator", "/actuator/**");
+        return registrationBean;
+    }
+
+}
diff --git a/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml b/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml
index 3c65077..cbe40be 100644
--- a/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml
+++ b/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml
@@ -43,5 +43,8 @@
   url: http://localhost:9090/admin
   instance:
     service-host-type: IP
+    metadata:
+      username: ${spring.boot.admin.client.username}
+      userpassword: ${spring.boot.admin.client.password}
   username: ruoyi
   password: 123456
diff --git a/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml b/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml
index 37ab887..3ba983c 100644
--- a/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml
+++ b/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml
@@ -43,5 +43,8 @@
   url: http://localhost:9090/admin
   instance:
     service-host-type: IP
+    metadata:
+      username: ${spring.boot.admin.client.username}
+      userpassword: ${spring.boot.admin.client.password}
   username: ruoyi
   password: 123456
diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java
index bd94b1c..6aeeb50 100644
--- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java
+++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java
@@ -4,14 +4,14 @@
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Constants;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import org.apache.poi.ss.formula.functions.T;
+import org.apache.ibatis.annotations.Param;
 import org.dromara.common.mybatis.annotation.DataColumn;
 import org.dromara.common.mybatis.annotation.DataPermission;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 import org.dromara.demo.domain.TestDemo;
 import org.dromara.demo.domain.vo.TestDemoVo;
-import org.apache.ibatis.annotations.Param;
 
+import java.io.Serializable;
 import java.util.Collection;
 import java.util.List;
 
@@ -44,16 +44,17 @@
     List<TestDemo> selectList(@Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper);
 
     @Override
-    @DataPermission({
+    @DataPermission(value = {
         @DataColumn(key = "deptName", value = "dept_id"),
         @DataColumn(key = "userName", value = "user_id")
-    })
-    int updateById(@Param(Constants.ENTITY) TestDemo entity);
+    }, joinStr = "AND")
+    List<TestDemo> selectBatchIds(@Param(Constants.COLL) Collection<? extends Serializable> idList);
 
     @Override
     @DataPermission({
         @DataColumn(key = "deptName", value = "dept_id"),
         @DataColumn(key = "userName", value = "user_id")
     })
-    int deleteByIds(@Param(Constants.COLL) Collection<?> idList);
+    int updateById(@Param(Constants.ENTITY) TestDemo entity);
+
 }
diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java
index 86b39c2..3cfde3a 100644
--- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java
+++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java
@@ -3,6 +3,8 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
@@ -12,7 +14,6 @@
 import org.dromara.demo.domain.vo.TestDemoVo;
 import org.dromara.demo.mapper.TestDemoMapper;
 import org.dromara.demo.service.ITestDemoService;
-import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 
 import java.util.Collection;
@@ -99,7 +100,11 @@
     @Override
     public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
         if (isValid) {
-            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+            // 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+            List<TestDemo> list = baseMapper.selectBatchIds(ids);
+            if (list.size() != ids.size()) {
+                throw new ServiceException("鎮ㄦ病鏈夊垹闄ゆ潈闄�!");
+            }
         }
         return baseMapper.deleteByIds(ids) > 0;
     }
diff --git a/ruoyi-modules/ruoyi-generator/pom.xml b/ruoyi-modules/ruoyi-generator/pom.xml
index de34f69..b7fd94f 100644
--- a/ruoyi-modules/ruoyi-generator/pom.xml
+++ b/ruoyi-modules/ruoyi-generator/pom.xml
@@ -47,6 +47,38 @@
             <groupId>org.apache.velocity</groupId>
             <artifactId>velocity-engine-core</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.anyline</groupId>
+            <artifactId>anyline-environment-spring-data-jdbc</artifactId>
+            <version>${anyline.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.anyline</groupId>
+            <artifactId>anyline-data-jdbc-mysql</artifactId>
+            <version>${anyline.version}</version>
+        </dependency>
+
+        <!-- anyline鏀寔100+绉嶇被鍨嬫暟鎹簱 娣诲姞瀵瑰簲鐨刯dbc渚濊禆涓巃nyline瀵瑰簲鏁版嵁搴撲緷璧栧寘鍗冲彲 -->
+<!--        <dependency>-->
+<!--            <groupId>org.anyline</groupId>-->
+<!--            <artifactId>anyline-data-jdbc-oracle</artifactId>-->
+<!--        <version>${anyline.version}</version>-->
+<!--        </dependency>-->
+
+<!--        <dependency>-->
+<!--            <groupId>org.anyline</groupId>-->
+<!--            <artifactId>anyline-data-jdbc-postgresql</artifactId>-->
+<!--        <version>${anyline.version}</version>-->
+<!--        </dependency>-->
+
+<!--        <dependency>-->
+<!--            <groupId>org.anyline</groupId>-->
+<!--            <artifactId>anyline-data-jdbc-mssql</artifactId>-->
+<!--        <version>${anyline.version}</version>-->
+<!--        </dependency>-->
+
     </dependencies>
 
 </project>
diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/MyBatisDataSourceMonitor.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/MyBatisDataSourceMonitor.java
new file mode 100644
index 0000000..8c0f352
--- /dev/null
+++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/MyBatisDataSourceMonitor.java
@@ -0,0 +1,105 @@
+package org.dromara.generator.config;
+
+import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
+import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
+import lombok.extern.slf4j.Slf4j;
+import org.anyline.data.datasource.DataSourceMonitor;
+import org.anyline.data.runtime.DataRuntime;
+import org.anyline.util.ConfigTable;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.datasource.DataSourceUtils;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * anyline 閫傞厤 鍔ㄦ�佹暟鎹簮鏀归��
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@Component
+public class MyBatisDataSourceMonitor implements DataSourceMonitor {
+
+    public MyBatisDataSourceMonitor() {
+        // 璋冩暣鎵ц妯″紡涓鸿嚜瀹氫箟
+        ConfigTable.KEEP_ADAPTER = 2;
+        // 绂佺敤缂撳瓨
+        ConfigTable.METADATA_CACHE_SCOPE = 0;
+    }
+
+    private final Map<String, String> features = new HashMap<>();
+
+    /**
+     * 鏁版嵁婧愮壒寰� 鐢ㄦ潵瀹氬噯 adapter 鍖呭惈鏁版嵁搴撴垨JDBC鍗忚鍏抽敭瀛�<br/>
+     * 涓�鑸細閫氳繃 浜у搧鍚峗url 鍚堟垚 濡傛灉杩斿洖null 涓婂眰鏂规硶浼氶�氳繃driver_浜у搧鍚峗url鍚堟垚
+     *
+     * @param datasource 鏁版嵁婧�
+     * @return String 杩斿洖null鐢变笂灞傝嚜鍔ㄦ彁鍙�
+     */
+    @Override
+    public String feature(DataRuntime runtime, Object datasource) {
+        String feature = null;
+        if (datasource instanceof JdbcTemplate jdbc) {
+            DataSource ds = jdbc.getDataSource();
+            if (ds instanceof DynamicRoutingDataSource) {
+                String key = DynamicDataSourceContextHolder.peek();
+                feature = features.get(key);
+                if (null == feature) {
+                    Connection con = null;
+                    try {
+                        con = DataSourceUtils.getConnection(ds);
+                        DatabaseMetaData meta = con.getMetaData();
+                        String url = meta.getURL();
+                        feature = meta.getDatabaseProductName().toLowerCase().replace(" ", "") + "_" + url;
+                        features.put(key, feature);
+                    } catch (Exception e) {
+                        log.error(e.getMessage(), e);
+                    } finally {
+                        if (null != con && !DataSourceUtils.isConnectionTransactional(con, ds)) {
+                            DataSourceUtils.releaseConnection(con, ds);
+                        }
+                    }
+                }
+            }
+        }
+        return feature;
+    }
+
+    /**
+     * 鏁版嵁婧愬敮涓�鏍囪瘑 濡傛灉涓嶅疄鐜板垯榛樿feature
+     * @param datasource 鏁版嵁婧�
+     * @return String 杩斿洖null鐢变笂灞傝嚜鍔ㄦ彁鍙�
+     */
+    @Override
+    public String key(DataRuntime runtime, Object datasource) {
+        if(datasource instanceof JdbcTemplate jdbc){
+            DataSource ds = jdbc.getDataSource();
+            if(ds instanceof DynamicRoutingDataSource){
+                return DynamicDataSourceContextHolder.peek();
+            }
+        }
+        return runtime.getKey();
+    }
+
+    /**
+     * ConfigTable.KEEP_ADAPTER=2 : 鏍规嵁褰撳墠鎺ュ彛鍒ゆ柇鏄惁淇濇寔鍚屼竴涓暟鎹簮缁戝畾鍚屼竴涓猘dapter<br/>
+     * DynamicRoutingDataSource绫诲瀷鐨勮繑鍥瀎alse,鍥犱负鍚屼竴涓狣ynamicRoutingDataSource鍙兘瀵瑰簲澶氱被鏁版嵁搴�, 濡傛灉椤圭洰涓彧鏈変竴绉嶆暟鎹簱 搴旇鐩存帴杩斿洖true
+     *
+     * @param datasource 鏁版嵁婧�
+     * @return boolean
+     */
+    @Override
+    public boolean keepAdapter(DataRuntime runtime, Object datasource) {
+        if (datasource instanceof JdbcTemplate jdbc) {
+            DataSource ds = jdbc.getDataSource();
+            return !(ds instanceof DynamicRoutingDataSource);
+        }
+        return true;
+    }
+
+}
diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java
index ebdb993..e1560b4 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java
+++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java
@@ -17,7 +17,6 @@
  *
  * @author Lion Li
  */
-
 @Data
 @EqualsAndHashCode(callSuper = true)
 @TableName("gen_table_column")
diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java
index f38d39c..ed8ed20 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java
+++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java
@@ -1,12 +1,8 @@
 package org.dromara.generator.mapper;
 
-import com.baomidou.dynamic.datasource.annotation.DS;
 import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
-import org.apache.ibatis.annotations.Param;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 import org.dromara.generator.domain.GenTableColumn;
-
-import java.util.List;
 
 /**
  * 涓氬姟瀛楁 鏁版嵁灞�
@@ -15,14 +11,5 @@
  */
 @InterceptorIgnore(dataPermission = "true", tenantLine = "true")
 public interface GenTableColumnMapper extends BaseMapperPlus<GenTableColumn, GenTableColumn> {
-    /**
-     * 鏍规嵁琛ㄥ悕绉版煡璇㈠垪淇℃伅
-     *
-     * @param tableName 琛ㄥ悕绉�
-     * @param dataName  鏁版嵁婧愬悕绉�
-     * @return 鍒椾俊鎭�
-     */
-    @DS("#dataName")
-    List<GenTableColumn> selectDbTableColumnsByName(@Param("tableName") String tableName, String dataName);
 
 }
diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java
index c2ff7b6..63f4c15 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java
+++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java
@@ -18,22 +18,6 @@
 public interface GenTableMapper extends BaseMapperPlus<GenTable, GenTable> {
 
     /**
-     * 鏌ヨ鎹簱鍒楄〃
-     *
-     * @param genTable 鏌ヨ鏉′欢
-     * @return 鏁版嵁搴撹〃闆嗗悎
-     */
-    Page<GenTable> selectPageDbTableList(@Param("page") Page<GenTable> page, @Param("genTable") GenTable genTable);
-
-    /**
-     * 鏌ヨ鎹簱鍒楄〃
-     *
-     * @param tableNames 琛ㄥ悕绉扮粍
-     * @return 鏁版嵁搴撹〃闆嗗悎
-     */
-    List<GenTable> selectDbTableListByNames(String[] tableNames);
-
-    /**
      * 鏌ヨ鎵�鏈夎〃淇℃伅
      *
      * @return 琛ㄤ俊鎭泦鍚�
diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java
index 02a9fa7..99935f7 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java
+++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java
@@ -9,15 +9,20 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.anyline.metadata.Column;
+import org.anyline.metadata.Table;
+import org.anyline.proxy.ServiceProxy;
 import org.apache.velocity.Template;
 import org.apache.velocity.VelocityContext;
 import org.apache.velocity.app.Velocity;
 import org.dromara.common.core.constant.Constants;
 import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.SpringUtils;
 import org.dromara.common.core.utils.StreamUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.core.utils.file.FileUtils;
@@ -41,11 +46,7 @@
 import java.io.IOException;
 import java.io.StringWriter;
 import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
@@ -62,6 +63,8 @@
     private final GenTableMapper baseMapper;
     private final GenTableColumnMapper genTableColumnMapper;
     private final IdentifierGenerator identifierGenerator;
+
+    private static final String[] TABLE_IGNORE = new String[]{"sj_", "act_", "flw_", "gen_"};
 
     /**
      * 鏌ヨ涓氬姟瀛楁鍒楄〃
@@ -99,7 +102,7 @@
         Map<String, Object> params = genTable.getParams();
         QueryWrapper<GenTable> wrapper = Wrappers.query();
         wrapper
-            .eq(StringUtils.isNotEmpty(genTable.getDataName()),"data_name", genTable.getDataName())
+            .eq(StringUtils.isNotEmpty(genTable.getDataName()), "data_name", genTable.getDataName())
             .like(StringUtils.isNotBlank(genTable.getTableName()), "lower(table_name)", StringUtils.lowerCase(genTable.getTableName()))
             .like(StringUtils.isNotBlank(genTable.getTableComment()), "lower(table_comment)", StringUtils.lowerCase(genTable.getTableComment()))
             .between(params.get("beginTime") != null && params.get("endTime") != null,
@@ -107,11 +110,67 @@
         return wrapper;
     }
 
+    /**
+     * 鏌ヨ鏁版嵁搴撳垪琛�
+     *
+     * @param genTable  鍖呭惈鏌ヨ鏉′欢鐨凣enTable瀵硅薄
+     * @param pageQuery 鍖呭惈鍒嗛〉淇℃伅鐨凱ageQuery瀵硅薄
+     * @return 鍖呭惈鍒嗛〉缁撴灉鐨凾ableDataInfo瀵硅薄
+     */
     @DS("#genTable.dataName")
     @Override
     public TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery) {
-        genTable.getParams().put("genTableNames",baseMapper.selectTableNameList(genTable.getDataName()));
-        Page<GenTable> page = baseMapper.selectPageDbTableList(pageQuery.build(), genTable);
+        // 鑾峰彇鏌ヨ鏉′欢
+        String tableName = genTable.getTableName();
+        String tableComment = genTable.getTableComment();
+
+        LinkedHashMap<String, Table<?>> tablesMap = ServiceProxy.metadata().tables();
+        if (CollUtil.isEmpty(tablesMap)) {
+            return TableDataInfo.build();
+        }
+        List<String> tableNames = baseMapper.selectTableNameList(genTable.getDataName());
+        String[] tableArrays;
+        if (CollUtil.isNotEmpty(tableNames)) {
+            tableArrays = tableNames.toArray(new String[0]);
+        } else {
+            tableArrays = new String[0];
+        }
+        // 杩囨护骞惰浆鎹㈣〃鏍兼暟鎹�
+        List<GenTable> tables = tablesMap.values().stream()
+            .filter(x -> !StringUtils.containsAnyIgnoreCase(x.getName(), TABLE_IGNORE))
+            .filter(x -> {
+                if (CollUtil.isEmpty(tableNames)) {
+                    return true;
+                }
+                return !StringUtils.equalsAnyIgnoreCase(x.getName(), tableArrays);
+            })
+            .filter(x -> {
+                boolean nameMatches = true;
+                boolean commentMatches = true;
+                // 杩涜琛ㄥ悕绉扮殑妯$硦鏌ヨ
+                if (StringUtils.isNotBlank(tableName)) {
+                    nameMatches = StringUtils.containsIgnoreCase(x.getName(), tableName);
+                }
+                // 杩涜琛ㄦ弿杩扮殑妯$硦鏌ヨ
+                if (StringUtils.isNotBlank(tableComment)) {
+                    commentMatches = StringUtils.containsIgnoreCase(x.getComment(), tableComment);
+                }
+                // 鍚屾椂鍖归厤鍚嶇О鍜屾弿杩�
+                return nameMatches && commentMatches;
+            })
+            .map(x -> {
+                GenTable gen = new GenTable();
+                gen.setTableName(x.getName());
+                gen.setTableComment(x.getComment());
+                gen.setCreateTime(x.getCreateTime());
+                gen.setUpdateTime(x.getUpdateTime());
+                return gen;
+            }).toList();
+
+        IPage<GenTable> page = pageQuery.build();
+        page.setTotal(tables.size());
+        // 鎵嬪姩鍒嗛〉 set鏁版嵁
+        page.setRecords(CollUtil.page((int) page.getCurrent() - 1, (int) page.getSize(), tables));
         return TableDataInfo.build(page);
     }
 
@@ -125,7 +184,29 @@
     @DS("#dataName")
     @Override
     public List<GenTable> selectDbTableListByNames(String[] tableNames, String dataName) {
-        return baseMapper.selectDbTableListByNames(tableNames);
+        Set<String> tableNameSet = new HashSet<>(List.of(tableNames));
+        LinkedHashMap<String, Table<?>> tablesMap = ServiceProxy.metadata().tables();
+
+        if (CollUtil.isEmpty(tablesMap)) {
+            return new ArrayList<>();
+        }
+
+        List<Table<?>> tableList = tablesMap.values().stream()
+            .filter(x -> !StringUtils.containsAnyIgnoreCase(x.getName(), TABLE_IGNORE))
+            .filter(x -> tableNameSet.contains(x.getName())).toList();
+
+        if (CollUtil.isEmpty(tableList)) {
+            return new ArrayList<>();
+        }
+        return tableList.stream().map(x -> {
+            GenTable gen = new GenTable();
+            gen.setDataName(dataName);
+            gen.setTableName(x.getName());
+            gen.setTableComment(x.getComment());
+            gen.setCreateTime(x.getCreateTime());
+            gen.setUpdateTime(x.getUpdateTime());
+            return gen;
+        }).toList();
     }
 
     /**
@@ -187,7 +268,7 @@
                 int row = baseMapper.insert(table);
                 if (row > 0) {
                     // 淇濆瓨鍒椾俊鎭�
-                    List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName, dataName);
+                    List<GenTableColumn> genTableColumns = SpringUtils.getAopProxy(this).selectDbTableColumnsByName(tableName, dataName);
                     List<GenTableColumn> saveColumns = new ArrayList<>();
                     for (GenTableColumn column : genTableColumns) {
                         GenUtils.initColumnField(column, table);
@@ -201,6 +282,32 @@
         } catch (Exception e) {
             throw new ServiceException("瀵煎叆澶辫触锛�" + e.getMessage());
         }
+    }
+
+    /**
+     * 鏍规嵁琛ㄥ悕绉版煡璇㈠垪淇℃伅
+     *
+     * @param tableName 琛ㄥ悕绉�
+     * @param dataName  鏁版嵁婧愬悕绉�
+     * @return 鍒椾俊鎭�
+     */
+    @DS("#dataName")
+    @Override
+    public List<GenTableColumn> selectDbTableColumnsByName(String tableName, String dataName) {
+        LinkedHashMap<String, Column> columns = ServiceProxy.metadata().columns(tableName);
+        List<GenTableColumn> tableColumns = new ArrayList<>();
+        columns.forEach((columnName, column) -> {
+            GenTableColumn tableColumn = new GenTableColumn();
+            tableColumn.setIsPk(String.valueOf(column.isPrimaryKey()));
+            tableColumn.setColumnName(column.getName());
+            tableColumn.setColumnComment(column.getComment());
+            tableColumn.setColumnType(column.getTypeName().toLowerCase());
+            tableColumn.setSort(column.getPosition());
+            tableColumn.setIsRequired(column.isNullable() == 0 ? "1" : "0");
+            tableColumn.setIsIncrement(column.isAutoIncrement() == -1 ? "0" : "1");
+            tableColumns.add(tableColumn);
+        });
+        return tableColumns;
     }
 
     /**
@@ -298,7 +405,7 @@
         List<GenTableColumn> tableColumns = table.getColumns();
         Map<String, GenTableColumn> tableColumnMap = StreamUtils.toIdentityMap(tableColumns, GenTableColumn::getColumnName);
 
-        List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(table.getTableName(), table.getDataName());
+        List<GenTableColumn> dbTableColumns = SpringUtils.getAopProxy(this).selectDbTableColumnsByName(table.getTableName(), table.getDataName());
         if (CollUtil.isEmpty(dbTableColumns)) {
             throw new ServiceException("鍚屾鏁版嵁澶辫触锛屽師琛ㄧ粨鏋勪笉瀛樺湪");
         }
diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/IGenTableService.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/IGenTableService.java
index 2a2fb82..b2c20c5 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/IGenTableService.java
+++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/IGenTableService.java
@@ -86,6 +86,15 @@
     void importGenTable(List<GenTable> tableList, String dataName);
 
     /**
+     * 鏍规嵁琛ㄥ悕绉版煡璇㈠垪淇℃伅
+     *
+     * @param tableName 琛ㄥ悕绉�
+     * @param dataName  鏁版嵁婧愬悕绉�
+     * @return 鍒椾俊鎭�
+     */
+    List<GenTableColumn> selectDbTableColumnsByName(String tableName, String dataName);
+
+    /**
      * 棰勮浠g爜
      *
      * @param tableId 琛ㄧ紪鍙�
diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java
index f5db391..6e111e3 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java
+++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java
@@ -215,6 +215,9 @@
                 importList.add("com.fasterxml.jackson.annotation.JsonFormat");
             } else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) {
                 importList.add("java.math.BigDecimal");
+            } else if (!column.isSuperColumn() && "imageUpload".equals(column.getHtmlType())) {
+                importList.add("org.dromara.common.translation.annotation.Translation");
+                importList.add("org.dromara.common.translation.constant.TransConstant");
             }
         }
         return importList;
diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
index 123d51a..fc1c610 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
+++ b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
@@ -7,87 +7,4 @@
     <resultMap type="org.dromara.generator.domain.GenTableColumn" id="GenTableColumnResult">
     </resultMap>
 
-    <select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult">
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isMySql()">
-            select column_name,
-                   (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else '0' end) as is_required,
-                   (case when column_key = 'PRI' then '1' else '0' end) as is_pk,
-                   ordinal_position as sort,
-                   column_comment,
-                   (case when extra = 'auto_increment' then '1' else '0' end) as is_increment,
-                   column_type
-            from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName})
-            order by ordinal_position
-        </if>
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isOracle()">
-            select lower(temp.column_name) as column_name,
-                    (case when (temp.nullable = 'N'  and  temp.constraint_type != 'P') then '1' else '0' end) as is_required,
-                    (case when temp.constraint_type = 'P' then '1' else '0' end) as is_pk,
-                    temp.column_id as sort,
-                    temp.comments as column_comment,
-                    (case when temp.constraint_type = 'P' then '1' else '0' end) as is_increment,
-                    lower(temp.data_type) as column_type
-            from (
-                select col.column_id, col.column_name,col.nullable, col.data_type, colc.comments, uc.constraint_type, row_number()
-                    over (partition by col.column_name order by uc.constraint_type desc) as row_flg
-                from user_tab_columns col
-                left join user_col_comments colc on colc.table_name = col.table_name and colc.column_name = col.column_name
-                left join user_cons_columns ucc on ucc.table_name = col.table_name and ucc.column_name = col.column_name
-                left join user_constraints uc on uc.constraint_name = ucc.constraint_name
-                where col.table_name = upper(#{tableName})
-            ) temp
-            WHERE temp.row_flg = 1
-            ORDER BY temp.column_id
-        </if>
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isPostgerSql()">
-            SELECT column_name, is_required, is_pk, sort, column_comment, is_increment, column_type
-            FROM (
-                SELECT c.relname AS table_name,
-                       a.attname AS column_name,
-                       d.description AS column_comment,
-                       CASE WHEN a.attnotnull AND con.conname IS NULL THEN 1 ELSE 0
-                       END AS is_required,
-                       CASE WHEN con.conname IS NOT NULL THEN 1 ELSE 0
-                       END AS is_pk,
-                       a.attnum AS sort,
-                       CASE WHEN "position"(pg_get_expr(ad.adbin, ad.adrelid),
-                           ((c.relname::text || '_'::text) || a.attname::text) || '_seq'::text) > 0 THEN 1 ELSE 0
-                       END AS is_increment,
-                       btrim(
-                           CASE WHEN t.typelem <![CDATA[ <> ]]> 0::oid AND t.typlen = '-1'::integer THEN 'ARRAY'::text ELSE
-                                CASE WHEN t.typtype = 'd'::"char" THEN format_type(t.typbasetype, NULL::integer)
-                                ELSE format_type(a.atttypid, NULL::integer) END
-                           END, '"'::text
-                       ) AS column_type
-                FROM pg_attribute a
-                    JOIN (pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid) ON a.attrelid = c.oid
-                    LEFT JOIN pg_description d ON d.objoid = c.oid AND a.attnum = d.objsubid
-                    LEFT JOIN pg_constraint con ON con.conrelid = c.oid AND (a.attnum = ANY (con.conkey))
-                    LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum
-                    LEFT JOIN pg_type t ON a.atttypid = t.oid
-                WHERE (c.relkind = ANY (ARRAY ['r'::"char", 'p'::"char"]))
-                    AND a.attnum > 0
-                    AND n.nspname = 'public'::name
-                ORDER BY c.relname, a.attnum
-            ) temp
-            WHERE table_name = (#{tableName})
-                AND column_type <![CDATA[ <> ]]> '-'
-        </if>
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isSqlServer()">
-            SELECT
-                cast(A.NAME as nvarchar) as column_name,
-                cast(B.NAME as nvarchar) + (case when B.NAME = 'numeric' then '(' + cast(A.prec as nvarchar) + ',' + cast(A.scale as nvarchar) + ')' else '' end) as column_type,
-                cast(G.[VALUE] as nvarchar) as column_comment,
-                (SELECT 1 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE Z WHERE TABLE_NAME = D.NAME and A.NAME = Z.column_name  ) as is_pk,
-                colorder as sort
-            FROM SYSCOLUMNS A
-                LEFT JOIN SYSTYPES B ON A.XTYPE = B.XUSERTYPE
-                INNER JOIN SYSOBJECTS D ON A.ID = D.ID AND D.XTYPE='U' AND D.NAME != 'DTPROPERTIES'
-                LEFT JOIN SYS.EXTENDED_PROPERTIES G ON A.ID = G.MAJOR_ID AND A.COLID = G.MINOR_ID
-                LEFT JOIN SYS.EXTENDED_PROPERTIES F ON D.ID = F.MAJOR_ID AND F.MINOR_ID = 0
-            WHERE D.NAME = #{tableName}
-            ORDER BY A.COLORDER
-        </if>
-    </select>
-
 </mapper>
diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml
index 901bbf0..78aa852 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml
+++ b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml
@@ -14,239 +14,25 @@
         <id property="columnId" column="column_id"/>
     </resultMap>
 
-    <select id="selectPageDbTableList" resultMap="GenTableResult">
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isMySql()">
-            select table_name, table_comment, create_time, update_time
-            from information_schema.tables
-            where table_schema = (select database())
-            AND table_name NOT LIKE 'sj_%' AND table_name NOT LIKE 'gen_%'
-            AND table_name NOT LIKE 'act_%' AND table_name NOT LIKE 'flw_%'
-            <if test="genTable.params.genTableNames != null and genTable.params.genTableNames.size > 0">
-                AND table_name NOT IN
-                <foreach collection="genTable.params.genTableNames" open="(" close=")" separator="," item="item">
-                    #{item}
-                </foreach>
-            </if>
-            <if test="genTable.tableName != null and genTable.tableName != ''">
-                AND lower(table_name) like lower(concat('%', #{genTable.tableName}, '%'))
-            </if>
-            <if test="genTable.tableComment != null and genTable.tableComment != ''">
-                AND lower(table_comment) like lower(concat('%', #{genTable.tableComment}, '%'))
-            </if>
-            order by create_time desc
-        </if>
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isOracle()">
-            select lower(dt.table_name) as table_name, dtc.comments as table_comment, uo.created as create_time, uo.last_ddl_time as update_time
-            from user_tables dt, user_tab_comments dtc, user_objects uo
-            where dt.table_name = dtc.table_name
-            and dt.table_name = uo.object_name
-            and uo.object_type = 'TABLE'
-            AND dt.table_name NOT LIKE 'SJ_%' AND dt.table_name NOT LIKE 'GEN_%'
-            AND dt.table_name NOT LIKE 'ACT_%' AND dt.table_name NOT LIKE 'FLW_%'
-            <if test="genTable.params.genTableNames != null and genTable.params.genTableNames.size > 0">
-                AND lower(dt.table_name) NOT IN
-                <foreach collection="genTable.params.genTableNames" open="(" close=")" separator="," item="item">
-                    #{item}
-                </foreach>
-            </if>
-            <if test="genTable.tableName != null and genTable.tableName != ''">
-                AND lower(dt.table_name) like lower(concat(concat('%', #{genTable.tableName}), '%'))
-            </if>
-            <if test="genTable.tableComment != null and genTable.tableComment != ''">
-                AND lower(dtc.comments) like lower(concat(concat('%', #{genTable.tableComment}), '%'))
-            </if>
-            order by create_time desc
-        </if>
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isPostgerSql()">
-            select table_name, table_comment, create_time, update_time
-            from (
-                SELECT c.relname AS table_name,
-                        obj_description(c.oid) AS table_comment,
-                        CURRENT_TIMESTAMP AS create_time,
-                        CURRENT_TIMESTAMP AS update_time
-                FROM pg_class c
-                    LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
-                WHERE (c.relkind = ANY (ARRAY ['r'::"char", 'p'::"char"]))
-                    AND c.relname != 'spatial_%'::text
-                    AND n.nspname = 'public'::name
-                    AND n.nspname <![CDATA[ <> ]]> ''::name
-            ) list_table
-            where table_name NOT LIKE 'sj_%' AND table_name NOT LIKE 'gen_%'
-            AND table_name NOT LIKE 'act_%' AND table_name NOT LIKE 'flw_%'
-            <if test="genTable.params.genTableNames != null and genTable.params.genTableNames.size > 0">
-                AND table_name NOT IN
-                <foreach collection="genTable.params.genTableNames" open="(" close=")" separator="," item="item">
-                    #{item}
-                </foreach>
-            </if>
-            <if test="genTable.tableName != null and genTable.tableName != ''">
-                AND lower(table_name) like lower(concat('%', #{genTable.tableName}, '%'))
-            </if>
-            <if test="genTable.tableComment != null and genTable.tableComment != ''">
-                AND lower(table_comment) like lower(concat('%', #{genTable.tableComment}, '%'))
-            </if>
-            order by create_time desc
-        </if>
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isSqlServer()">
-            SELECT cast(D.NAME as nvarchar) as table_name,
-                   cast(F.VALUE as nvarchar) as table_comment,
-                   crdate as create_time,
-                   refdate as update_time
-            FROM SYSOBJECTS D
-                INNER JOIN SYS.EXTENDED_PROPERTIES F ON D.ID = F.MAJOR_ID
-                    AND F.MINOR_ID = 0 AND D.XTYPE = 'U' AND D.NAME != 'DTPROPERTIES'
-                    AND D.NAME NOT LIKE 'sj_%' AND D.NAME NOT LIKE 'gen_%'
-                    AND D.NAME NOT LIKE 'act_%' AND D.NAME NOT LIKE 'flw_%'
-            <if test="genTable.params.genTableNames != null and genTable.params.genTableNames.size > 0">
-                AND D.NAME NOT IN
-                <foreach collection="genTable.params.genTableNames" open="(" close=")" separator="," item="item">
-                    #{item}
-                </foreach>
-            </if>
-            <if test="genTable.tableName != null and genTable.tableName != ''">
-                AND lower(D.NAME) like lower(concat(N'%', N'${genTable.tableName}', N'%'))
-            </if>
-            <if test="genTable.tableComment != null and genTable.tableComment != ''">
-                AND lower(CAST(F.VALUE AS nvarchar)) like lower(concat(N'%', N'${genTable.tableComment}', N'%'))
-            </if>
-            order by crdate desc
-        </if>
-    </select>
-
-    <select id="selectDbTableListByNames" resultMap="GenTableResult">
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isMySql()">
-            select table_name, table_comment, create_time, update_time from information_schema.tables
-            where table_schema = (select database())
-            and table_name NOT LIKE 'sj_%' and table_name NOT LIKE 'gen_%'
-            and table_name NOT LIKE 'act_%' AND table_name NOT LIKE 'flw_%'
-            and table_name in
-            <foreach collection="array" item="name" open="(" separator="," close=")">
-                 #{name}
-            </foreach>
-        </if>
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isOracle()">
-            select lower(dt.table_name) as table_name, dtc.comments as table_comment, uo.created as create_time, uo.last_ddl_time as update_time
-            from user_tables dt, user_tab_comments dtc, user_objects uo
-            where dt.table_name = dtc.table_name
-            and dt.table_name = uo.object_name
-            and uo.object_type = 'TABLE'
-            and dt.table_name NOT LIKE 'SJ_%' AND dt.table_name NOT LIKE 'GEN_%'
-            and dt.table_name NOT LIKE 'ACT_%' AND dt.table_name NOT LIKE 'FLW_%'
-            and lower(dt.table_name) in
-            <foreach collection="array" item="name" open="(" separator="," close=")">
-                #{name}
-            </foreach>
-        </if>
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isPostgerSql()">
-            select table_name, table_comment, create_time, update_time
-            from (
-                SELECT c.relname AS table_name,
-                        obj_description(c.oid) AS table_comment,
-                        CURRENT_TIMESTAMP AS create_time,
-                        CURRENT_TIMESTAMP AS update_time
-                FROM pg_class c
-                    LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
-                WHERE (c.relkind = ANY (ARRAY ['r'::"char", 'p'::"char"]))
-                    AND c.relname != 'spatial_%'::text
-                    AND n.nspname = 'public'::name
-                    AND n.nspname <![CDATA[ <> ]]> ''::name
-            ) list_table
-            where table_name NOT LIKE 'sj_%' and table_name NOT LIKE 'gen_%'
-            and table_name NOT LIKE 'act_%' and table_name NOT LIKE 'flw_%'
-            and table_name in
-            <foreach collection="array" item="name" open="(" separator="," close=")">
-                #{name}
-            </foreach>
-        </if>
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isSqlServer()">
-            SELECT cast(D.NAME as nvarchar) as table_name,
-                   cast(F.VALUE as nvarchar) as table_comment,
-                   crdate as create_time,
-                   refdate as update_time
-            FROM SYSOBJECTS D
-                INNER JOIN SYS.EXTENDED_PROPERTIES F ON D.ID = F.MAJOR_ID
-                    AND F.MINOR_ID = 0 AND D.XTYPE = 'U' AND D.NAME != 'DTPROPERTIES'
-                    AND D.NAME NOT LIKE 'sj_%' AND D.NAME NOT LIKE 'gen_%'
-                    AND D.NAME NOT LIKE 'act_%' AND D.NAME NOT LIKE 'flw_%'
-                    AND D.NAME in
-                    <foreach collection="array" item="name" open="(" separator="," close=")">
-                        #{name}
-                    </foreach>
-        </if>
-    </select>
-
-    <select id="selectTableByName" parameterType="String" resultMap="GenTableResult">
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isMySql()">
-            select table_name, table_comment, create_time, update_time from information_schema.tables
-            where table_schema = (select database())
-            and table_name NOT LIKE 'sj_%' and table_name NOT LIKE 'gen_%'
-            and table_name NOT LIKE 'act_%' AND table_name NOT LIKE 'flw_%'
-            and table_name = #{tableName}
-        </if>
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isOracle()">
-            select lower(dt.table_name) as table_name, dtc.comments as table_comment, uo.created as create_time, uo.last_ddl_time as update_time
-            from user_tables dt, user_tab_comments dtc, user_objects uo
-            where dt.table_name = dtc.table_name
-            and dt.table_name = uo.object_name
-            and uo.object_type = 'TABLE'
-            AND dt.table_name NOT LIKE 'SJ_%' AND dt.table_name NOT LIKE 'GEN_%'
-            AND dt.table_name NOT LIKE 'ACT_%' AND dt.table_name NOT LIKE 'FLW_%'
-            AND dt.table_name NOT IN (select table_name from gen_table)
-            and lower(dt.table_name) = #{tableName}
-        </if>
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isPostgerSql()">
-            select table_name, table_comment, create_time, update_time
-            from (
-                SELECT c.relname AS table_name,
-                        obj_description(c.oid) AS table_comment,
-                        CURRENT_TIMESTAMP AS create_time,
-                        CURRENT_TIMESTAMP AS update_time
-                FROM pg_class c
-                    LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
-                WHERE (c.relkind = ANY (ARRAY ['r'::"char", 'p'::"char"]))
-                    AND c.relname != 'spatial_%'::text
-                    AND n.nspname = 'public'::name
-                    AND n.nspname <![CDATA[ <> ]]> ''::name
-            ) list_table
-            where table_name NOT LIKE 'sj_%' and table_name NOT LIKE 'gen_%'
-            and table_name NOT LIKE 'act_%' and table_name NOT LIKE 'flw_%'
-            and table_name = #{tableName}
-        </if>
-        <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isSqlServer()">
-            SELECT cast(D.NAME as nvarchar) as table_name,
-                   cast(F.VALUE as nvarchar) as table_comment,
-                   crdate as create_time,
-                   refdate as update_time
-            FROM SYSOBJECTS D
-                INNER JOIN SYS.EXTENDED_PROPERTIES F ON D.ID = F.MAJOR_ID
-                    AND F.MINOR_ID = 0 AND D.XTYPE = 'U' AND D.NAME != 'DTPROPERTIES'
-                    AND D.NAME NOT LIKE 'sj_%' AND D.NAME NOT LIKE 'gen_%'
-                    AND D.NAME NOT LIKE 'act_%' AND D.NAME NOT LIKE 'flw_%'
-                    AND D.NAME = #{tableName}
-        </if>
-    </select>
-
-    <select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult">
+    <sql id="genSelect">
         SELECT t.table_id, t.data_name, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
                c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
         FROM gen_table t
-             LEFT JOIN gen_table_column c ON t.table_id = c.table_id
+                 LEFT JOIN gen_table_column c ON t.table_id = c.table_id
+    </sql>
+
+    <select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult">
+        <include refid="genSelect"/>
         where t.table_id = #{tableId} order by c.sort
     </select>
 
     <select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult">
-        SELECT t.table_id, t.data_name, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
-               c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
-        FROM gen_table t
-             LEFT JOIN gen_table_column c ON t.table_id = c.table_id
+        <include refid="genSelect"/>
         where t.table_name = #{tableName} order by c.sort
     </select>
 
     <select id="selectGenTableAll" parameterType="String" resultMap="GenTableResult">
-        SELECT t.table_id, t.data_name, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
-               c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
-        FROM gen_table t
-             LEFT JOIN gen_table_column c ON t.table_id = c.table_id
+        <include refid="genSelect"/>
         order by c.sort
     </select>
 
diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
index f99a2ed..c896afb 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
+++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
@@ -53,6 +53,13 @@
 #end
     private $column.javaType $column.javaField;
 
+#if($column.htmlType == "imageUpload")
+    /**
+     * ${column.columnComment}Url
+     */
+    @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "${column.javaField}")
+    private String ${column.javaField}Url";
+#end
 #end
 #end
 
diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm
index c3f6ed1..35a468e 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm
+++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm
@@ -9,6 +9,12 @@
                         #elseif($column.javaType == 'Boolean') boolean;
                         #else string;
                     #end
+#if($column.htmlType == "imageUpload")
+  /**
+   * ${column.columnComment}Url
+   */
+  ${column.javaField}Url: string;
+#end
 #end
 #end
 #if ($table.tree)
diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
index d13ef2f..caf3472 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
+++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
@@ -99,9 +99,9 @@
           </template>
         </el-table-column>
 #elseif($column.list && $column.htmlType == "imageUpload")
-        <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
+        <el-table-column label="${comment}" align="center" prop="${javaField}Url" width="100">
           <template #default="scope">
-            <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
+            <image-preview :src="scope.row.${javaField}Url" :width="50" :height="50"/>
           </template>
         </el-table-column>
 #elseif($column.list && $column.dictType && "" != $column.dictType)
diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
index 886f4ab..a92d19a 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
+++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
@@ -101,9 +101,9 @@
           </template>
         </el-table-column>
 #elseif($column.list && $column.htmlType == "imageUpload")
-        <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
+        <el-table-column label="${comment}" align="center" prop="${javaField}Url" width="100">
           <template #default="scope">
-            <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
+            <image-preview :src="scope.row.${javaField}Url" :width="50" :height="50"/>
           </template>
         </el-table-column>
 #elseif($column.list && $column.dictType && "" != $column.dictType)
diff --git a/ruoyi-modules/ruoyi-system/pom.xml b/ruoyi-modules/ruoyi-system/pom.xml
index acf33ce..0fc6d55 100644
--- a/ruoyi-modules/ruoyi-system/pom.xml
+++ b/ruoyi-modules/ruoyi-system/pom.xml
@@ -95,6 +95,11 @@
             <artifactId>ruoyi-common-websocket</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-sse</artifactId>
+        </dependency>
+
     </dependencies>
 
 </project>
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java
index 18e32d8..98ac2d5 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java
@@ -1,7 +1,9 @@
 package org.dromara.system.controller.monitor;
 
 import cn.dev33.satoken.annotation.SaCheckPermission;
-import org.dromara.common.core.constant.GlobalConstants;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheConstants;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.excel.utils.ExcelUtil;
 import org.dromara.common.log.annotation.Log;
@@ -13,8 +15,6 @@
 import org.dromara.system.domain.bo.SysLogininforBo;
 import org.dromara.system.domain.vo.SysLogininforVo;
 import org.dromara.system.service.ISysLogininforService;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.RequiredArgsConstructor;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
@@ -79,7 +79,7 @@
     @Log(title = "璐︽埛瑙i攣", businessType = BusinessType.OTHER)
     @GetMapping("/unlock/{userName}")
     public R<Void> unlock(@PathVariable("userName") String userName) {
-        String loginName = GlobalConstants.PWD_ERR_CNT_KEY + userName;
+        String loginName = CacheConstants.PWD_ERR_CNT_KEY + userName;
         if (RedisUtils.hasKey(loginName)) {
             RedisUtils.deleteObject(loginName);
         }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java
index 4f5f23f..968bbe9 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java
@@ -12,6 +12,7 @@
 import org.dromara.system.domain.bo.SysDeptBo;
 import org.dromara.system.domain.vo.SysDeptVo;
 import org.dromara.system.service.ISysDeptService;
+import org.dromara.system.service.ISysPostService;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
@@ -29,6 +30,7 @@
 public class SysDeptController extends BaseController {
 
     private final ISysDeptService deptService;
+    private final ISysPostService postService;
 
     /**
      * 鑾峰彇閮ㄩ棬鍒楄〃
@@ -117,6 +119,9 @@
         if (deptService.checkDeptExistUser(deptId)) {
             return R.warn("閮ㄩ棬瀛樺湪鐢ㄦ埛,涓嶅厑璁稿垹闄�");
         }
+        if (postService.countPostByDeptId(deptId) > 0) {
+            return R.warn("閮ㄩ棬瀛樺湪宀椾綅,涓嶅厑璁稿垹闄�");
+        }
         deptService.checkDeptDataScope(deptId);
         return toAjax(deptService.deleteDeptById(deptId));
     }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java
index a0aa26e..5d65137 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java
@@ -8,8 +8,8 @@
 import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.sse.utils.SseMessageUtils;
 import org.dromara.common.web.core.BaseController;
-import org.dromara.common.websocket.utils.WebSocketUtils;
 import org.dromara.system.domain.bo.SysNoticeBo;
 import org.dromara.system.domain.vo.SysNoticeVo;
 import org.dromara.system.service.ISysNoticeService;
@@ -62,7 +62,7 @@
             return R.fail();
         }
         String type = dictService.getDictLabel("sys_notice_type", notice.getNoticeType());
-        WebSocketUtils.publishAll("[" + type + "] " + notice.getNoticeTitle());
+        SseMessageUtils.publishAll("[" + type + "] " + notice.getNoticeTitle());
         return R.ok();
     }
 
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java
index 559e1d5..893b381 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java
@@ -11,6 +11,7 @@
 import org.dromara.common.idempotent.annotation.RepeatSubmit;
 import org.dromara.common.log.annotation.Log;
 import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.helper.DataPermissionHelper;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.common.web.core.BaseController;
 import org.dromara.system.domain.bo.SysUserBo;
@@ -72,7 +73,8 @@
         if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
             return R.fail("淇敼鐢ㄦ埛'" + username + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
         }
-        if (userService.updateUserProfile(user) > 0) {
+        int rows = DataPermissionHelper.ignore(() -> userService.updateUserProfile(user));
+        if (rows > 0) {
             return R.ok();
         }
         return R.fail("淇敼涓汉淇℃伅寮傚父锛岃鑱旂郴绠$悊鍛�");
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java
index 60be68a..bad240c 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java
@@ -24,6 +24,7 @@
 import org.dromara.system.domain.bo.SysTenantBo;
 import org.dromara.system.domain.vo.SysTenantVo;
 import org.dromara.system.service.ISysTenantService;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
@@ -38,6 +39,7 @@
 @RequiredArgsConstructor
 @RestController
 @RequestMapping("/system/tenant")
+@ConditionalOnProperty(value = "tenant.enable", havingValue = "true")
 public class SysTenantController extends BaseController {
 
     private final ISysTenantService tenantService;
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java
index 7d99916..4bfe597 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java
@@ -20,6 +20,7 @@
 import jakarta.validation.constraints.NotEmpty;
 import jakarta.validation.constraints.NotNull;
 import lombok.RequiredArgsConstructor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
@@ -34,6 +35,7 @@
 @RequiredArgsConstructor
 @RestController
 @RequestMapping("/system/tenant/package")
+@ConditionalOnProperty(value = "tenant.enable", havingValue = "true")
 public class SysTenantPackageController extends BaseController {
 
     private final ISysTenantPackageService tenantPackageService;
@@ -92,6 +94,9 @@
     @RepeatSubmit()
     @PostMapping()
     public R<Void> add(@Validated(AddGroup.class) @RequestBody SysTenantPackageBo bo) {
+        if (!tenantPackageService.checkPackageNameUnique(bo)) {
+            return R.fail("鏂板濂楅'" + bo.getPackageName() + "'澶辫触锛屽椁愬悕绉板凡瀛樺湪");
+        }
         return toAjax(tenantPackageService.insertByBo(bo));
     }
 
@@ -104,6 +109,9 @@
     @RepeatSubmit()
     @PutMapping()
     public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysTenantPackageBo bo) {
+        if (!tenantPackageService.checkPackageNameUnique(bo)) {
+            return R.fail("淇敼濂楅'" + bo.getPackageName() + "'澶辫触锛屽椁愬悕绉板凡瀛樺湪");
+        }
         return toAjax(tenantPackageService.updateByBo(bo));
     }
 
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java
index d1f4059..86249d2 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java
@@ -61,13 +61,13 @@
     /**
      * 鐢ㄦ埛閭
      */
-    @Sensitive(strategy = SensitiveStrategy.EMAIL)
+    @Sensitive(strategy = SensitiveStrategy.EMAIL, perms = "system:user:edit")
     private String email;
 
     /**
      * 鎵嬫満鍙风爜
      */
-    @Sensitive(strategy = SensitiveStrategy.PHONE)
+    @Sensitive(strategy = SensitiveStrategy.PHONE, perms = "system:user:edit")
     private String phonenumber;
 
     /**
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java
index c43f039..3751b23 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java
@@ -81,6 +81,14 @@
     long countUserPostById(Long postId);
 
     /**
+     * 閫氳繃閮ㄩ棬ID鏌ヨ宀椾綅浣跨敤鏁伴噺
+     *
+     * @param deptId 閮ㄩ棬id
+     * @return 缁撴灉
+     */
+    long countPostByDeptId(Long deptId);
+
+    /**
      * 鍒犻櫎宀椾綅淇℃伅
      *
      * @param postId 宀椾綅ID
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java
index cdb887c..d060b68 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java
@@ -1,9 +1,9 @@
 package org.dromara.system.service;
 
-import org.dromara.system.domain.vo.SysTenantPackageVo;
-import org.dromara.system.domain.bo.SysTenantPackageBo;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysTenantPackageBo;
+import org.dromara.system.domain.vo.SysTenantPackageVo;
 
 import java.util.Collection;
 import java.util.List;
@@ -46,6 +46,11 @@
     Boolean updateByBo(SysTenantPackageBo bo);
 
     /**
+     * 鏍¢獙濂楅鍚嶇О鏄惁鍞竴
+     */
+    boolean checkPackageNameUnique(SysTenantPackageBo bo);
+
+    /**
      * 淇敼濂楅鐘舵��
      */
     int updatePackageStatus(SysTenantPackageBo bo);
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java
index a31c426..018f9a0 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java
@@ -2,6 +2,7 @@
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import lombok.RequiredArgsConstructor;
 import org.dromara.common.core.utils.StreamUtils;
@@ -38,6 +39,9 @@
      */
     @Override
     public String getRoleCustom(Long roleId) {
+        if (ObjectUtil.isNull(roleId)) {
+            return "-1";
+        }
         List<SysRoleDept> list = roleDeptMapper.selectList(
             new LambdaQueryWrapper<SysRoleDept>()
                 .select(SysRoleDept::getDeptId)
@@ -45,7 +49,7 @@
         if (CollUtil.isNotEmpty(list)) {
             return StreamUtils.join(list, rd -> Convert.toStr(rd.getDeptId()));
         }
-        return null;
+        return "-1";
     }
 
     /**
@@ -56,6 +60,9 @@
      */
     @Override
     public String getDeptAndChild(Long deptId) {
+        if (ObjectUtil.isNull(deptId)) {
+            return "-1";
+        }
         List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
             .select(SysDept::getDeptId)
             .apply(DataBaseHelper.findInSet(deptId, "ancestors")));
@@ -64,7 +71,7 @@
         if (CollUtil.isNotEmpty(ids)) {
             return StreamUtils.join(ids, Convert::toStr);
         }
-        return null;
+        return "-1";
     }
 
 }
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
index 5054036..160238d 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
@@ -78,7 +78,7 @@
 
     private LambdaQueryWrapper<SysDept> buildQueryWrapper(SysDeptBo bo) {
         LambdaQueryWrapper<SysDept> lqw = Wrappers.lambdaQuery();
-        lqw.eq(SysDept::getDelFlag, "0");
+        lqw.eq(SysDept::getDelFlag, UserConstants.DEL_FLAG_NORMAL);
         lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), SysDept::getDeptId, bo.getDeptId());
         lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), SysDept::getParentId, bo.getParentId());
         lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysDept::getDeptName, bo.getDeptName());
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java
index d167e8d..1866531 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java
@@ -77,8 +77,9 @@
     @Override
     public List<SysOssVo> listByIds(Collection<Long> ossIds) {
         List<SysOssVo> list = new ArrayList<>();
+        SysOssServiceImpl ossService = SpringUtils.getAopProxy(this);
         for (Long id : ossIds) {
-            SysOssVo vo = SpringUtils.getAopProxy(this).getById(id);
+            SysOssVo vo = ossService.getById(id);
             if (ObjectUtil.isNotNull(vo)) {
                 try {
                     list.add(this.matchingUrl(vo));
@@ -100,8 +101,9 @@
     @Override
     public String selectUrlByIds(String ossIds) {
         List<String> list = new ArrayList<>();
+        SysOssServiceImpl ossService = SpringUtils.getAopProxy(this);
         for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) {
-            SysOssVo vo = SpringUtils.getAopProxy(this).getById(id);
+            SysOssVo vo = ossService.getById(id);
             if (ObjectUtil.isNotNull(vo)) {
                 try {
                     list.add(this.matchingUrl(vo).getUrl());
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
index b8a7e60..2c38129 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
@@ -178,6 +178,17 @@
     }
 
     /**
+     * 閫氳繃閮ㄩ棬ID鏌ヨ宀椾綅浣跨敤鏁伴噺
+     *
+     * @param deptId 閮ㄩ棬id
+     * @return 缁撴灉
+     */
+    @Override
+    public long countPostByDeptId(Long deptId) {
+        return baseMapper.selectCount(new LambdaQueryWrapper<SysPost>().eq(SysPost::getDeptId, deptId));
+    }
+
+    /**
      * 鍒犻櫎宀椾綅淇℃伅
      *
      * @param postId 宀椾綅ID
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
index 31f9498..9b8b0ec 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
@@ -293,6 +293,10 @@
     @Transactional(rollbackFor = Exception.class)
     public int updateRole(SysRoleBo bo) {
         SysRole role = MapstructUtils.convert(bo, SysRole.class);
+
+        if (UserConstants.ROLE_DISABLE.equals(role.getStatus()) && this.countUserRoleByRoleId(role.getRoleId()) > 0) {
+            throw new ServiceException("瑙掕壊宸插垎閰嶏紝涓嶈兘绂佺敤!");
+        }
         // 淇敼瑙掕壊淇℃伅
         baseMapper.updateById(role);
         // 鍒犻櫎瑙掕壊涓庤彍鍗曞叧鑱�
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java
index 5fd04af..d2a72f6 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java
@@ -1,6 +1,7 @@
 package org.dromara.system.service.impl;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -117,6 +118,17 @@
     }
 
     /**
+     * 鏍¢獙濂楅鍚嶇О鏄惁鍞竴
+     */
+    @Override
+    public boolean checkPackageNameUnique(SysTenantPackageBo bo) {
+        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysTenantPackage>()
+            .eq(SysTenantPackage::getPackageName, bo.getPackageName())
+            .ne(ObjectUtil.isNotNull(bo.getPackageId()), SysTenantPackage::getPackageId, bo.getPackageId()));
+        return !exist;
+    }
+
+    /**
      * 淇敼濂楅鐘舵��
      *
      * @param bo 濂楅淇℃伅
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
index 3cb4159..2540606 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
@@ -26,10 +26,7 @@
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.mybatis.helper.DataBaseHelper;
 import org.dromara.common.satoken.utils.LoginHelper;
-import org.dromara.system.domain.SysDept;
-import org.dromara.system.domain.SysUser;
-import org.dromara.system.domain.SysUserPost;
-import org.dromara.system.domain.SysUserRole;
+import org.dromara.system.domain.*;
 import org.dromara.system.domain.bo.SysUserBo;
 import org.dromara.system.domain.vo.SysPostVo;
 import org.dromara.system.domain.vo.SysRoleVo;
@@ -473,17 +470,14 @@
      */
     private void insertUserRole(Long userId, Long[] roleIds, boolean clear) {
         if (ArrayUtil.isNotEmpty(roleIds)) {
-            // 鍒ゆ柇鏄惁鍏锋湁姝よ鑹茬殑鎿嶄綔鏉冮檺
-            List<SysRoleVo> roles = roleMapper.selectRoleList(new LambdaQueryWrapper<>());
-            if (CollUtil.isEmpty(roles)) {
-                throw new ServiceException("娌℃湁鏉冮檺璁块棶瑙掕壊鐨勬暟鎹�");
-            }
-            List<Long> roleList = StreamUtils.toList(roles, SysRoleVo::getRoleId);
+            List<Long> roleList = new ArrayList<>(List.of(roleIds));
             if (!LoginHelper.isSuperAdmin(userId)) {
                 roleList.remove(UserConstants.SUPER_ADMIN_ID);
             }
-            List<Long> canDoRoleList = StreamUtils.filter(List.of(roleIds), roleList::contains);
-            if (CollUtil.isEmpty(canDoRoleList)) {
+            // 鍒ゆ柇鏄惁鍏锋湁姝よ鑹茬殑鎿嶄綔鏉冮檺
+            List<SysRoleVo> roles = roleMapper.selectRoleList(
+                new QueryWrapper<SysRole>().in("r.role_id", roleList));
+            if (CollUtil.isEmpty(roles)) {
                 throw new ServiceException("娌℃湁鏉冮檺璁块棶瑙掕壊鐨勬暟鎹�");
             }
             if (clear) {
@@ -491,7 +485,7 @@
                 userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId));
             }
             // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
-            List<SysUserRole> list = StreamUtils.toList(canDoRoleList, roleId -> {
+            List<SysUserRole> list = StreamUtils.toList(roleList, roleId -> {
                 SysUserRole ur = new SysUserRole();
                 ur.setUserId(userId);
                 ur.setRoleId(roleId);
@@ -640,7 +634,7 @@
             return List.of();
         }
         List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
-            .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName)
+            .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber)
             .eq(SysUser::getStatus, UserConstants.USER_NORMAL)
             .in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds));
         return BeanUtil.copyToList(list, UserDTO.class);
@@ -653,4 +647,26 @@
         return StreamUtils.toList(userRoles, SysUserRole::getUserId);
     }
 
+    @Override
+    public List<UserDTO> selectUsersByRoleIds(List<Long> roleIds) {
+        if (CollUtil.isEmpty(roleIds)) {
+            return List.of();
+        }
+        List<SysUserRole> userRoles = userRoleMapper.selectList(
+            new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds));
+        List<Long> userIds = StreamUtils.toList(userRoles, SysUserRole::getUserId);
+        return selectListByIds(userIds);
+    }
+
+    @Override
+    public List<UserDTO> selectUsersByDeptIds(List<Long> deptIds) {
+        if (CollUtil.isEmpty(deptIds)) {
+            return List.of();
+        }
+        List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
+            .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber)
+            .eq(SysUser::getStatus, UserConstants.USER_NORMAL)
+            .in(CollUtil.isNotEmpty(deptIds), SysUser::getDeptId, deptIds));
+        return BeanUtil.copyToList(list, UserDTO.class);
+    }
 }
diff --git a/ruoyi-modules/ruoyi-workflow/pom.xml b/ruoyi-modules/ruoyi-workflow/pom.xml
index 9ed4097..e55839e 100644
--- a/ruoyi-modules/ruoyi-workflow/pom.xml
+++ b/ruoyi-modules/ruoyi-workflow/pom.xml
@@ -57,7 +57,7 @@
         <dependency>
             <groupId>org.apache.xmlgraphics</groupId>
             <artifactId>batik-all</artifactId>
-            <version>1.10</version>
+            <version>1.17</version>
             <exclusions>
                 <exclusion>
                     <groupId>xalan</groupId>
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java
index 3332f86..842d3d6 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java
@@ -18,6 +18,7 @@
 import org.dromara.workflow.service.IActModelService;
 import org.flowable.engine.RepositoryService;
 import org.flowable.engine.repository.Model;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
@@ -36,8 +37,8 @@
 @RequestMapping("/workflow/model")
 public class ActModelController extends BaseController {
 
-    private final RepositoryService repositoryService;
-
+    @Autowired(required = false)
+    private RepositoryService repositoryService;
     private final IActModelService actModelService;
 
 
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java
index 75f9d9b..25724b6 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java
@@ -21,6 +21,7 @@
 import org.dromara.workflow.service.IWfTaskBackNodeService;
 import org.dromara.workflow.utils.QueryUtils;
 import org.flowable.engine.TaskService;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
@@ -38,10 +39,9 @@
 @RequestMapping("/workflow/task")
 public class ActTaskController extends BaseController {
 
+    @Autowired(required = false)
+    private TaskService taskService;
     private final IActTaskService actTaskService;
-
-    private final TaskService taskService;
-
     private final IWfTaskBackNodeService wfTaskBackNodeService;
 
 
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java
index d4f696b..217538e 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java
@@ -39,6 +39,7 @@
 import org.flowable.engine.repository.ModelQuery;
 import org.flowable.engine.repository.ProcessDefinition;
 import org.flowable.validation.ValidationError;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -65,7 +66,8 @@
 @Service
 public class ActModelServiceImpl implements IActModelService {
 
-    private final RepositoryService repositoryService;
+    @Autowired(required = false)
+    private RepositoryService repositoryService;
     private final IWfNodeConfigService wfNodeConfigService;
     private final IWfDefinitionConfigService wfDefinitionConfigService;
 
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java
index 6a17289..77fb257 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java
@@ -37,6 +37,7 @@
 import org.flowable.engine.history.HistoricProcessInstance;
 import org.flowable.engine.impl.bpmn.deployer.ResourceNameUtil;
 import org.flowable.engine.repository.*;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
@@ -61,8 +62,10 @@
 @Service
 public class ActProcessDefinitionServiceImpl implements IActProcessDefinitionService {
 
-    private final RepositoryService repositoryService;
-    private final ProcessMigrationService processMigrationService;
+    @Autowired(required = false)
+    private RepositoryService repositoryService;
+    @Autowired(required = false)
+    private ProcessMigrationService processMigrationService;
     private final IWfCategoryService wfCategoryService;
     private final IWfDefinitionConfigService wfDefinitionConfigService;
     private final WfDefinitionConfigMapper wfDefinitionConfigMapper;
@@ -288,6 +291,7 @@
                 Model modelData = repositoryService.newModel();
                 modelData.setKey(pd.getKey());
                 modelData.setName(pd.getName());
+                modelData.setCategory(pd.getCategory());
                 modelData.setTenantId(pd.getTenantId());
                 repositoryService.saveModel(modelData);
                 repositoryService.addModelEditorSource(modelData.getId(), IoUtil.readBytes(inputStream));
@@ -350,8 +354,7 @@
             initWfDefConfig();
         } else {
             String originalFilename = file.getOriginalFilename();
-            String bpmnResourceSuffix = ResourceNameUtil.BPMN_RESOURCE_SUFFIXES[0];
-            if (originalFilename.contains(bpmnResourceSuffix)) {
+            if (StringUtils.containsAny(originalFilename, ResourceNameUtil.BPMN_RESOURCE_SUFFIXES)) {
                 // 鏂囦欢鍚� = 娴佺▼鍚嶇О-娴佺▼key
                 String[] splitFilename = originalFilename.substring(0, originalFilename.lastIndexOf(".")).split("-");
                 if (splitFilename.length < 2) {
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java
index e22e800..8b9b113 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java
@@ -48,6 +48,7 @@
 import org.flowable.task.api.Task;
 import org.flowable.task.api.history.HistoricTaskInstance;
 import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -68,12 +69,17 @@
 @Service
 public class ActProcessInstanceServiceImpl implements IActProcessInstanceService {
 
-    private final RepositoryService repositoryService;
-    private final RuntimeService runtimeService;
-    private final HistoryService historyService;
-    private final TaskService taskService;
+    @Autowired(required = false)
+    private RepositoryService repositoryService;
+    @Autowired(required = false)
+    private RuntimeService runtimeService;
+    @Autowired(required = false)
+    private HistoryService historyService;
+    @Autowired(required = false)
+    private TaskService taskService;
+    @Autowired(required = false)
+    private ManagementService managementService;
     private final IActHiProcinstService actHiProcinstService;
-    private final ManagementService managementService;
     private final IWfTaskBackNodeService wfTaskBackNodeService;
     private final IWfNodeConfigService wfNodeConfigService;
     private final FlowProcessEventHandler flowProcessEventHandler;
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java
index 32e6aec..5235d12 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java
@@ -52,6 +52,7 @@
 import org.flowable.task.api.history.HistoricTaskInstance;
 import org.flowable.task.service.impl.persistence.entity.TaskEntity;
 import org.flowable.variable.api.persistence.entity.VariableInstance;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -71,11 +72,16 @@
 @Service
 public class ActTaskServiceImpl implements IActTaskService {
 
-    private final RuntimeService runtimeService;
-    private final TaskService taskService;
-    private final HistoryService historyService;
-    private final IdentityService identityService;
-    private final ManagementService managementService;
+    @Autowired(required = false)
+    private RuntimeService runtimeService;
+    @Autowired(required = false)
+    private TaskService taskService;
+    @Autowired(required = false)
+    private HistoryService historyService;
+    @Autowired(required = false)
+    private IdentityService identityService;
+    @Autowired(required = false)
+    private ManagementService managementService;
     private final ActTaskMapper actTaskMapper;
     private final IWfTaskBackNodeService wfTaskBackNodeService;
     private final ActHiTaskinstMapper actHiTaskinstMapper;
@@ -261,7 +267,7 @@
         queryWrapper.eq("t.business_status_", BusinessStatusEnum.WAITING.getStatus());
         queryWrapper.eq(TenantHelper.isEnable(), "t.tenant_id_", TenantHelper.getTenantId());
         String ids = StreamUtils.join(roleIds, x -> "'" + x + "'");
-        queryWrapper.and(w1 -> w1.eq("t.assignee_", userId).or(w2 -> w2.isNull("t.assignee_").apply("exists ( select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TASK_ID_ = t.ID_ and LINK.TYPE_ = 'candidate' and (LINK.USER_ID_ = {0} or ( LINK.GROUP_ID_ IN ({1}) ) ))", userId, ids)));
+        queryWrapper.and(w1 -> w1.eq("t.assignee_", userId).or(w2 -> w2.isNull("t.assignee_").apply("exists ( select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TASK_ID_ = t.ID_ and LINK.TYPE_ = 'candidate' and (LINK.USER_ID_ = {0} or ( LINK.GROUP_ID_ IN (" + ids + ") ) ))", userId)));
         if (StringUtils.isNotBlank(taskBo.getName())) {
             queryWrapper.like("t.name_", taskBo.getName());
         }
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java
index b498262..e562823 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java
@@ -15,6 +15,7 @@
 import org.flowable.engine.repository.Deployment;
 import org.flowable.engine.repository.Model;
 import org.flowable.engine.repository.ProcessDefinition;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -32,8 +33,8 @@
 public class WfCategoryServiceImpl implements IWfCategoryService {
 
     private final WfCategoryMapper baseMapper;
-
-    private final RepositoryService repositoryService;
+    @Autowired(required = false)
+    private RepositoryService repositoryService;
 
     /**
      * 鏌ヨ娴佺▼鍒嗙被
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java
index 11f6ef1..f75a188 100644
--- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java
@@ -8,6 +8,7 @@
 import org.dromara.workflow.service.IActProcessInstanceService;
 import org.dromara.workflow.utils.WorkflowUtils;
 import org.flowable.engine.RuntimeService;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
@@ -22,8 +23,9 @@
 @Service
 public class WorkflowServiceImpl implements WorkflowService {
 
+    @Autowired(required = false)
+    private RuntimeService runtimeService;
     private final IActProcessInstanceService iActProcessInstanceService;
-    private final RuntimeService runtimeService;
     private final IActHiProcinstService iActHiProcinstService;
     /**
      * 杩愯涓殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
diff --git a/script/docker/docker-compose.yml b/script/docker/docker-compose.yml
index b4f96aa..91d97ae 100644
--- a/script/docker/docker-compose.yml
+++ b/script/docker/docker-compose.yml
@@ -100,7 +100,7 @@
     network_mode: "host"
 
   ruoyi-server1:
-    image: ruoyi/ruoyi-server:5.2.1
+    image: ruoyi/ruoyi-server:5.2.2
     container_name: ruoyi-server1
     environment:
       # 鏃跺尯涓婃捣
@@ -115,7 +115,7 @@
     network_mode: "host"
 
   ruoyi-server2:
-    image: ruoyi/ruoyi-server:5.2.1
+    image: ruoyi/ruoyi-server:5.2.2
     container_name: ruoyi-server2
     environment:
       # 鏃跺尯涓婃捣
@@ -130,7 +130,7 @@
     network_mode: "host"
 
   ruoyi-monitor-admin:
-    image: ruoyi/ruoyi-monitor-admin:5.2.1
+    image: ruoyi/ruoyi-monitor-admin:5.2.2
     container_name: ruoyi-monitor-admin
     environment:
       # 鏃跺尯涓婃捣
@@ -142,7 +142,7 @@
     network_mode: "host"
 
   ruoyi-snailjob-server:
-    image: ruoyi/ruoyi-snailjob-server:5.2.1
+    image: ruoyi/ruoyi-snailjob-server:5.2.2
     container_name: ruoyi-snailjob-server
     environment:
       # 鏃跺尯涓婃捣
diff --git a/script/docker/nginx/conf/nginx.conf b/script/docker/nginx/conf/nginx.conf
index a6fc073..3c79d97 100644
--- a/script/docker/nginx/conf/nginx.conf
+++ b/script/docker/nginx/conf/nginx.conf
@@ -78,10 +78,13 @@
             proxy_set_header X-Real-IP $remote_addr;
             proxy_set_header REMOTE-HOST $remote_addr;
             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-            # websocket鍙傛暟
+            proxy_read_timeout 86400s;
+            # sse 涓� websocket鍙傛暟
             proxy_http_version 1.1;
             proxy_set_header Upgrade $http_upgrade;
             proxy_set_header Connection "upgrade";
+            proxy_buffering off;
+            proxy_cache off;
             proxy_pass http://server/;
         }
 
diff --git a/script/sql/oracle/snail_job_oracle.sql b/script/sql/oracle/snail_job_oracle.sql
index 19aa07e..d2e17c1 100644
--- a/script/sql/oracle/snail_job_oracle.sql
+++ b/script/sql/oracle/snail_job_oracle.sql
@@ -2,7 +2,7 @@
  SnailJob Database Transfer Tool
  Source Server Type    : MySQL
  Target Server Type    : Oracle
- Date: 2024-05-14 23:36:38
+ Date: 2024-07-06 12:49:36
 */
 
 
@@ -136,7 +136,7 @@
 COMMENT ON COLUMN sj_notify_recipient.id IS '涓婚敭';
 COMMENT ON COLUMN sj_notify_recipient.namespace_id IS '鍛藉悕绌洪棿id';
 COMMENT ON COLUMN sj_notify_recipient.recipient_name IS '鎺ユ敹浜哄悕绉�';
-COMMENT ON COLUMN sj_notify_recipient.notify_type IS '閫氱煡绫诲瀷 1銆侀拤閽� 2銆侀偖浠� 3銆佷紒涓氬井淇� 4 椋炰功';
+COMMENT ON COLUMN sj_notify_recipient.notify_type IS '閫氱煡绫诲瀷 1銆侀拤閽� 2銆侀偖浠� 3銆佷紒涓氬井淇� 4 椋炰功 5 webhook';
 COMMENT ON COLUMN sj_notify_recipient.notify_attribute IS '閰嶇疆灞炴��';
 COMMENT ON COLUMN sj_notify_recipient.description IS '鎻忚堪';
 COMMENT ON COLUMN sj_notify_recipient.create_dt IS '鍒涘缓鏃堕棿';
@@ -296,8 +296,8 @@
 ALTER TABLE sj_retry_task_log_message
     ADD CONSTRAINT pk_sj_retry_task_log_message PRIMARY KEY (id);
 
-CREATE INDEX idx_sj_retry_task_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, unique_id);
-CREATE INDEX idx_sj_retry_task_log_message_02 ON sj_retry_task_log_message (create_dt);
+CREATE INDEX idx_sj_rt_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, unique_id);
+CREATE INDEX idx_sj_rt_log_message_02 ON sj_retry_task_log_message (create_dt);
 
 COMMENT ON COLUMN sj_retry_task_log_message.id IS '涓婚敭';
 COMMENT ON COLUMN sj_retry_task_log_message.namespace_id IS '鍛藉悕绌洪棿id';
@@ -389,8 +389,7 @@
 -- sj_distributed_lock
 CREATE TABLE sj_distributed_lock
 (
-    id         number GENERATED ALWAYS AS IDENTITY,
-    name       varchar2(64)                              NULL,
+    name       varchar2(64)                              NOT NULL,
     lock_until timestamp(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL,
     locked_at  timestamp(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL,
     locked_by  varchar2(255)                             NULL,
@@ -399,9 +398,8 @@
 );
 
 ALTER TABLE sj_distributed_lock
-    ADD CONSTRAINT pk_sj_distributed_lock PRIMARY KEY (id);
+    ADD CONSTRAINT pk_sj_distributed_lock PRIMARY KEY (name);
 
-COMMENT ON COLUMN sj_distributed_lock.id IS '涓婚敭';
 COMMENT ON COLUMN sj_distributed_lock.name IS '閿佸悕绉�';
 COMMENT ON COLUMN sj_distributed_lock.lock_until IS '閿佸畾鏃堕暱';
 COMMENT ON COLUMN sj_distributed_lock.locked_at IS '閿佸畾鏃堕棿';
@@ -449,7 +447,7 @@
 ALTER TABLE sj_system_user_permission
     ADD CONSTRAINT pk_sj_system_user_permission PRIMARY KEY (id);
 
-CREATE UNIQUE INDEX uk_sj_system_user_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id);
+CREATE UNIQUE INDEX uk_sj_su_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id);
 
 COMMENT ON COLUMN sj_system_user_permission.id IS '涓婚敭';
 COMMENT ON COLUMN sj_system_user_permission.group_name IS '缁勫悕绉�';
@@ -598,7 +596,11 @@
     parent_id      number        DEFAULT 0                                  NOT NULL,
     task_status    smallint      DEFAULT 0                                  NOT NULL,
     retry_count    number        DEFAULT 0                                  NOT NULL,
+    mr_stage       smallint      DEFAULT NULL                               NULL,
+    leaf           smallint      DEFAULT '1'                                NOT NULL,
+    task_name      varchar2(255) DEFAULT ''                                 NULL,
     client_info    varchar2(128) DEFAULT NULL                               NULL,
+    wf_context     clob          DEFAULT NULL                               NULL,
     result_message clob                                                     NULL,
     args_str       clob          DEFAULT NULL                               NULL,
     args_type      smallint      DEFAULT 1                                  NOT NULL,
@@ -622,7 +624,11 @@
 COMMENT ON COLUMN sj_job_task.parent_id IS '鐖舵墽琛屽櫒id';
 COMMENT ON COLUMN sj_job_task.task_status IS '鎵ц鐨勭姸鎬� 0銆佸け璐� 1銆佹垚鍔�';
 COMMENT ON COLUMN sj_job_task.retry_count IS '閲嶈瘯娆℃暟';
+COMMENT ON COLUMN sj_job_task.mr_stage IS '鍔ㄦ�佸垎鐗囨墍澶勯樁娈� 1:map 2:reduce 3:mergeReduce';
+COMMENT ON COLUMN sj_job_task.leaf IS '鍙跺瓙鑺傜偣';
+COMMENT ON COLUMN sj_job_task.task_name IS '浠诲姟鍚嶇О';
 COMMENT ON COLUMN sj_job_task.client_info IS '瀹㈡埛绔湴鍧� clientId#ip:port';
+COMMENT ON COLUMN sj_job_task.wf_context IS '宸ヤ綔娴佸叏灞�涓婁笅鏂�';
 COMMENT ON COLUMN sj_job_task.result_message IS '鎵ц缁撴灉';
 COMMENT ON COLUMN sj_job_task.args_str IS '鎵ц鏂规硶鍙傛暟';
 COMMENT ON COLUMN sj_job_task.args_type IS '鍙傛暟绫诲瀷 ';
@@ -773,6 +779,7 @@
     executor_timeout number        DEFAULT 0                                  NOT NULL,
     description      varchar2(256) DEFAULT ''                                 NULL,
     flow_info        clob          DEFAULT NULL                               NULL,
+    wf_context       clob          DEFAULT NULL                               NULL,
     bucket_index     number        DEFAULT 0                                  NOT NULL,
     version          number                                                   NOT NULL,
     ext_attrs        varchar2(256) DEFAULT ''                                 NULL,
@@ -799,6 +806,7 @@
 COMMENT ON COLUMN sj_workflow.executor_timeout IS '浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇';
 COMMENT ON COLUMN sj_workflow.description IS '鎻忚堪';
 COMMENT ON COLUMN sj_workflow.flow_info IS '娴佺▼淇℃伅';
+COMMENT ON COLUMN sj_workflow.wf_context IS '涓婁笅鏂�';
 COMMENT ON COLUMN sj_workflow.bucket_index IS 'bucket';
 COMMENT ON COLUMN sj_workflow.version IS '鐗堟湰鍙�';
 COMMENT ON COLUMN sj_workflow.ext_attrs IS '鎵╁睍瀛楁';
@@ -864,8 +872,10 @@
     task_batch_status smallint      DEFAULT 0                                  NOT NULL,
     operation_reason  smallint      DEFAULT 0                                  NOT NULL,
     flow_info         clob          DEFAULT NULL                               NULL,
+    wf_context        clob          DEFAULT NULL                               NULL,
     execution_at      number        DEFAULT 0                                  NOT NULL,
     ext_attrs         varchar2(256) DEFAULT ''                                 NULL,
+    version           number        DEFAULT 1                                  NOT NULL,
     deleted           smallint      DEFAULT 0                                  NOT NULL,
     create_dt         date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
     update_dt         date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
@@ -885,10 +895,11 @@
 COMMENT ON COLUMN sj_workflow_task_batch.task_batch_status IS '浠诲姟鎵规鐘舵�� 0銆佸け璐� 1銆佹垚鍔�';
 COMMENT ON COLUMN sj_workflow_task_batch.operation_reason IS '鎿嶄綔鍘熷洜';
 COMMENT ON COLUMN sj_workflow_task_batch.flow_info IS '娴佺▼淇℃伅';
+COMMENT ON COLUMN sj_workflow_task_batch.wf_context IS '鍏ㄥ眬涓婁笅鏂�';
 COMMENT ON COLUMN sj_workflow_task_batch.execution_at IS '浠诲姟鎵ц鏃堕棿';
 COMMENT ON COLUMN sj_workflow_task_batch.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_workflow_task_batch.version IS '鐗堟湰鍙�';
 COMMENT ON COLUMN sj_workflow_task_batch.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
 COMMENT ON COLUMN sj_workflow_task_batch.create_dt IS '鍒涘缓鏃堕棿';
 COMMENT ON COLUMN sj_workflow_task_batch.update_dt IS '淇敼鏃堕棿';
 COMMENT ON TABLE sj_workflow_task_batch IS '宸ヤ綔娴佹壒娆�';
-
diff --git a/script/sql/postgres/snail_job_postgre.sql b/script/sql/postgres/snail_job_postgre.sql
index 30a871e..c8abc68 100644
--- a/script/sql/postgres/snail_job_postgre.sql
+++ b/script/sql/postgres/snail_job_postgre.sql
@@ -2,7 +2,7 @@
  SnailJob Database Transfer Tool
  Source Server Type    : MySQL
  Target Server Type    : PostgreSQL
- Date: 2024-05-13 22:49:34
+ Date: 2024-07-06 11:45:40
 */
 
 
@@ -124,7 +124,7 @@
 COMMENT ON COLUMN sj_notify_recipient.id IS '涓婚敭';
 COMMENT ON COLUMN sj_notify_recipient.namespace_id IS '鍛藉悕绌洪棿id';
 COMMENT ON COLUMN sj_notify_recipient.recipient_name IS '鎺ユ敹浜哄悕绉�';
-COMMENT ON COLUMN sj_notify_recipient.notify_type IS '閫氱煡绫诲瀷 1銆侀拤閽� 2銆侀偖浠� 3銆佷紒涓氬井淇� 4 椋炰功';
+COMMENT ON COLUMN sj_notify_recipient.notify_type IS '閫氱煡绫诲瀷 1銆侀拤閽� 2銆侀偖浠� 3銆佷紒涓氬井淇� 4 椋炰功 5 webhook';
 COMMENT ON COLUMN sj_notify_recipient.notify_attribute IS '閰嶇疆灞炴��';
 COMMENT ON COLUMN sj_notify_recipient.description IS '鎻忚堪';
 COMMENT ON COLUMN sj_notify_recipient.create_dt IS '鍒涘缓鏃堕棿';
@@ -359,8 +359,7 @@
 -- sj_distributed_lock
 CREATE TABLE sj_distributed_lock
 (
-    id         bigserial PRIMARY KEY,
-    name       varchar(64)  NOT NULL,
+    name       varchar(64)  PRIMARY KEY,
     lock_until timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
     locked_at  timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
     locked_by  varchar(255) NOT NULL,
@@ -368,7 +367,6 @@
     update_dt  timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
 );
 
-COMMENT ON COLUMN sj_distributed_lock.id IS '涓婚敭';
 COMMENT ON COLUMN sj_distributed_lock.name IS '閿佸悕绉�';
 COMMENT ON COLUMN sj_distributed_lock.lock_until IS '閿佸畾鏃堕暱';
 COMMENT ON COLUMN sj_distributed_lock.locked_at IS '閿佸畾鏃堕棿';
@@ -550,7 +548,11 @@
     parent_id      bigint       NOT NULL DEFAULT 0,
     task_status    smallint     NOT NULL DEFAULT 0,
     retry_count    int          NOT NULL DEFAULT 0,
+    mr_stage       smallint     NULL     DEFAULT NULL,
+    leaf           smallint     NOT NULL DEFAULT '1',
+    task_name      varchar(255) NOT NULL DEFAULT '',
     client_info    varchar(128) NULL     DEFAULT NULL,
+    wf_context     text         NULL     DEFAULT NULL,
     result_message text         NOT NULL,
     args_str       text         NULL     DEFAULT NULL,
     args_type      smallint     NOT NULL DEFAULT 1,
@@ -571,7 +573,11 @@
 COMMENT ON COLUMN sj_job_task.parent_id IS '鐖舵墽琛屽櫒id';
 COMMENT ON COLUMN sj_job_task.task_status IS '鎵ц鐨勭姸鎬� 0銆佸け璐� 1銆佹垚鍔�';
 COMMENT ON COLUMN sj_job_task.retry_count IS '閲嶈瘯娆℃暟';
+COMMENT ON COLUMN sj_job_task.mr_stage IS '鍔ㄦ�佸垎鐗囨墍澶勯樁娈� 1:map 2:reduce 3:mergeReduce';
+COMMENT ON COLUMN sj_job_task.leaf IS '鍙跺瓙鑺傜偣';
+COMMENT ON COLUMN sj_job_task.task_name IS '浠诲姟鍚嶇О';
 COMMENT ON COLUMN sj_job_task.client_info IS '瀹㈡埛绔湴鍧� clientId#ip:port';
+COMMENT ON COLUMN sj_job_task.wf_context IS '宸ヤ綔娴佸叏灞�涓婁笅鏂�';
 COMMENT ON COLUMN sj_job_task.result_message IS '鎵ц缁撴灉';
 COMMENT ON COLUMN sj_job_task.args_str IS '鎵ц鏂规硶鍙傛暟';
 COMMENT ON COLUMN sj_job_task.args_type IS '鍙傛暟绫诲瀷 ';
@@ -713,6 +719,7 @@
     executor_timeout int          NOT NULL DEFAULT 0,
     description      varchar(256) NOT NULL DEFAULT '',
     flow_info        text         NULL     DEFAULT NULL,
+    wf_context       text         NULL     DEFAULT NULL,
     bucket_index     int          NOT NULL DEFAULT 0,
     version          int          NOT NULL,
     ext_attrs        varchar(256) NULL     DEFAULT '',
@@ -736,6 +743,7 @@
 COMMENT ON COLUMN sj_workflow.executor_timeout IS '浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇';
 COMMENT ON COLUMN sj_workflow.description IS '鎻忚堪';
 COMMENT ON COLUMN sj_workflow.flow_info IS '娴佺▼淇℃伅';
+COMMENT ON COLUMN sj_workflow.wf_context IS '涓婁笅鏂�';
 COMMENT ON COLUMN sj_workflow.bucket_index IS 'bucket';
 COMMENT ON COLUMN sj_workflow.version IS '鐗堟湰鍙�';
 COMMENT ON COLUMN sj_workflow.ext_attrs IS '鎵╁睍瀛楁';
@@ -798,8 +806,10 @@
     task_batch_status smallint     NOT NULL DEFAULT 0,
     operation_reason  smallint     NOT NULL DEFAULT 0,
     flow_info         text         NULL     DEFAULT NULL,
+    wf_context        text         NULL     DEFAULT NULL,
     execution_at      bigint       NOT NULL DEFAULT 0,
     ext_attrs         varchar(256) NULL     DEFAULT '',
+    version           int          NOT NULL DEFAULT 1,
     deleted           smallint     NOT NULL DEFAULT 0,
     create_dt         timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
     update_dt         timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
@@ -816,10 +826,11 @@
 COMMENT ON COLUMN sj_workflow_task_batch.task_batch_status IS '浠诲姟鎵规鐘舵�� 0銆佸け璐� 1銆佹垚鍔�';
 COMMENT ON COLUMN sj_workflow_task_batch.operation_reason IS '鎿嶄綔鍘熷洜';
 COMMENT ON COLUMN sj_workflow_task_batch.flow_info IS '娴佺▼淇℃伅';
+COMMENT ON COLUMN sj_workflow_task_batch.wf_context IS '鍏ㄥ眬涓婁笅鏂�';
 COMMENT ON COLUMN sj_workflow_task_batch.execution_at IS '浠诲姟鎵ц鏃堕棿';
 COMMENT ON COLUMN sj_workflow_task_batch.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_workflow_task_batch.version IS '鐗堟湰鍙�';
 COMMENT ON COLUMN sj_workflow_task_batch.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
 COMMENT ON COLUMN sj_workflow_task_batch.create_dt IS '鍒涘缓鏃堕棿';
 COMMENT ON COLUMN sj_workflow_task_batch.update_dt IS '淇敼鏃堕棿';
 COMMENT ON TABLE sj_workflow_task_batch IS '宸ヤ綔娴佹壒娆�';
-
diff --git a/script/sql/snail_job.sql b/script/sql/snail_job.sql
index ce93e11..c3aa760 100644
--- a/script/sql/snail_job.sql
+++ b/script/sql/snail_job.sql
@@ -68,7 +68,7 @@
     `id`               bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
     `namespace_id`     varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
     `recipient_name`   varchar(64)         NOT NULL COMMENT '鎺ユ敹浜哄悕绉�',
-    `notify_type`      tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閫氱煡绫诲瀷 1銆侀拤閽� 2銆侀偖浠� 3銆佷紒涓氬井淇� 4 椋炰功',
+    `notify_type`      tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閫氱煡绫诲瀷 1銆侀拤閽� 2銆侀偖浠� 3銆佷紒涓氬井淇� 4 椋炰功 5 webhook',
     `notify_attribute` varchar(512)        NOT NULL COMMENT '閰嶇疆灞炴��',
     `description`      varchar(256)        NOT NULL DEFAULT '' COMMENT '鎻忚堪',
     `create_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
@@ -222,15 +222,13 @@
 
 CREATE TABLE `sj_distributed_lock`
 (
-    `id`         bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
     `name`       varchar(64)         NOT NULL COMMENT '閿佸悕绉�',
     `lock_until` timestamp(3)        NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '閿佸畾鏃堕暱',
     `locked_at`  timestamp(3)        NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '閿佸畾鏃堕棿',
     `locked_by`  varchar(255)        NOT NULL COMMENT '閿佸畾鑰�',
     `create_dt`  datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
     `update_dt`  datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
-    PRIMARY KEY (`id`),
-    UNIQUE KEY `uk_name` (`name`)
+    PRIMARY KEY (`name`)
 ) ENGINE = InnoDB
   AUTO_INCREMENT = 0
   DEFAULT CHARSET = utf8mb4 COMMENT ='閿佸畾琛�';
@@ -345,12 +343,16 @@
     `job_id`         bigint(20)          NOT NULL COMMENT '浠诲姟淇℃伅id',
     `task_batch_id`  bigint(20)          NOT NULL COMMENT '璋冨害浠诲姟id',
     `parent_id`      bigint(20)          NOT NULL DEFAULT 0 COMMENT '鐖舵墽琛屽櫒id',
-    `task_status`    tinyint(4)          NOT NULL DEFAULT 0 COMMENT '鎵ц鐨勭姸鎬� 0銆佸け璐� 1銆佹垚鍔�',
+    `task_status`    tinyint             NOT NULL DEFAULT 0 COMMENT '鎵ц鐨勭姸鎬� 0銆佸け璐� 1銆佹垚鍔�',
     `retry_count`    int(11)             NOT NULL DEFAULT 0 COMMENT '閲嶈瘯娆℃暟',
+    `mr_stage`       tinyint                      DEFAULT NULL COMMENT '鍔ㄦ�佸垎鐗囨墍澶勯樁娈� 1:map 2:reduce 3:mergeReduce',
+    `leaf`           tinyint             NOT NULL DEFAULT '1' COMMENT '鍙跺瓙鑺傜偣',
+    `task_name`      varchar(255)        NOT NULL DEFAULT '' COMMENT '浠诲姟鍚嶇О',
     `client_info`    varchar(128)                 DEFAULT NULL COMMENT '瀹㈡埛绔湴鍧� clientId#ip:port',
+    `wf_context`     text                         DEFAULT NULL COMMENT '宸ヤ綔娴佸叏灞�涓婁笅鏂�',
     `result_message` text                NOT NULL COMMENT '鎵ц缁撴灉',
     `args_str`       text                         DEFAULT NULL COMMENT '鎵ц鏂规硶鍙傛暟',
-    `args_type`      tinyint(4)          NOT NULL DEFAULT 1 COMMENT '鍙傛暟绫诲瀷 ',
+    `args_type`      tinyint             NOT NULL DEFAULT 1 COMMENT '鍙傛暟绫诲瀷 ',
     `ext_attrs`      varchar(256)        NULL     DEFAULT '' COMMENT '鎵╁睍瀛楁',
     `create_dt`      datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
     `update_dt`      datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
@@ -447,6 +449,7 @@
     `executor_timeout` int(11)             NOT NULL DEFAULT 0 COMMENT '浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇',
     `description`      varchar(256)        NOT NULL DEFAULT '' COMMENT '鎻忚堪',
     `flow_info`        text                         DEFAULT NULL COMMENT '娴佺▼淇℃伅',
+    `wf_context`       text                         DEFAULT NULL COMMENT '涓婁笅鏂�',
     `bucket_index`     int(11)             NOT NULL DEFAULT 0 COMMENT 'bucket',
     `version`          int(11)             NOT NULL COMMENT '鐗堟湰鍙�',
     `ext_attrs`        varchar(256)        NULL     DEFAULT '' COMMENT '鎵╁睍瀛楁',
@@ -495,8 +498,10 @@
     `task_batch_status` tinyint(4)          NOT NULL DEFAULT 0 COMMENT '浠诲姟鎵规鐘舵�� 0銆佸け璐� 1銆佹垚鍔�',
     `operation_reason`  tinyint(4)          NOT NULL DEFAULT 0 COMMENT '鎿嶄綔鍘熷洜',
     `flow_info`         text                         DEFAULT NULL COMMENT '娴佺▼淇℃伅',
+    `wf_context`        text                         DEFAULT NULL COMMENT '鍏ㄥ眬涓婁笅鏂�',
     `execution_at`      bigint(13)          NOT NULL DEFAULT 0 COMMENT '浠诲姟鎵ц鏃堕棿',
     `ext_attrs`         varchar(256)        NULL     DEFAULT '' COMMENT '鎵╁睍瀛楁',
+    `version`           int(11)              NOT NULL DEFAULT 1 COMMENT '鐗堟湰鍙�',
     `deleted`           tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎 1銆佸垹闄�',
     `create_dt`         datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
     `update_dt`         datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
diff --git a/script/sql/sqlserver/snail_job_sqlserver.sql b/script/sql/sqlserver/snail_job_sqlserver.sql
index d6fa1ae..249842b 100644
--- a/script/sql/sqlserver/snail_job_sqlserver.sql
+++ b/script/sql/sqlserver/snail_job_sqlserver.sql
@@ -2,7 +2,7 @@
  SnailJob Database Transfer Tool
  Source Server Type    : MySQL
  Target Server Type    : Microsoft SQL Server
- Date: 2024-05-13 23:03:34
+ Date: 2024-07-06 12:55:47
 */
 
 
@@ -370,7 +370,7 @@
 GO
 
 EXEC sp_addextendedproperty
-     'MS_Description', N'閫氱煡绫诲瀷 1銆侀拤閽� 2銆侀偖浠� 3銆佷紒涓氬井淇� 4 椋炰功',
+     'MS_Description', N'閫氱煡绫诲瀷 1銆侀拤閽� 2銆侀偖浠� 3銆佷紒涓氬井淇� 4 椋炰功 5 webhook',
      'SCHEMA', N'dbo',
      'TABLE', N'sj_notify_recipient',
      'COLUMN', N'notify_type'
@@ -1142,21 +1142,13 @@
 -- sj_distributed_lock
 CREATE TABLE sj_distributed_lock
 (
-    id         bigint        NOT NULL PRIMARY KEY IDENTITY,
-    name       nvarchar(64)  NOT NULL,
+    name       nvarchar(64)  NOT NULL PRIMARY KEY,
     lock_until datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
     locked_at  datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
     locked_by  nvarchar(255) NOT NULL,
     create_dt  datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
     update_dt  datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
 )
-GO
-
-EXEC sp_addextendedproperty
-     'MS_Description', N'涓婚敭',
-     'SCHEMA', N'dbo',
-     'TABLE', N'sj_distributed_lock',
-     'COLUMN', N'id'
 GO
 
 EXEC sp_addextendedproperty
@@ -1745,7 +1737,11 @@
     parent_id      bigint        NOT NULL DEFAULT 0,
     task_status    tinyint       NOT NULL DEFAULT 0,
     retry_count    int           NOT NULL DEFAULT 0,
+    mr_stage       tinyint       NULL     DEFAULT NULL,
+    leaf           tinyint       NOT NULL DEFAULT '1',
+    task_name      nvarchar(255) NOT NULL DEFAULT '',
     client_info    nvarchar(128) NULL     DEFAULT NULL,
+    wf_context     nvarchar(max) NULL     DEFAULT NULL,
     result_message nvarchar(max) NOT NULL,
     args_str       nvarchar(max) NULL     DEFAULT NULL,
     args_type      tinyint       NOT NULL DEFAULT 1,
@@ -1819,10 +1815,38 @@
 GO
 
 EXEC sp_addextendedproperty
+     'MS_Description', N'鍔ㄦ�佸垎鐗囨墍澶勯樁娈� 1:map 2:reduce 3:mergeReduce',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'mr_stage'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍙跺瓙鑺傜偣',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'leaf'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟鍚嶇О',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'task_name'
+GO
+
+EXEC sp_addextendedproperty
      'MS_Description', N'瀹㈡埛绔湴鍧� clientId#ip:port',
      'SCHEMA', N'dbo',
      'TABLE', N'sj_job_task',
      'COLUMN', N'client_info'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'宸ヤ綔娴佸叏灞�涓婁笅鏂�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'wf_context'
 GO
 
 EXEC sp_addextendedproperty
@@ -2281,6 +2305,7 @@
     executor_timeout int           NOT NULL DEFAULT 0,
     description      nvarchar(256) NOT NULL DEFAULT '',
     flow_info        nvarchar(max) NULL     DEFAULT NULL,
+    wf_context       nvarchar(max) NULL     DEFAULT NULL,
     bucket_index     int           NOT NULL DEFAULT 0,
     version          int           NOT NULL,
     ext_attrs        nvarchar(256) NULL     DEFAULT '',
@@ -2377,6 +2402,13 @@
      'SCHEMA', N'dbo',
      'TABLE', N'sj_workflow',
      'COLUMN', N'flow_info'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婁笅鏂�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'wf_context'
 GO
 
 EXEC sp_addextendedproperty
@@ -2590,8 +2622,10 @@
     task_batch_status tinyint       NOT NULL DEFAULT 0,
     operation_reason  tinyint       NOT NULL DEFAULT 0,
     flow_info         nvarchar(max) NULL     DEFAULT NULL,
+    wf_context        nvarchar(max) NULL     DEFAULT NULL,
     execution_at      bigint        NOT NULL DEFAULT 0,
     ext_attrs         nvarchar(256) NULL     DEFAULT '',
+    version           int           NOT NULL DEFAULT 1,
     deleted           tinyint       NOT NULL DEFAULT 0,
     create_dt         datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
     update_dt         datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
@@ -2655,6 +2689,13 @@
 GO
 
 EXEC sp_addextendedproperty
+     'MS_Description', N'鍏ㄥ眬涓婁笅鏂�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'wf_context'
+GO
+
+EXEC sp_addextendedproperty
      'MS_Description', N'浠诲姟鎵ц鏃堕棿',
      'SCHEMA', N'dbo',
      'TABLE', N'sj_workflow_task_batch',
@@ -2669,6 +2710,13 @@
 GO
 
 EXEC sp_addextendedproperty
+     'MS_Description', N'鐗堟湰鍙�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'version'
+GO
+
+EXEC sp_addextendedproperty
      'MS_Description', N'閫昏緫鍒犻櫎 1銆佸垹闄�',
      'SCHEMA', N'dbo',
      'TABLE', N'sj_workflow_task_batch',

--
Gitblit v1.9.3