Forráskód Böngészése

Merge remote-tracking branch 'yudao/feature/mall_product' into feature/mall_product

puhui999 1 éve
szülő
commit
92b10e2ecf
100 módosított fájl, 575 hozzáadás és 1200 törlés
  1. 15 24
      Docker-HOWTO.md
  2. 1 1
      README.md
  3. 6 17
      docker-compose.yml
  4. 1 1
      pom.xml
  5. 19 5
      yudao-dependencies/pom.xml
  6. 1 1
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
  7. 5 2
      yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java
  8. 0 2
      yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml
  9. 1 0
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java
  10. 13 11
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java
  11. 5 2
      yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClientConfig.java
  12. 0 47
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisKeyDefine.java
  13. 0 27
      yudao-framework/yudao-spring-boot-starter-biz-tenant/src/test/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisKeyDefineTest.java
  14. 0 4
      yudao-framework/yudao-spring-boot-starter-biz-weixin/pom.xml
  15. 0 8
      yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/config/YudaoCaptchaConfiguration.java
  16. 16 13
      yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/core/enums/CaptchaRedisKeyConstants.java
  17. 1 2
      yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
  18. 4 28
      yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
  19. 9 7
      yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/redis/IdempotentRedisDAO.java
  20. 1 9
      yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java
  21. 8 8
      yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/Lock4jRedisKeyConstants.java
  22. 5 0
      yudao-framework/yudao-spring-boot-starter-redis/pom.xml
  23. 27 4
      yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java
  24. 13 2
      yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java
  25. 0 113
      yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/RedisKeyDefine.java
  26. 0 28
      yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/RedisKeyRegistry.java
  27. 51 0
      yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/TimeoutRedisCacheManager.java
  28. 2 3
      yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java
  29. 1 0
      yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseDbAndRedisUnitTest.java
  30. 2 1
      yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java
  31. 1 1
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
  32. 7 5
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
  33. 10 10
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java
  34. 0 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
  35. 4 0
      yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java
  36. 1 1
      yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImplTest.java
  37. 4 4
      yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java
  38. 0 5
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.http
  39. 5 74
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.java
  40. 0 35
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisKeyDefineRespVO.java
  41. 0 18
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisKeyValueRespVO.java
  42. 0 5
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/redis/RedisConvert.java
  43. 6 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileConfigMapper.java
  44. 0 29
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/file/FileConfigRefreshConsumer.java
  45. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/package-info.java
  46. 0 17
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/file/FileConfigRefreshMessage.java
  47. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/package-info.java
  48. 0 26
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/file/FileConfigProducer.java
  49. 1 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/package-info.java
  50. 0 5
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigService.java
  51. 43 22
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java
  52. 4 11
      yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java
  53. 4 4
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java
  54. 6 0
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/account/MpAccountMapper.java
  55. 0 29
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/consumer/MpAccountRefreshConsumer.java
  56. 0 21
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/MpAccountRefreshMessage.java
  57. 0 28
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/MpAccountProducer.java
  58. 36 12
      yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java
  59. 0 2
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java
  60. 0 2
      yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java
  61. 0 6
      yudao-module-pay/yudao-module-pay-biz/pom.xml
  62. 8 6
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/RedisKeyConstants.java
  63. 1 1
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/notify/PayNotifyLockRedisDAO.java
  64. 3 4
      yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java
  65. 1 1
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java
  66. 1 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/permission/PermissionApiImpl.java
  67. 1 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java
  68. 1 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http
  69. 18 26
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java
  70. 50 2
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java
  71. 3 3
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogBaseVO.java
  72. 3 3
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java
  73. 0 3
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/RoleController.http
  74. 1 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/permission/PermissionAssignRoleDataScopeReqVO.java
  75. 3 3
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordBaseVO.java
  76. 3 3
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantBaseVO.java
  77. 1 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/profile/UserProfileUpdateReqVO.java
  78. 1 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserExportReqVO.java
  79. 1 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserPageItemRespVO.java
  80. 4 2
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserUpdateStatusReqVO.java
  81. 16 9
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java
  82. 5 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/DeptMapper.java
  83. 3 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/MenuMapper.java
  84. 8 6
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMenuMapper.java
  85. 5 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sensitiveword/SensitiveWordMapper.java
  86. 6 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsChannelMapper.java
  87. 86 14
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java
  88. 0 41
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/common/CaptchaRedisDAO.java
  89. 1 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/oauth2/OAuth2AccessTokenRedisDAO.java
  90. 0 29
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/auth/OAuth2ClientRefreshConsumer.java
  91. 0 29
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/dept/DeptRefreshConsumer.java
  92. 0 31
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailAccountRefreshConsumer.java
  93. 0 29
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailTemplateRefreshConsumer.java
  94. 0 29
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/notify/NotifyTemplateRefreshConsumer.java
  95. 0 29
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/permission/MenuRefreshConsumer.java
  96. 0 29
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/permission/RoleMenuRefreshConsumer.java
  97. 0 29
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/permission/RoleRefreshConsumer.java
  98. 0 29
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/permission/UserRoleRefreshConsumer.java
  99. 0 29
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sensitiveword/SensitiveWordRefreshConsumer.java
  100. 0 29
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsChannelRefreshConsumer.java

+ 15 - 24
Docker-HOWTO.md

@@ -1,23 +1,24 @@
 # Docker Build & Up
 
 目标: 快速部署体验系统,帮助了解系统之间的依赖关系。
+依赖:docker compose v2,删除`name: yudao-system`,降低`version`版本为`3.3`以下,支持`docker-compose`。
 
 ## 功能文件列表
 
 ```text
 .
-├── Docker-HOWTO.md
-├── docker-compose.yml
-├── docker.env
+├── Docker-HOWTO.md                 
+├── docker-compose.yml              
+├── docker.env                      <-- 提供docker-compose环境变量配置
 ├── yudao-server
-│   ├── Dockerfile
-│   └── nginx.conf
+│   └── Dockerfile
 └── yudao-ui-admin
     ├── .dockerignore
-    └── Dockerfile
+    ├── Dockerfile
+    └── nginx.conf                  <-- 提供基础配置,gzip压缩、api转发
 ```
 
-## Maven build (Optional)
+## 构建 jar 包
 
 ```shell
 # 创建maven缓存volume
@@ -30,29 +31,19 @@ docker run -it --rm --name yudao-maven \
     maven mvn clean install package '-Dmaven.test.skip=true'
 ```
 
-## Docker Compose Build
-
-```shell
-docker compose --env-file docker.env build
-```
-
-## Docker Compose Up
+## 构建启动服务
 
 ```shell
 docker compose --env-file docker.env up -d
 ```
 
-第一次执行,由于数据库未初始化,因此yudao-server容器会运行失败。执行如下命令初始化数据库:
+首次运行会自动构建容器。可以通过`docker compose build [service]`来手动构建所有或某个docker镜像
 
-```shell
-docker compose exec -T mysql \
-    sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" --default-character-set=utf8mb4 ruoyi-vue-pro' \
-    < ./sql/mysql/ruoyi-vue-pro.sql
-```
+`--env-file docker.env`为可选参数,只是展示了通过`.env`文件配置容器启动的环境变量,`docker-compose.yml`本身已经提供足够的默认参数来正常运行系统。
 
-## Server:Port
+## 服务器的宿主机端口映射
 
-- admin: http://localhost:8080
-- API: http://localhost:48080
-- mysql: root/123456, port: 3308
+- admin ui: http://localhost:8080
+- api server: http://localhost:48080
+- mysql: root/123456, port: 3306
 - redis: port: 6379

+ 1 - 1
README.md

@@ -102,7 +102,7 @@
 
 系统内置多种多种业务功能,可以用于快速你的业务系统:
 
-![功能分层](https://static.iocoder.cn/ruoyi-vue-pro-biz.png)
+![功能分层](https://static.iocoder.cn/ruoyi-vue-pro-biz.png?imageView2/2/format/webp)
 
 * 系统功能
 * 基础设施

+ 6 - 17
docker-compose.yml

@@ -1,4 +1,4 @@
-version: "3.8"
+version: "3.4"
 
 name: yudao-system
 
@@ -9,25 +9,22 @@ services:
     restart: unless-stopped
     tty: true
     ports:
-      - 13306:3306
+      - "3306:3306"
     environment:
       MYSQL_DATABASE: ${MYSQL_DATABASE:-ruoyi-vue-pro}
       MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-123456}
     volumes:
       - mysql:/var/lib/mysql/
-    networks:
-      - yudao-network
+      - ./sql/mysql/ruoyi-vue-pro.sql:/docker-entrypoint-initdb.d/ruoyi-vue-pro.sql:ro
 
   redis:
     container_name: yudao-redis
     image: redis:6-alpine
     restart: unless-stopped
     ports:
-      - 16379:6379
+      - "6379:6379"
     volumes:
       - redis:/data
-    networks:
-      - yudao-network
 
   server:
     container_name: yudao-server
@@ -36,7 +33,7 @@ services:
     image: yudao-server
     restart: unless-stopped
     ports:
-      - 48080:48080
+      - "48080:48080"
     environment:
       # https://github.com/polovyivan/docker-pass-configs-to-container
       SPRING_PROFILES_ACTIVE: local
@@ -54,8 +51,6 @@ services:
         --spring.datasource.dynamic.datasource.slave.username=${SLAVE_DATASOURCE_USERNAME:-root}
         --spring.datasource.dynamic.datasource.slave.password=${SLAVE_DATASOURCE_PASSWORD:-123456}
         --spring.redis.host=${REDIS_HOST:-yudao-redis}
-    networks:
-      - yudao-network
     depends_on:
       - mysql
       - redis
@@ -78,16 +73,10 @@ services:
     image: yudao-admin
     restart: unless-stopped
     ports:
-      - 8080:80
-    networks:
-      - yudao-network
+      - "8080:80"
     depends_on:
       - server
 
-networks:
-  yudao-network:
-    driver: bridge
-
 volumes:
   mysql:
     driver: local

+ 1 - 1
pom.xml

@@ -30,7 +30,7 @@
     <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
 
     <properties>
-        <revision>1.7.3-snapshot</revision>
+        <revision>1.8.0-snapshot</revision>
         <!-- Maven 相关 -->
         <java.version>1.8</java.version>
         <maven.compiler.source>${java.version}</maven.compiler.source>

+ 19 - 5
yudao-dependencies/pom.xml

@@ -14,7 +14,7 @@
     <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
 
     <properties>
-        <revision>1.7.3-snapshot</revision>
+        <revision>1.8.0-snapshot</revision>
         <!-- 统一依赖管理 -->
         <spring.boot.version>2.7.13</spring.boot.version>
         <!-- Web 相关 -->
@@ -71,7 +71,7 @@
         <justauth.version>1.0.1</justauth.version>
         <jimureport.version>1.5.8</jimureport.version>
         <xercesImpl.version>2.12.2</xercesImpl.version>
-        <wx-java-mp.version>4.5.0</wx-java-mp.version>
+        <weixin-java.version>4.5.0</weixin-java.version>
     </properties>
 
     <dependencyManagement>
@@ -216,10 +216,9 @@
                 <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <!-- 多数据源 -->
                 <version>${dynamic-datasource.version}</version>
             </dependency>
-
             <dependency>
                 <groupId>com.github.yulichang</groupId>
-                <artifactId>mybatis-plus-join-boot-starter</artifactId>
+                <artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 -->
                 <version>${mybatis-plus-join-boot-starter.version}</version>
             </dependency>
 
@@ -599,10 +598,25 @@
                 <version>${justauth.version}</version>
             </dependency>
 
+            <dependency>
+                <groupId>com.github.binarywang</groupId>
+                <artifactId>weixin-java-pay</artifactId>
+                <version>${weixin-java.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.github.binarywang</groupId>
+                <artifactId>weixin-java-mp</artifactId>
+                <version>${weixin-java.version}</version>
+            </dependency>
             <dependency>
                 <groupId>com.github.binarywang</groupId>
                 <artifactId>wx-java-mp-spring-boot-starter</artifactId>
-                <version>${wx-java-mp.version}</version>
+                <version>${weixin-java.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.github.binarywang</groupId>
+                <artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
+                <version>${weixin-java.version}</version>
             </dependency>
 
             <!-- 积木报表-->

+ 1 - 1
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java

@@ -204,7 +204,7 @@ public class CollectionUtils {
         return from.stream().filter(predicate).findFirst().orElse(null);
     }
 
-    public static <T, V extends Comparable<? super V>> V getMaxValue(List<T> from, Function<T, V> valueFunc) {
+    public static <T, V extends Comparable<? super V>> V getMaxValue(Collection<T> from, Function<T, V> valueFunc) {
         if (CollUtil.isEmpty(from)) {
             return null;
         }

+ 5 - 2
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRuleTest.java

@@ -4,11 +4,11 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ReflectUtil;
 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
-import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
-import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
 import cn.iocoder.yudao.framework.security.core.LoginUser;
 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
+import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
 import net.sf.jsqlparser.expression.Alias;
 import net.sf.jsqlparser.expression.Expression;
 import org.junit.jupiter.api.BeforeEach;
@@ -23,6 +23,7 @@ import static cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataP
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
 import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.same;
 import static org.mockito.Mockito.mockStatic;
 import static org.mockito.Mockito.when;
@@ -73,6 +74,8 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
             LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
                     .setUserType(UserTypeEnum.ADMIN.getValue()));
             securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
+            // mock 方法(permissionApi 返回 null)
+            when(permissionApi.getDeptDataPermission(eq(loginUser.getId()))).thenReturn(null);
 
             // 调用
             NullPointerException exception = assertThrows(NullPointerException.class,

+ 0 - 2
yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml

@@ -63,9 +63,7 @@
         <dependency>
             <groupId>com.github.binarywang</groupId>
             <artifactId>weixin-java-pay</artifactId>
-            <version>4.5.0</version>
         </dependency>
-        <!-- TODO 芋艿:清理 -->
 
         <!-- Test 测试相关 -->
         <dependency>

+ 1 - 0
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java

@@ -70,6 +70,7 @@ public class PayClientFactoryImpl implements PayClientFactory {
             case ALIPAY_APP: return (AbstractPayClient<Config>) new AlipayAppPayClient(channelId, (AlipayPayClientConfig) config);
             case ALIPAY_PC: return (AbstractPayClient<Config>) new AlipayPcPayClient(channelId, (AlipayPayClientConfig) config);
             case ALIPAY_BAR: return (AbstractPayClient<Config>) new AlipayBarPayClient(channelId, (AlipayPayClientConfig) config);
+            // 其它支付
             case MOCK: return (AbstractPayClient<Config>) new MockPayClient(channelId, (MockPayClientConfig) config);
         }
         // 创建失败,错误日志 + 抛出异常

+ 13 - 11
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClient.java

@@ -11,7 +11,9 @@ import java.time.LocalDateTime;
 import java.util.Map;
 
 /**
- * 模拟支付的 PayClient 实现类, 模拟支付返回结果都是成功
+ * 模拟支付的 PayClient 实现类
+ *
+ * 模拟支付返回结果都是成功,方便大家日常流畅
  *
  * @author jason
  */
@@ -25,31 +27,30 @@ public class MockPayClient extends AbstractPayClient<MockPayClientConfig> {
 
     @Override
     protected void doInit() {
-
     }
 
     @Override
     protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
-        // 模拟支付渠道订单号为空
-        return PayOrderRespDTO.successOf("", "", LocalDateTime.now(), reqDTO.getOutTradeNo(), MOCK_RESP_SUCCESS_DATA);
+        return PayOrderRespDTO.successOf("MOCK-P-" + reqDTO.getOutTradeNo(), "", LocalDateTime.now(),
+                reqDTO.getOutTradeNo(), MOCK_RESP_SUCCESS_DATA);
     }
 
     @Override
     protected PayOrderRespDTO doGetOrder(String outTradeNo) {
-        // 模拟支付渠道订单号为空
-        return PayOrderRespDTO.successOf("", "", LocalDateTime.now(), outTradeNo, MOCK_RESP_SUCCESS_DATA);
+        return PayOrderRespDTO.successOf("MOCK-P-" + outTradeNo, "", LocalDateTime.now(),
+                outTradeNo, MOCK_RESP_SUCCESS_DATA);
     }
 
     @Override
     protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
-        // 模拟支付渠道退款单号为空
-        return PayRefundRespDTO.successOf("", LocalDateTime.now(), reqDTO.getOutRefundNo(), MOCK_RESP_SUCCESS_DATA);
+        return PayRefundRespDTO.successOf("MOCK-R-" + reqDTO.getOutRefundNo(), LocalDateTime.now(),
+                reqDTO.getOutRefundNo(), MOCK_RESP_SUCCESS_DATA);
     }
 
     @Override
     protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) {
-        // 模拟支付渠道退款单号为空
-        return PayRefundRespDTO.successOf("", LocalDateTime.now(), outRefundNo, MOCK_RESP_SUCCESS_DATA);
+        return PayRefundRespDTO.successOf("MOCK-R-" + outRefundNo, LocalDateTime.now(),
+                outRefundNo, MOCK_RESP_SUCCESS_DATA);
     }
 
     @Override
@@ -61,4 +62,5 @@ public class MockPayClient extends AbstractPayClient<MockPayClientConfig> {
     protected PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) {
         throw new UnsupportedOperationException("模拟支付无支付回调");
     }
-}
+
+}

+ 5 - 2
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/mock/MockPayClientConfig.java

@@ -14,7 +14,9 @@ import javax.validation.Validator;
 public class MockPayClientConfig implements PayClientConfig {
 
     /**
-     * 配置名称,如果不加任何属性, JsonUtils.parseObject2 解析会报错. 暂时加个名称
+     * 配置名称
+     *
+     * 如果不加任何属性,JsonUtils.parseObject2 解析会报错,所以暂时加个名称
      */
     private String name;
 
@@ -22,4 +24,5 @@ public class MockPayClientConfig implements PayClientConfig {
     public void validate(Validator validator) {
         // 模拟支付配置无需校验
     }
-}
+
+}

+ 0 - 47
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisKeyDefine.java

@@ -1,47 +0,0 @@
-package cn.iocoder.yudao.framework.tenant.core.redis;
-
-import cn.hutool.core.util.ArrayUtil;
-import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
-import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
-
-import java.time.Duration;
-
-/**
- * 多租户拓展的 RedisKeyDefine 实现类
- *
- * 由于 Redis 不同于 MySQL 有 column 字段,无法通过类似 WHERE tenant_id = ? 的方式过滤
- * 所以需要通过在 Redis Key 上增加后缀的方式,进行租户之间的隔离。具体的步骤是:
- * 1. 假设 Redis Key 是 user:%d,示例是 user:1;对应到多租户的 Redis Key 是 user:%d:%d,
- * 2. 在 Redis DAO 中,需要使用 {@link #formatKey(Object...)} 方法,进行 Redis Key 的格式化
- *
- * 注意,大多数情况下,并不用使用 TenantRedisKeyDefine 实现。主要的使用场景,还是 Redis Key 可能存在冲突的情况。
- * 例如说,租户 1 和 2 都有一个手机号作为 Key,则他们会存在冲突的问题
- *
- * @author 芋道源码
- */
-public class TenantRedisKeyDefine extends RedisKeyDefine {
-
-    /**
-     * 多租户的 KEY 模板
-     */
-    private static final String KEY_TEMPLATE_SUFFIX = ":%d";
-
-    public TenantRedisKeyDefine(String memo, String keyTemplate, KeyTypeEnum keyType, Class<?> valueType, Duration timeout) {
-        super(memo, buildKeyTemplate(keyTemplate), keyType, valueType, timeout);
-    }
-
-    public TenantRedisKeyDefine(String memo, String keyTemplate, KeyTypeEnum keyType, Class<?> valueType, TimeoutTypeEnum timeoutType) {
-        super(memo, buildKeyTemplate(keyTemplate), keyType, valueType, timeoutType);
-    }
-
-    private static String buildKeyTemplate(String keyTemplate) {
-        return keyTemplate + KEY_TEMPLATE_SUFFIX;
-    }
-
-    @Override
-    public String formatKey(Object... args) {
-        args = ArrayUtil.append(args, TenantContextHolder.getRequiredTenantId());
-        return super.formatKey(args);
-    }
-
-}

+ 0 - 27
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/test/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisKeyDefineTest.java

@@ -1,27 +0,0 @@
-package cn.iocoder.yudao.framework.tenant.core.redis;
-
-import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
-import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-class TenantRedisKeyDefineTest {
-
-    @Test
-    public void testFormatKey() {
-        Long tenantId = 30L;
-        TenantContextHolder.setTenantId(tenantId);
-        // 准备参数
-        TenantRedisKeyDefine define = new TenantRedisKeyDefine("", "user:%d:%d", RedisKeyDefine.KeyTypeEnum.HASH,
-                Object.class, RedisKeyDefine.TimeoutTypeEnum.FIXED);
-        Long userId = 10L;
-        Integer userType = 1;
-
-        // 调用
-        String key = define.formatKey(userId, userType);
-        // 断言
-        assertEquals("user:10:1:30", key);
-    }
-
-}

+ 0 - 4
yudao-framework/yudao-spring-boot-starter-biz-weixin/pom.xml

@@ -34,16 +34,12 @@
         <!-- 三方云服务相关 -->
         <dependency>
             <groupId>com.github.binarywang</groupId>
-<!--            <artifactId>weixin-java-mp</artifactId>-->
             <artifactId>wx-java-mp-spring-boot-starter</artifactId>
-            <version>4.5.0</version>
         </dependency>
         <dependency>
             <groupId>com.github.binarywang</groupId>
             <artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
-            <version>4.5.0</version>
         </dependency>
-        <!-- TODO 芋艿:清理 -->
     </dependencies>
 
 </project>

+ 0 - 8
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/config/YudaoCaptchaConfiguration.java

@@ -1,7 +1,5 @@
 package cn.iocoder.yudao.framework.captcha.config;
 
-import cn.hutool.core.util.ClassUtil;
-import cn.iocoder.yudao.framework.captcha.core.enums.CaptchaRedisKeyConstants;
 import cn.iocoder.yudao.framework.captcha.core.service.RedisCaptchaServiceImpl;
 import com.xingyuv.captcha.properties.AjCaptchaProperties;
 import com.xingyuv.captcha.service.CaptchaCacheService;
@@ -15,12 +13,6 @@ import javax.annotation.Resource;
 @AutoConfiguration
 public class YudaoCaptchaConfiguration {
 
-    static {
-        // 手动加载 Lock4jRedisKeyConstants 类,因为它不会被使用到
-        // 如果不加载,会导致 Redis 监控,看到它的 Redis Key 枚举
-        ClassUtil.loadClass(CaptchaRedisKeyConstants.class.getName());
-    }
-
     @Resource
     private StringRedisTemplate stringRedisTemplate;
 

+ 16 - 13
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/core/enums/CaptchaRedisKeyConstants.java

@@ -1,12 +1,5 @@
 package cn.iocoder.yudao.framework.captcha.core.enums;
 
-import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
-import com.xingyuv.captcha.model.vo.PointVO;
-
-import java.time.Duration;
-
-import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING;
-
 /**
  * 验证码 Redis Key 枚举类
  *
@@ -14,12 +7,22 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.S
  */
 public interface CaptchaRedisKeyConstants {
 
-    RedisKeyDefine AJ_CAPTCHA_REQ_LIMIT = new RedisKeyDefine("验证码的请求限流",
-            "AJ.CAPTCHA.REQ.LIMIT-%s-%s",
-            STRING, Integer.class, Duration.ofSeconds(60)); // 例如说:验证失败 5 次,get 接口锁定
+    /**
+     * 验证码的请求限流
+     *
+     * KEY 格式:AJ.CAPTCHA.REQ.LIMIT-%s-%s
+     * VALUE 数据类型:String // 例如说:验证失败 5 次,get 接口锁定
+     * 过期时间:60 秒
+     */
+    String AJ_CAPTCHA_REQ_LIMIT = "AJ.CAPTCHA.REQ.LIMIT-%s-%s";
 
-    RedisKeyDefine AJ_CAPTCHA_RUNNING = new RedisKeyDefine("验证码的坐标",
-            "RUNNING:CAPTCHA:%s", // AbstractCaptchaService.REDIS_CAPTCHA_KEY
-            STRING, PointVO.class, Duration.ofSeconds(120)); // {"secretKey":"PP1w2Frr2KEejD2m","x":162,"y":5}
+    /**
+     * 验证码的坐标
+     *
+     * KEY 格式:RUNNING:CAPTCHA:%s // AbstractCaptchaService.REDIS_CAPTCHA_KEY
+     * VALUE 数据类型:String // PointVO.class {"secretKey":"PP1w2Frr2KEejD2m","x":162,"y":5}
+     * 过期时间:120 秒
+     */
+    String AJ_CAPTCHA_RUNNING = "RUNNING:CAPTCHA:%s";
 
 }

+ 1 - 2
yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml

@@ -64,9 +64,8 @@
 
         <dependency>
             <groupId>com.github.yulichang</groupId>
-            <artifactId>mybatis-plus-join-boot-starter</artifactId>
+            <artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 -->
         </dependency>
-
     </dependencies>
 
 </project>

+ 4 - 28
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java

@@ -6,10 +6,10 @@ import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
 import com.baomidou.mybatisplus.extension.toolkit.Db;
-import com.github.yulichang.base.MPJBaseMapper;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.Collection;
@@ -17,10 +17,8 @@ import java.util.List;
 
 /**
  * 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力
- * <p>
- * 为什么继承 MPJBaseMapper 接口?支持 MyBatis Plus 多表 Join 的能力。
  */
-public interface BaseMapperX<T> extends MPJBaseMapper<T> {
+public interface BaseMapperX<T> extends BaseMapper<T> {
 
     default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) {
         // MyBatis Plus 查询
@@ -46,18 +44,6 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> {
         return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
     }
 
-    default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2,
-                        SFunction<T, ?> field3, Object value3) {
-        return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)
-                .eq(field3, value3));
-    }
-
-    default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2,
-                        SFunction<T, ?> field3, Object value3, SFunction<T, ?> field4, Object value4) {
-        return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)
-                .eq(field3, value3).eq(field4, value4));
-    }
-
     default Long selectCount() {
         return selectCount(new QueryWrapper<T>());
     }
@@ -117,11 +103,6 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> {
         update(update, new QueryWrapper<>());
     }
 
-    /**
-     * 根据ID 批量更新,适合大量数据更新
-     *
-     * @param entities 实体们
-     */
     default void updateBatch(Collection<T> entities) {
         Db.updateBatchById(entities);
     }
@@ -130,13 +111,8 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> {
         Db.updateBatchById(entities, size);
     }
 
-    /**
-     * 批量修改插入, 会根据实体的主键是否为空,更新还是修改。默认为 1000
-     *
-     * @param entities 实体们
-     */
-    default void saveOrUpdateBatch(Collection<T> entities){
-        Db.saveOrUpdateBatch(entities);
+    default void saveOrUpdateBatch(Collection<T> collection) {
+        Db.saveOrUpdateBatch(collection);
     }
 
 }

+ 9 - 7
yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/redis/IdempotentRedisDAO.java

@@ -1,13 +1,10 @@
 package cn.iocoder.yudao.framework.idempotent.core.redis;
 
-import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
 import lombok.AllArgsConstructor;
 import org.springframework.data.redis.core.StringRedisTemplate;
 
 import java.util.concurrent.TimeUnit;
 
-import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING;
-
 /**
  * 幂等 Redis DAO
  *
@@ -16,9 +13,14 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.S
 @AllArgsConstructor
 public class IdempotentRedisDAO {
 
-    private static final RedisKeyDefine IDEMPOTENT = new RedisKeyDefine("幂等操作",
-            "idempotent:%s", // 参数为 uuid
-            STRING, String.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
+    /**
+     * 幂等操作
+     *
+     * KEY 格式:idempotent:%s // 参数为 uuid
+     * VALUE 格式:String
+     * 过期时间:不固定
+     */
+    private static final String IDEMPOTENT = "idempotent:%s";
 
     private final StringRedisTemplate redisTemplate;
 
@@ -28,7 +30,7 @@ public class IdempotentRedisDAO {
     }
 
     private static String formatKey(String key) {
-        return String.format(IDEMPOTENT.getKeyTemplate(), key);
+        return String.format(IDEMPOTENT, key);
     }
 
 }

+ 1 - 9
yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java

@@ -1,21 +1,13 @@
 package cn.iocoder.yudao.framework.lock4j.config;
 
-import cn.hutool.core.util.ClassUtil;
-import com.baomidou.lock.spring.boot.autoconfigure.LockAutoConfiguration;
 import cn.iocoder.yudao.framework.lock4j.core.DefaultLockFailureStrategy;
-import cn.iocoder.yudao.framework.lock4j.core.Lock4jRedisKeyConstants;
+import com.baomidou.lock.spring.boot.autoconfigure.LockAutoConfiguration;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
 import org.springframework.context.annotation.Bean;
 
 @AutoConfiguration(before = LockAutoConfiguration.class)
 public class YudaoLock4jConfiguration {
 
-    static {
-        // 手动加载 Lock4jRedisKeyConstants 类,因为它不会被使用到
-        // 如果不加载,会导致 Redis 监控,看到它的 Redis Key 枚举
-        ClassUtil.loadClass(Lock4jRedisKeyConstants.class.getName());
-    }
-
     @Bean
     public DefaultLockFailureStrategy lockFailureStrategy() {
         return new DefaultLockFailureStrategy();

+ 8 - 8
yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/Lock4jRedisKeyConstants.java

@@ -1,10 +1,5 @@
 package cn.iocoder.yudao.framework.lock4j.core;
 
-import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
-import org.redisson.api.RLock;
-
-import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.HASH;
-
 /**
  * Lock4j Redis Key 枚举类
  *
@@ -12,8 +7,13 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.H
  */
 public interface Lock4jRedisKeyConstants {
 
-    RedisKeyDefine LOCK4J = new RedisKeyDefine("分布式锁",
-            "lock4j:%s", // 参数来自 DefaultLockKeyBuilder 类
-            HASH, RLock.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); // Redisson 的 Lock 锁,使用 Hash 数据结构
+    /**
+     * 分布式锁
+     *
+     * KEY 格式:lock4j:%s // 参数来自 DefaultLockKeyBuilder 类
+     * VALUE 数据格式:HASH // RLock.class:Redisson 的 Lock 锁,使用 Hash 数据结构
+     * 过期时间:不固定
+     */
+    String LOCK4J = "lock4j:%s";
 
 }

+ 5 - 0
yudao-framework/yudao-spring-boot-starter-redis/pom.xml

@@ -37,6 +37,11 @@
             <artifactId>netty-all</artifactId>
         </dependency>
 
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+        </dependency>
     </dependencies>
 
 </project>

+ 27 - 4
yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.framework.redis.config;
 
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.redis.core.TimeoutRedisCacheManager;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
 import org.springframework.boot.autoconfigure.cache.CacheProperties;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -7,8 +9,15 @@ import org.springframework.cache.annotation.EnableCaching;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Primary;
 import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.cache.RedisCacheWriter;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.serializer.RedisSerializationContext;
-import org.springframework.data.redis.serializer.RedisSerializer;
+
+import java.util.Objects;
+
+import static cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration.buildRedisSerializer;
 
 /**
  * Cache 配置类,基于 Redis 实现
@@ -20,15 +29,19 @@ public class YudaoCacheAutoConfiguration {
 
     /**
      * RedisCacheConfiguration Bean
-     *
+     * <p>
      * 参考 org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration 的 createConfiguration 方法
      */
     @Bean
     @Primary
     public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
-        // 设置使用 JSON 序列化方式
         RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
-        config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
+        // 设置使用 : 单冒号,而不是双 :: 冒号,避免 Redis Desktop Manager 多余空格
+        // 详细可见 https://blog.csdn.net/chuixue24/article/details/103928965 博客
+        config = config.computePrefixWith(cacheName -> cacheName + StrUtil.COLON);
+        // 设置使用 JSON 序列化方式
+        config = config.serializeValuesWith(
+                RedisSerializationContext.SerializationPair.fromSerializer(buildRedisSerializer()));
 
         // 设置 CacheProperties.Redis 的属性
         CacheProperties.Redis redisProperties = cacheProperties.getRedis();
@@ -47,4 +60,14 @@ public class YudaoCacheAutoConfiguration {
         return config;
     }
 
+    @Bean
+    public RedisCacheManager redisCacheManager(RedisTemplate<String, Object> redisTemplate,
+                                               RedisCacheConfiguration redisCacheConfiguration) {
+        // 创建 RedisCacheWriter 对象
+        RedisConnectionFactory connectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory());
+        RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
+        // 创建 TenantRedisCacheManager 对象
+        return new TimeoutRedisCacheManager(cacheWriter, redisCacheConfiguration);
+    }
+
 }

+ 13 - 2
yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java

@@ -1,5 +1,8 @@
 package cn.iocoder.yudao.framework.redis.config;
 
+import cn.hutool.core.util.ReflectUtil;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
 import org.springframework.context.annotation.Bean;
 import org.springframework.data.redis.connection.RedisConnectionFactory;
@@ -25,9 +28,17 @@ public class YudaoRedisAutoConfiguration {
         template.setKeySerializer(RedisSerializer.string());
         template.setHashKeySerializer(RedisSerializer.string());
         // 使用 JSON 序列化方式(库是 Jackson ),序列化 VALUE 。
-        template.setValueSerializer(RedisSerializer.json());
-        template.setHashValueSerializer(RedisSerializer.json());
+        template.setValueSerializer(buildRedisSerializer());
+        template.setHashValueSerializer(buildRedisSerializer());
         return template;
     }
 
+    public static RedisSerializer<?> buildRedisSerializer() {
+        RedisSerializer<Object> json = RedisSerializer.json();
+        // 解决 LocalDateTime 的序列化
+        ObjectMapper objectMapper = (ObjectMapper) ReflectUtil.getFieldValue(json, "mapper");
+        objectMapper.registerModules(new JavaTimeModule());
+        return json;
+    }
+
 }

+ 0 - 113
yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/RedisKeyDefine.java

@@ -1,113 +0,0 @@
-package cn.iocoder.yudao.framework.redis.core;
-
-import com.fasterxml.jackson.annotation.JsonValue;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.Getter;
-
-import java.time.Duration;
-
-/**
- * Redis Key 定义类
- *
- * @author 芋道源码
- */
-@Data
-public class RedisKeyDefine {
-
-    @Getter
-    @AllArgsConstructor
-    public enum KeyTypeEnum {
-
-        STRING("String"),
-        LIST("List"),
-        HASH("Hash"),
-        SET("Set"),
-        ZSET("Sorted Set"),
-        STREAM("Stream"),
-        PUBSUB("Pub/Sub");
-
-        /**
-         * 类型
-         */
-        @JsonValue
-        private final String type;
-
-    }
-
-    @Getter
-    @AllArgsConstructor
-    public enum TimeoutTypeEnum {
-
-        FOREVER(1), // 永不超时
-        DYNAMIC(2), // 动态超时
-        FIXED(3); // 固定超时
-
-        /**
-         * 类型
-         */
-        @JsonValue
-        private final Integer type;
-
-    }
-
-    /**
-     * Key 模板
-     */
-    private final String keyTemplate;
-    /**
-     * Key 类型的枚举
-     */
-    private final KeyTypeEnum keyType;
-    /**
-     * Value 类型
-     *
-     * 如果是使用分布式锁,设置为 {@link java.util.concurrent.locks.Lock} 类型
-     */
-    private final Class<?> valueType;
-    /**
-     * 超时类型
-     */
-    private final TimeoutTypeEnum timeoutType;
-    /**
-     * 过期时间
-     */
-    private final Duration timeout;
-    /**
-     * 备注
-     */
-    private final String memo;
-
-    private RedisKeyDefine(String memo, String keyTemplate, KeyTypeEnum keyType, Class<?> valueType,
-                           TimeoutTypeEnum timeoutType, Duration timeout) {
-        this.memo = memo;
-        this.keyTemplate = keyTemplate;
-        this.keyType = keyType;
-        this.valueType = valueType;
-        this.timeout = timeout;
-        this.timeoutType = timeoutType;
-        // 添加注册表
-        RedisKeyRegistry.add(this);
-    }
-
-    public RedisKeyDefine(String memo, String keyTemplate, KeyTypeEnum keyType, Class<?> valueType, Duration timeout) {
-        this(memo, keyTemplate, keyType, valueType, TimeoutTypeEnum.FIXED, timeout);
-    }
-
-    public RedisKeyDefine(String memo, String keyTemplate, KeyTypeEnum keyType, Class<?> valueType, TimeoutTypeEnum timeoutType) {
-        this(memo, keyTemplate, keyType, valueType, timeoutType, Duration.ZERO);
-    }
-
-    /**
-     * 格式化 Key
-     *
-     * 注意,内部采用 {@link String#format(String, Object...)} 实现
-     *
-     * @param args 格式化的参数
-     * @return Key
-     */
-    public String formatKey(Object... args) {
-        return String.format(keyTemplate, args);
-    }
-
-}

+ 0 - 28
yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/RedisKeyRegistry.java

@@ -1,28 +0,0 @@
-package cn.iocoder.yudao.framework.redis.core;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * {@link RedisKeyDefine} 注册表
- */
-public class RedisKeyRegistry {
-
-    /**
-     * Redis RedisKeyDefine 数组
-     */
-    private static final List<RedisKeyDefine> DEFINES = new ArrayList<>();
-
-    public static void add(RedisKeyDefine define) {
-        DEFINES.add(define);
-    }
-
-    public static List<RedisKeyDefine> list() {
-        return DEFINES;
-    }
-
-    public static int size() {
-        return DEFINES.size();
-    }
-
-}

+ 51 - 0
yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/TimeoutRedisCacheManager.java

@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.framework.redis.core;
+
+import cn.hutool.core.util.StrUtil;
+import org.springframework.boot.convert.DurationStyle;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.data.redis.cache.RedisCache;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.cache.RedisCacheWriter;
+
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+
+/**
+ * 支持自定义过期时间的 {@link RedisCacheManager} 实现类
+ *
+ * 在 {@link Cacheable#cacheNames()} 格式为 "key#ttl" 时,# 后面的 ttl 为过期时间,单位为秒
+ *
+ * @author 芋道源码
+ */
+public class TimeoutRedisCacheManager extends RedisCacheManager {
+
+    private static final String SPLIT = "#";
+
+    public TimeoutRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
+        super(cacheWriter, defaultCacheConfiguration);
+    }
+
+    @Override
+    protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
+        if (StrUtil.isEmpty(name)) {
+            return super.createRedisCache(name, cacheConfig);
+        }
+        // 如果使用 # 分隔,大小不为 2,则说明不使用自定义过期时间
+        String[] names = StrUtil.splitToArray(name, SPLIT);
+        if (names.length != 2) {
+            return super.createRedisCache(name, cacheConfig);
+        }
+
+        // 核心:通过修改 cacheConfig 的过期时间,实现自定义过期时间
+        if (cacheConfig != null) {
+            // 移除 # 后面的 : 以及后面的内容,避免影响解析
+            names[1] = StrUtil.subBefore(names[1], StrUtil.COLON, false);
+            // 解析时间
+            Duration duration = DurationStyle.detectAndParse(names[1], ChronoUnit.SECONDS);
+            cacheConfig = cacheConfig.entryTtl(duration);
+        }
+        return super.createRedisCache(names[0], cacheConfig);
+    }
+
+}

+ 2 - 3
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java

@@ -60,7 +60,7 @@ public class YudaoWebSecurityConfigurerAdapter {
     /**
      * 自定义的权限映射 Bean 们
      *
-     * @see #configure(HttpSecurity)
+     * @see #filterChain(HttpSecurity)
      */
     @Resource
     private List<AuthorizeRequestsCustomizer> authorizeRequestsCustomizers;
@@ -79,7 +79,7 @@ public class YudaoWebSecurityConfigurerAdapter {
 
     /**
      * 配置 URL 的安全配置
-     * <p>
+     *
      * anyRequest          |   匹配所有请求路径
      * access              |   SpringEl表达式结果为true时可以访问
      * anonymous           |   匿名可以访问
@@ -141,7 +141,6 @@ public class YudaoWebSecurityConfigurerAdapter {
 
         // 添加 Token Filter
         httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
-
         return httpSecurity.build();
     }
 

+ 1 - 0
yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseDbAndRedisUnitTest.java

@@ -40,6 +40,7 @@ public class BaseDbAndRedisUnitTest {
 
             // Redis 配置类
             RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer
+//            RedisAutoConfiguration.class, // Spring Redis 自动配置类
             YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
             RedissonAutoConfiguration.class, // Redisson 自动高配置类
     })

+ 2 - 1
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java

@@ -52,7 +52,8 @@ public class YudaoSwaggerAutoConfiguration {
                 // 接口信息
                 .info(buildInfo(properties))
                 // 接口安全配置
-                .components(new Components().securitySchemes(securitySchemas));
+                .components(new Components().securitySchemes(securitySchemas))
+                .addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION));
         securitySchemas.keySet().forEach(key -> openAPI.addSecurityItem(new SecurityRequirement().addList(key)));
         return openAPI;
     }

+ 1 - 1
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java

@@ -47,7 +47,7 @@ public class BpmTaskController {
     @Parameter(name = "processInstanceId", description = "流程实例的编号", required = true)
     @PreAuthorize("@ss.hasPermission('bpm:task:query')")
     public CommonResult<List<BpmTaskRespVO>> getTaskListByProcessInstanceId(
-        @RequestParam("processInstanceId") String processInstanceId) {
+            @RequestParam("processInstanceId") String processInstanceId) {
         return success(taskService.getTaskListByProcessInstanceId(processInstanceId));
     }
 

+ 7 - 5
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java

@@ -73,11 +73,13 @@ public interface BpmTaskConvert {
 
     BpmTaskDonePageItemRespVO convert2(HistoricTaskInstance bean);
 
-    @Mappings({@Mapping(source = "processInstance.id", target = "id"),
-        @Mapping(source = "processInstance.name", target = "name"),
-        @Mapping(source = "processInstance.startUserId", target = "startUserId"),
-        @Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"),
-        @Mapping(source = "startUser.nickname", target = "startUserNickname")})
+    @Mappings({
+            @Mapping(source = "processInstance.id", target = "id"),
+            @Mapping(source = "processInstance.name", target = "name"),
+            @Mapping(source = "processInstance.startUserId", target = "startUserId"),
+            @Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"),
+            @Mapping(source = "startUser.nickname", target = "startUserNickname")
+    })
     BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser);
 
     default List<BpmTaskRespVO> convertList3(List<HistoricTaskInstance> tasks,

+ 10 - 10
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java

@@ -15,8 +15,8 @@ import cn.iocoder.yudao.module.bpm.convert.definition.BpmTaskAssignRuleConvert;
 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
 import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper;
-import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
 import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants;
+import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
 import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript;
 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 import cn.iocoder.yudao.module.system.api.dept.PostApi;
@@ -89,7 +89,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
 
     @Override
     public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId,
-        String taskDefinitionKey) {
+                                                                                String taskDefinitionKey) {
         return taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, taskDefinitionKey);
     }
 
@@ -128,14 +128,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
         validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions());
         // 校验是否已经配置
         BpmTaskAssignRuleDO existRule =
-            taskRuleMapper.selectListByModelIdAndTaskDefinitionKey(reqVO.getModelId(), reqVO.getTaskDefinitionKey());
+                taskRuleMapper.selectListByModelIdAndTaskDefinitionKey(reqVO.getModelId(), reqVO.getTaskDefinitionKey());
         if (existRule != null) {
             throw exception(TASK_ASSIGN_RULE_EXISTS, reqVO.getModelId(), reqVO.getTaskDefinitionKey());
         }
 
         // 存储
         BpmTaskAssignRuleDO rule = BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO)
-            .setProcessDefinitionId(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL); // 只有流程模型,才允许新建
+                .setProcessDefinitionId(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL); // 只有流程模型,才允许新建
         taskRuleMapper.insert(rule);
         return rule.getId();
     }
@@ -169,14 +169,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
 
         // 遍历,匹配对应的规则
         Map<String, BpmTaskAssignRuleRespVO> processInstanceRuleMap =
-            CollectionUtils.convertMap(processInstanceRules, BpmTaskAssignRuleRespVO::getTaskDefinitionKey);
+                CollectionUtils.convertMap(processInstanceRules, BpmTaskAssignRuleRespVO::getTaskDefinitionKey);
         for (BpmTaskAssignRuleRespVO modelRule : modelRules) {
             BpmTaskAssignRuleRespVO processInstanceRule = processInstanceRuleMap.get(modelRule.getTaskDefinitionKey());
             if (processInstanceRule == null) {
                 return false;
             }
             if (!ObjectUtil.equals(modelRule.getType(), processInstanceRule.getType()) || !ObjectUtil.equal(
-                modelRule.getOptions(), processInstanceRule.getOptions())) {
+                    modelRule.getOptions(), processInstanceRule.getOptions())) {
                 return false;
             }
         }
@@ -192,7 +192,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
         // 开始复制
         List<BpmTaskAssignRuleDO> newRules = BpmTaskAssignRuleConvert.INSTANCE.convertList2(rules);
         newRules.forEach(rule -> rule.setProcessDefinitionId(toProcessDefinitionId).setId(null).setCreateTime(null)
-            .setUpdateTime(null));
+                .setUpdateTime(null));
         taskRuleMapper.insertBatch(newRules);
     }
 
@@ -215,7 +215,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
         if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.ROLE.getType())) {
             roleApi.validRoleList(options);
         } else if (ObjectUtils.equalsAny(type, BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(),
-            BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) {
+                BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) {
             deptApi.validateDeptList(options);
         } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.POST.getType())) {
             postApi.validPostList(options);
@@ -225,7 +225,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
             userGroupService.validUserGroups(options);
         } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.SCRIPT.getType())) {
             dictDataApi.validateDictDataList(DictTypeConstants.TASK_ASSIGN_SCRIPT,
-                CollectionUtils.convertSet(options, String::valueOf));
+                    CollectionUtils.convertSet(options, String::valueOf));
         } else {
             throw new IllegalArgumentException(format("未知的规则类型({})", type));
         }
@@ -298,7 +298,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
     }
 
     private Set<Long> calculateTaskCandidateUsersByPost(BpmTaskAssignRuleDO rule) {
-        List<AdminUserRespDTO> users = adminUserApi.getUsersByPostIds(rule.getOptions());
+        List<AdminUserRespDTO> users = adminUserApi.getUserListByPostIds(rule.getOptions());
         return convertSet(users, AdminUserRespDTO::getId);
     }
 

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java


+ 4 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java

@@ -40,6 +40,8 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest {
         // mock 方法(startUser)
         AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L));
         when(adminUserApi.getUser(eq(1L))).thenReturn(startUser);
+        // mock 方法(getStartUserDept)没有部门
+        when(deptApi.getDept(eq(10L))).thenReturn(null);
 
         // 调用
         Set<Long> result = script.calculateTaskCandidateUsers(execution);
@@ -56,7 +58,9 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest {
         when(adminUserApi.getUser(eq(1L))).thenReturn(startUser);
         DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L)
                 .setLeaderUserId(20L));
+        // mock 方法(getDept)
         when(deptApi.getDept(eq(10L))).thenReturn(startUserDept);
+        when(deptApi.getDept(eq(100L))).thenReturn(null);
 
         // 调用
         Set<Long> result = script.calculateTaskCandidateUsers(execution);

+ 1 - 1
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImplTest.java

@@ -120,7 +120,7 @@ public class BpmTaskAssignRuleServiceImplTest extends BaseDbUnitTest {
         // mock 方法
         List<AdminUserRespDTO> users = CollectionUtils.convertList(asSet(11L, 22L),
                 id -> new AdminUserRespDTO().setId(id));
-        when(adminUserApi.getUsersByPostIds(eq(rule.getOptions()))).thenReturn(users);
+        when(adminUserApi.getUserListByPostIds(eq(rule.getOptions()))).thenReturn(users);
         mockGetUserMap(asSet(11L, 22L));
 
         // 调用

+ 4 - 4
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmUserGroupServiceTest.java

@@ -23,10 +23,10 @@ import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgn
 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_NOT_EXISTS;
 
 /**
-* {@link BpmUserGroupServiceImpl} 的单元测试类
-*
-* @author 芋道源码
-*/
+ * {@link BpmUserGroupServiceImpl} 的单元测试类
+ *
+ * @author 芋道源码
+ */
 @Import(BpmUserGroupServiceImpl.class)
 public class BpmUserGroupServiceTest extends BaseDbUnitTest {
 

+ 0 - 5
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.http

@@ -2,8 +2,3 @@
 GET {{baseUrl}}/infra/redis/get-monitor-info
 Authorization: Bearer {{token}}
 tenant-id: {{adminTenentId}}
-
-### 请求 /infra/redis/get-key-list 接口 => 成功
-GET {{baseUrl}}/infra/redis/get-key-list
-Authorization: Bearer {{token}}
-tenant-id: {{adminTenentId}}

+ 5 - 74
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.java

@@ -1,27 +1,20 @@
 package cn.iocoder.yudao.module.infra.controller.admin.redis;
 
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
-import cn.iocoder.yudao.framework.redis.core.RedisKeyRegistry;
-import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyDefineRespVO;
-import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyValueRespVO;
 import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO;
 import cn.iocoder.yudao.module.infra.convert.redis.RedisConvert;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.data.redis.connection.RedisServerCommands;
-import org.springframework.data.redis.core.Cursor;
 import org.springframework.data.redis.core.RedisCallback;
-import org.springframework.data.redis.core.ScanOptions;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
-import java.util.*;
+import java.util.Properties;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
@@ -47,66 +40,4 @@ public class RedisController {
         return success(RedisConvert.INSTANCE.build(info, dbSize, commandStats));
     }
 
-    @GetMapping("/get-key-define-list")
-    @Operation(summary = "获得 Redis Key 模板列表")
-    @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
-    public CommonResult<List<RedisKeyDefineRespVO>> getKeyDefineList() {
-        List<RedisKeyDefine> keyDefines = RedisKeyRegistry.list();
-        return success(RedisConvert.INSTANCE.convertList(keyDefines));
-    }
-
-    @GetMapping("/get-key-list")
-    @Operation(summary = "获得 Redis keys 键名列表")
-    @Parameter(name = "keyTemplate", description = "Redis Key 定义", example = "true")
-    @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
-    public CommonResult<Set<String>> getKeyDefineList(@RequestParam("keyTemplate") String keyTemplate) {
-        return success(getKeyDefineList0(keyTemplate));
-    }
-
-    private Set<String> getKeyDefineList0(String keyTemplate) {
-        // key 格式化
-        String key = StrUtil.replace(keyTemplate, "%[s|c|b|d|x|o|f|a|e|g]", parameter -> "*");
-        // scan 扫描 key
-        Set<String> keys = new LinkedHashSet<>();
-        stringRedisTemplate.execute((RedisCallback<Set<String>>) connection -> {
-            try (Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(key).count(100).build())) {
-                cursor.forEachRemaining(value -> keys.add(StrUtil.utf8Str(value)));
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-            return keys;
-        });
-        return keys;
-    }
-
-    @GetMapping("/get-key-value")
-    @Operation(summary = "获得 Redis key 内容")
-    @Parameter(name = "key", description = "Redis Key", example = "oauth2_access_token:233")
-    @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
-    public CommonResult<RedisKeyValueRespVO> getKeyValue(@RequestParam("key") String key) {
-        String value = stringRedisTemplate.opsForValue().get(key);
-        return success(new RedisKeyValueRespVO(key, value));
-    }
-
-    @DeleteMapping("/delete-key")
-    @Operation(summary = "删除 Redis Key")
-    @Parameter(name = "key", description = "Redis Key", example = "oauth2_access_token:233")
-    @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
-    public CommonResult<Boolean> deleteKey(@RequestParam("key") String key) {
-        stringRedisTemplate.delete(key);
-        return success(Boolean.TRUE);
-    }
-
-    @DeleteMapping("/delete-keys")
-    @Operation(summary = "删除 Redis Key 根据模板")
-    @Parameter(name = "keyTemplate", description = "Redis Key 定义", example = "true")
-    @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
-    public CommonResult<Boolean> deleteKeys(@RequestParam("keyTemplate") String keyTemplate) {
-        Set<String> keys = getKeyDefineList0(keyTemplate);
-        if (CollUtil.isNotEmpty(keys)) {
-            stringRedisTemplate.delete(keys);
-        }
-        return success(Boolean.TRUE);
-    }
-
 }

+ 0 - 35
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisKeyDefineRespVO.java

@@ -1,35 +0,0 @@
-package cn.iocoder.yudao.module.infra.controller.admin.redis.vo;
-
-import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-
-import java.time.Duration;
-
-@Schema(description = "管理后台 - Redis Key 信息 Response VO")
-@Data
-@Builder
-@AllArgsConstructor
-public class RedisKeyDefineRespVO {
-
-    @Schema(description = "Key 模板", requiredMode = Schema.RequiredMode.REQUIRED, example = "login_user:%s")
-    private String keyTemplate;
-
-    @Schema(description = "Key 类型的枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "String")
-    private RedisKeyDefine.KeyTypeEnum keyType;
-
-    @Schema(description = "Value 类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "java.lang.String")
-    private Class<?> valueType;
-
-    @Schema(description = "超时类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    private RedisKeyDefine.TimeoutTypeEnum timeoutType;
-
-    @Schema(description = "过期时间,单位:毫秒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
-    private Duration timeout;
-
-    @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "啦啦啦啦~")
-    private String memo;
-
-}

+ 0 - 18
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisKeyValueRespVO.java

@@ -1,18 +0,0 @@
-package cn.iocoder.yudao.module.infra.controller.admin.redis.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-
-@Schema(description = "管理后台 - 单个 Redis Key Value Response VO")
-@Data
-@AllArgsConstructor
-public class RedisKeyValueRespVO {
-
-    @Schema(description = "c5f6990767804a928f4bb96ca249febf", requiredMode = Schema.RequiredMode.REQUIRED, example = "String")
-    private String key;
-
-    @Schema(requiredMode = Schema.RequiredMode.REQUIRED, example = "String")
-    private String value;
-
-}

+ 0 - 5
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/redis/RedisConvert.java

@@ -1,14 +1,11 @@
 package cn.iocoder.yudao.module.infra.convert.redis;
 
 import cn.hutool.core.util.StrUtil;
-import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
-import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyDefineRespVO;
 import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
 
 import java.util.ArrayList;
-import java.util.List;
 import java.util.Properties;
 
 @Mapper
@@ -29,6 +26,4 @@ public interface RedisConvert {
         return respVO;
     }
 
-    List<RedisKeyDefineRespVO> convertList(List<RedisKeyDefine> list);
-
 }

+ 6 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileConfigMapper.java

@@ -6,6 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO;
 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+import java.time.LocalDateTime;
 
 @Mapper
 public interface FileConfigMapper extends BaseMapperX<FileConfigDO> {
@@ -18,4 +21,7 @@ public interface FileConfigMapper extends BaseMapperX<FileConfigDO> {
                 .orderByDesc(FileConfigDO::getId));
     }
 
+    @Select("SELECT COUNT(*) FROM infra_file_config WHERE update_time > #{maxUpdateTime}")
+    Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
+
 }

+ 0 - 29
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/file/FileConfigRefreshConsumer.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.infra.mq.consumer.file;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.infra.mq.message.file.FileConfigRefreshMessage;
-import cn.iocoder.yudao.module.infra.service.file.FileConfigService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link FileConfigRefreshMessage} 的消费者
- *
- * @author 芋道源码
- */
-@Component
-@Slf4j
-public class FileConfigRefreshConsumer extends AbstractChannelMessageListener<FileConfigRefreshMessage> {
-
-    @Resource
-    private FileConfigService fileConfigService;
-
-    @Override
-    public void onMessage(FileConfigRefreshMessage message) {
-        log.info("[onMessage][收到 FileConfig 刷新消息]");
-        fileConfigService.initLocalCache();
-    }
-
-}

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/package-info.java

@@ -1,4 +1,4 @@
 /**
- * 占位符,避免缩进
+ * 消息队列的消费者
  */
 package cn.iocoder.yudao.module.infra.mq.consumer;

+ 0 - 17
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/file/FileConfigRefreshMessage.java

@@ -1,17 +0,0 @@
-package cn.iocoder.yudao.module.infra.mq.message.file;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
-import lombok.Data;
-
-/**
- * 文件配置数据刷新 Message
- */
-@Data
-public class FileConfigRefreshMessage extends AbstractChannelMessage {
-
-    @Override
-    public String getChannel() {
-        return "infra.file-config.refresh";
-    }
-
-}

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/package-info.java

@@ -1,4 +1,4 @@
 /**
- * 占位符,避免缩进
+ * 消息队列的消息
  */
 package cn.iocoder.yudao.module.infra.mq.message;

+ 0 - 26
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/file/FileConfigProducer.java

@@ -1,26 +0,0 @@
-package cn.iocoder.yudao.module.infra.mq.producer.file;
-
-import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
-import cn.iocoder.yudao.module.infra.mq.message.file.FileConfigRefreshMessage;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 文件配置相关消息的 Producer
- */
-@Component
-public class FileConfigProducer {
-
-    @Resource
-    private RedisMQTemplate redisMQTemplate;
-
-    /**
-     * 发送 {@link FileConfigRefreshMessage} 消息
-     */
-    public void sendFileConfigRefreshMessage() {
-        FileConfigRefreshMessage message = new FileConfigRefreshMessage();
-        redisMQTemplate.send(message);
-    }
-
-}

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/package-info.java

@@ -1,4 +1,4 @@
 /**
- * 占位符,避免缩进
+ * 消息队列的生产者
  */
 package cn.iocoder.yudao.module.infra.mq.producer;

+ 0 - 5
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigService.java

@@ -16,11 +16,6 @@ import javax.validation.Valid;
  */
 public interface FileConfigService {
 
-    /**
-     * 初始化文件客户端
-     */
-    void initLocalCache();
-
     /**
      * 创建文件配置
      *

+ 43 - 22
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java

@@ -1,8 +1,10 @@
 package cn.iocoder.yudao.module.infra.service.file;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.io.resource.ResourceUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
 import cn.iocoder.yudao.framework.file.core.client.FileClient;
@@ -15,20 +17,20 @@ import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigU
 import cn.iocoder.yudao.module.infra.convert.file.FileConfigConvert;
 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO;
 import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper;
-import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer;
 import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
-import org.springframework.transaction.support.TransactionSynchronization;
-import org.springframework.transaction.support.TransactionSynchronizationManager;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
 import javax.validation.Validator;
+import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_DELETE_FAIL_MASTER;
@@ -46,6 +48,12 @@ public class FileConfigServiceImpl implements FileConfigService {
 
     @Resource
     private FileClientFactory fileClientFactory;
+
+    /**
+     * 文件配置的缓存
+     */
+    @Getter
+    private List<FileConfigDO> fileConfigCache;
     /**
      * Master FileClient 对象,有且仅有一个,即 {@link FileConfigDO#getMaster()} 对应的
      */
@@ -55,13 +63,9 @@ public class FileConfigServiceImpl implements FileConfigService {
     @Resource
     private FileConfigMapper fileConfigMapper;
 
-    @Resource
-    private FileConfigProducer fileConfigProducer;
-
     @Resource
     private Validator validator;
 
-    @Override
     @PostConstruct
     public void initLocalCache() {
         // 第一步:查询数据
@@ -76,6 +80,27 @@ public class FileConfigServiceImpl implements FileConfigService {
                 masterFileClient = fileClientFactory.getFileClient(config.getId());
             }
         });
+        this.fileConfigCache = configs;
+    }
+
+    /**
+     * 通过定时任务轮询,刷新缓存
+     *
+     * 目的:多节点部署时,通过轮询”通知“所有节点,进行刷新
+     */
+    @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS)
+    public void refreshLocalCache() {
+        // 情况一:如果缓存里没有数据,则直接刷新缓存
+        if (CollUtil.isEmpty(fileConfigCache)) {
+            initLocalCache();
+            return;
+        }
+
+        // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存
+        LocalDateTime maxTime = CollectionUtils.getMaxValue(fileConfigCache, FileConfigDO::getUpdateTime);
+        if (fileConfigMapper.selectCountByUpdateTimeGt(maxTime) > 0) {
+            initLocalCache();
+        }
     }
 
     @Override
@@ -85,9 +110,9 @@ public class FileConfigServiceImpl implements FileConfigService {
                 .setConfig(parseClientConfig(createReqVO.getStorage(), createReqVO.getConfig()))
                 .setMaster(false); // 默认非 master
         fileConfigMapper.insert(fileConfig);
-        // 发送刷新配置的消息
-        fileConfigProducer.sendFileConfigRefreshMessage();
-        // 返回
+
+        // 刷新缓存
+        initLocalCache();
         return fileConfig.getId();
     }
 
@@ -99,8 +124,9 @@ public class FileConfigServiceImpl implements FileConfigService {
         FileConfigDO updateObj = FileConfigConvert.INSTANCE.convert(updateReqVO)
                 .setConfig(parseClientConfig(config.getStorage(), updateReqVO.getConfig()));
         fileConfigMapper.updateById(updateObj);
-        // 发送刷新配置的消息
-        fileConfigProducer.sendFileConfigRefreshMessage();
+
+        // 刷新缓存
+        initLocalCache();
     }
 
     @Override
@@ -112,15 +138,9 @@ public class FileConfigServiceImpl implements FileConfigService {
         fileConfigMapper.updateBatch(new FileConfigDO().setMaster(false));
         // 更新
         fileConfigMapper.updateById(new FileConfigDO().setId(id).setMaster(true));
-        // 发送刷新配置的消息
-        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
-
-            @Override
-            public void afterCommit() {
-                fileConfigProducer.sendFileConfigRefreshMessage();
-            }
 
-        });
+        // 刷新缓存
+        initLocalCache();
     }
 
     private FileClientConfig parseClientConfig(Integer storage, Map<String, Object> config) {
@@ -143,8 +163,9 @@ public class FileConfigServiceImpl implements FileConfigService {
         }
         // 删除
         fileConfigMapper.deleteById(id);
-        // 发送刷新配置的消息
-        fileConfigProducer.sendFileConfigRefreshMessage();
+
+        // 刷新缓存
+        initLocalCache();
     }
 
     private FileConfigDO validateFileConfigExists(Long id) {

+ 4 - 11
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java

@@ -16,7 +16,6 @@ import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigP
 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigUpdateReqVO;
 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO;
 import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper;
-import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer;
 import lombok.Data;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.mock.mockito.MockBean;
@@ -55,8 +54,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
     @Resource
     private FileConfigMapper fileConfigMapper;
 
-    @MockBean
-    private FileConfigProducer fileConfigProducer;
     @MockBean
     private Validator validator;
     @MockBean
@@ -81,6 +78,10 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
         verify(fileClientFactory).createOrUpdateFileClient(eq(2L),
                 eq(configDO2.getStorage()), eq(configDO2.getConfig()));
         assertSame(masterFileClient, fileConfigService.getMasterFileClient());
+        // 断言 fileConfigCache 缓存
+        assertEquals(2, fileConfigService.getFileConfigCache().size());
+        assertEquals(configDO1, fileConfigService.getFileConfigCache().get(0));
+        assertEquals(configDO2, fileConfigService.getFileConfigCache().get(1));
     }
 
     @Test
@@ -101,8 +102,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
         assertFalse(fileConfig.getMaster());
         assertEquals("/yunai", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath());
         assertEquals("https://www.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain());
-        // verify 调用
-        verify(fileConfigProducer).sendFileConfigRefreshMessage();
     }
 
     @Test
@@ -126,8 +125,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
         assertPojoEquals(reqVO, fileConfig, "config");
         assertEquals("/yunai2", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath());
         assertEquals("https://doc.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain());
-        // verify 调用
-        verify(fileConfigProducer).sendFileConfigRefreshMessage();
     }
 
     @Test
@@ -152,8 +149,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
         // 断言数据
         assertTrue(fileConfigMapper.selectById(dbFileConfig.getId()).getMaster());
         assertFalse(fileConfigMapper.selectById(masterFileConfig.getId()).getMaster());
-        // verify 调用
-        verify(fileConfigProducer).sendFileConfigRefreshMessage();
     }
 
     @Test
@@ -174,8 +169,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
         fileConfigService.deleteFileConfig(id);
        // 校验数据不存在了
        assertNull(fileConfigMapper.selectById(id));
-        // verify 调用
-        verify(fileConfigProducer).sendFileConfigRefreshMessage();
     }
 
     @Test

+ 4 - 4
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java

@@ -19,10 +19,10 @@ public interface TradeCartMapper extends BaseMapperX<TradeCartDO> {
 
     default TradeCartDO selectByUserIdAndSkuId(Long userId, Long skuId,
                                                Boolean addStatus, Boolean orderStatus) {
-        return selectOne(TradeCartDO::getUserId, userId,
-                TradeCartDO::getSkuId, skuId,
-                TradeCartDO::getAddStatus, addStatus,
-                TradeCartDO::getOrderStatus, orderStatus);
+        return selectOne(new LambdaQueryWrapper<TradeCartDO>().eq(TradeCartDO::getUserId, userId)
+                .eq(TradeCartDO::getSkuId, skuId)
+                .eq(TradeCartDO::getAddStatus, addStatus)
+                .eq(TradeCartDO::getOrderStatus, orderStatus));
     }
 
     default Integer selectSumByUserId(Long userId) {

+ 6 - 0
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/account/MpAccountMapper.java

@@ -6,6 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO;
 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+import java.time.LocalDateTime;
 
 @Mapper
 public interface MpAccountMapper extends BaseMapperX<MpAccountDO> {
@@ -22,4 +25,7 @@ public interface MpAccountMapper extends BaseMapperX<MpAccountDO> {
         return selectOne(MpAccountDO::getAppId, appId);
     }
 
+    @Select("SELECT COUNT(*) FROM mp_account WHERE update_time > #{maxUpdateTime}")
+    Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
+
 }

+ 0 - 29
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/consumer/MpAccountRefreshConsumer.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.mp.mq.consumer;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.mp.mq.message.MpAccountRefreshMessage;
-import cn.iocoder.yudao.module.mp.service.account.MpAccountService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link MpAccountRefreshMessage} 的消费者
- *
- * @author 芋道源码
- */
-@Component
-@Slf4j
-public class MpAccountRefreshConsumer extends AbstractChannelMessageListener<MpAccountRefreshMessage> {
-
-    @Resource
-    private MpAccountService mpAccountService;
-
-    @Override
-    public void onMessage(MpAccountRefreshMessage message) {
-        log.info("[onMessage][收到 Account 刷新消息]");
-        mpAccountService.initLocalCache();
-    }
-
-}

+ 0 - 21
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/MpAccountRefreshMessage.java

@@ -1,21 +0,0 @@
-package cn.iocoder.yudao.module.mp.mq.message;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-/**
- * 公众号账号刷新 Message
- *
- * @author 芋道源码
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-public class MpAccountRefreshMessage extends AbstractChannelMessage {
-
-    @Override
-    public String getChannel() {
-        return "mp.account.refresh";
-    }
-
-}

+ 0 - 28
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/MpAccountProducer.java

@@ -1,28 +0,0 @@
-package cn.iocoder.yudao.module.mp.mq.producer;
-
-import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
-import cn.iocoder.yudao.module.mp.mq.message.MpAccountRefreshMessage;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 公众号账号 Producer
- *
- * @author 芋道源码
- */
-@Component
-public class MpAccountProducer {
-
-    @Resource
-    private RedisMQTemplate redisMQTemplate;
-
-    /**
-     * 发送 {@link MpAccountRefreshMessage} 消息
-     */
-    public void sendAccountRefreshMessage() {
-        MpAccountRefreshMessage message = new MpAccountRefreshMessage();
-        redisMQTemplate.send(message);
-    }
-
-}

+ 36 - 12
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java

@@ -1,9 +1,9 @@
 package cn.iocoder.yudao.module.mp.service.account;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjUtil;
 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO;
 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO;
@@ -13,7 +13,6 @@ import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
 import cn.iocoder.yudao.module.mp.dal.mysql.account.MpAccountMapper;
 import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants;
 import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
-import cn.iocoder.yudao.module.mp.mq.producer.MpAccountProducer;
 import com.google.common.annotations.VisibleForTesting;
 import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
@@ -21,15 +20,20 @@ import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
 import org.springframework.context.annotation.Lazy;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
+import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue;
 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_USERNAME_EXISTS;
 
 /**
@@ -58,9 +62,6 @@ public class MpAccountServiceImpl implements MpAccountService {
     @Lazy // 延迟加载,解决循环依赖的问题
     private MpServiceFactory mpServiceFactory;
 
-    @Resource
-    private MpAccountProducer mpAccountProducer;
-
     @Override
     @PostConstruct
     public void initLocalCache() {
@@ -72,7 +73,30 @@ public class MpAccountServiceImpl implements MpAccountService {
 
             // 第二步:构建缓存。创建或更新支付 Client
             mpServiceFactory.init(accounts);
-            accountCache = CollectionUtils.convertMap(accounts, MpAccountDO::getAppId);
+            accountCache = convertMap(accounts, MpAccountDO::getAppId);
+        });
+    }
+
+    /**
+     * 通过定时任务轮询,刷新缓存
+     *
+     * 目的:多节点部署时,通过轮询”通知“所有节点,进行刷新
+     */
+    @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS)
+    public void refreshLocalCache() {
+        // 注意:忽略自动多租户,因为要全局初始化缓存
+        TenantUtils.executeIgnore(() -> {
+            // 情况一:如果缓存里没有数据,则直接刷新缓存
+            if (CollUtil.isEmpty(accountCache)) {
+                initLocalCache();
+                return;
+            }
+
+            // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存
+            LocalDateTime maxTime = getMaxValue(accountCache.values(), MpAccountDO::getUpdateTime);
+            if (mpAccountMapper.selectCountByUpdateTimeGt(maxTime) > 0) {
+                initLocalCache();
+            }
         });
     }
 
@@ -85,8 +109,8 @@ public class MpAccountServiceImpl implements MpAccountService {
         MpAccountDO account = MpAccountConvert.INSTANCE.convert(createReqVO);
         mpAccountMapper.insert(account);
 
-        // 发送刷新消息
-        mpAccountProducer.sendAccountRefreshMessage();
+        // 刷新缓存
+        initLocalCache();
         return account.getId();
     }
 
@@ -101,8 +125,8 @@ public class MpAccountServiceImpl implements MpAccountService {
         MpAccountDO updateObj = MpAccountConvert.INSTANCE.convert(updateReqVO);
         mpAccountMapper.updateById(updateObj);
 
-        // 发送刷新消息
-        mpAccountProducer.sendAccountRefreshMessage();
+        // 刷新缓存
+        initLocalCache();
     }
 
     @Override
@@ -112,8 +136,8 @@ public class MpAccountServiceImpl implements MpAccountService {
         // 删除
         mpAccountMapper.deleteById(id);
 
-        // 发送刷新消息
-        mpAccountProducer.sendAccountRefreshMessage();
+        // 刷新缓存
+        initLocalCache();
     }
 
     private MpAccountDO validateAccountExists(Long id) {

+ 0 - 2
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java

@@ -6,8 +6,6 @@ import lombok.Data;
 /**
  * 支付单信息 Response DTO
  *
- * TODO 芋艿:还没定好字段
- *
  * @author 芋道源码
  */
 @Data

+ 0 - 2
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java

@@ -8,8 +8,6 @@ import java.time.LocalDateTime;
 /**
  * 退款单信息 Response DTO
  *
- * TODO 芋艿:还没定好字段
- *
  * @author 芋道源码
  */
 @Data

+ 0 - 6
yudao-module-pay/yudao-module-pay-biz/pom.xml

@@ -61,12 +61,6 @@
             <artifactId>yudao-spring-boot-starter-job</artifactId>
         </dependency>
 
-        <!-- 消息队列相关 -->
-        <dependency>
-            <groupId>cn.iocoder.boot</groupId>
-            <artifactId>yudao-spring-boot-starter-mq</artifactId>
-        </dependency>
-
         <!-- Test 测试相关 -->
         <dependency>
             <groupId>cn.iocoder.boot</groupId>

+ 8 - 6
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/RedisKeyConstants.java

@@ -1,8 +1,5 @@
 package cn.iocoder.yudao.module.pay.dal.redis;
 
-import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
-import org.redisson.api.RLock;
-
 /**
  * 支付 Redis Key 枚举类
  *
@@ -10,9 +7,14 @@ import org.redisson.api.RLock;
  */
 public interface RedisKeyConstants {
 
-    RedisKeyDefine PAY_NOTIFY_LOCK = new RedisKeyDefine("通知任务的分布式锁",
-            "pay_notify:lock:%d", // 参数来自 DefaultLockKeyBuilder 类
-            RedisKeyDefine.KeyTypeEnum.HASH, RLock.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); // Redisson 的 Lock 锁,使用 Hash 数据结构
+    /**
+     * 通知任务的分布式锁
+     *
+     * KEY 格式:pay_notify:lock:%d // 参数来自 DefaultLockKeyBuilder 类
+     * VALUE 数据格式:HASH // RLock.class:Redisson 的 Lock 锁,使用 Hash 数据结构
+     * 过期时间:不固定
+     */
+    String PAY_NOTIFY_LOCK = "pay_notify:lock:%d";
 
     /**
      * 支付序号的缓存

+ 1 - 1
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/notify/PayNotifyLockRedisDAO.java

@@ -33,7 +33,7 @@ public class PayNotifyLockRedisDAO {
     }
 
     private static String formatKey(Long id) {
-        return String.format(PAY_NOTIFY_LOCK.getKeyTemplate(), id);
+        return String.format(PAY_NOTIFY_LOCK, id);
     }
 
 }

+ 3 - 4
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java

@@ -15,7 +15,6 @@ import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelUpdateR
 import cn.iocoder.yudao.module.pay.convert.channel.PayChannelConvert;
 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
 import cn.iocoder.yudao.module.pay.dal.mysql.channel.PayChannelMapper;
-import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
@@ -112,7 +111,7 @@ public class PayChannelServiceImpl implements PayChannelService {
         channelMapper.insert(channel);
 
         // 刷新缓存
-        refreshLocalCache();
+        initLocalCache();
         return channel.getId();
     }
 
@@ -127,7 +126,7 @@ public class PayChannelServiceImpl implements PayChannelService {
         channelMapper.updateById(channel);
 
         // 刷新缓存
-        refreshLocalCache();
+        initLocalCache();
     }
 
     /**
@@ -160,7 +159,7 @@ public class PayChannelServiceImpl implements PayChannelService {
         channelMapper.deleteById(id);
 
         // 刷新缓存
-        refreshLocalCache();
+        initLocalCache();
     }
 
     private PayChannelDO validateChannelExists(Long id) {

+ 1 - 1
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java

@@ -44,7 +44,7 @@ public interface AdminUserApi {
      * @param postIds 岗位数组
      * @return 用户数组
      */
-    List<AdminUserRespDTO> getUsersByPostIds(Collection<Long> postIds);
+    List<AdminUserRespDTO> getUserListByPostIds(Collection<Long> postIds);
 
     /**
      * 获得用户 Map

+ 1 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/permission/PermissionApiImpl.java

@@ -21,7 +21,7 @@ public class PermissionApiImpl implements PermissionApi {
 
     @Override
     public Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds) {
-        return permissionService.getUserRoleIdListByRoleIds(roleIds);
+        return permissionService.getUserRoleIdListByRoleId(roleIds);
     }
 
     @Override

+ 1 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java

@@ -40,7 +40,7 @@ public class AdminUserApiImpl implements AdminUserApi {
     }
 
     @Override
-    public List<AdminUserRespDTO> getUsersByPostIds(Collection<Long> postIds) {
+    public List<AdminUserRespDTO> getUserListByPostIds(Collection<Long> postIds) {
         List<AdminUserDO> users = userService.getUserListByPostIds(postIds);
         return UserConvert.INSTANCE.convertList4(users);
     }

+ 1 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http

@@ -2,6 +2,7 @@
 POST {{baseUrl}}/system/auth/login
 Content-Type: application/json
 tenant-id: {{adminTenentId}}
+tag: Yunai.local
 
 {
   "username": "admin",

+ 18 - 26
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.controller.admin.auth;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
 import cn.iocoder.yudao.framework.security.config.SecurityProperties;
 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
@@ -12,8 +11,8 @@ import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
-import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
 import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
+import cn.iocoder.yudao.module.system.service.permission.MenuService;
 import cn.iocoder.yudao.module.system.service.permission.PermissionService;
 import cn.iocoder.yudao.module.system.service.permission.RoleService;
 import cn.iocoder.yudao.module.system.service.social.SocialUserService;
@@ -34,9 +33,9 @@ import java.util.List;
 import java.util.Set;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.obtainAuthorization;
-import static java.util.Collections.singleton;
 
 @Tag(name = "管理后台 - 认证")
 @RestController
@@ -52,6 +51,8 @@ public class AuthController {
     @Resource
     private RoleService roleService;
     @Resource
+    private MenuService menuService;
+    @Resource
     private PermissionService permissionService;
     @Resource
     private SocialUserService socialUserService;
@@ -91,33 +92,24 @@ public class AuthController {
     @GetMapping("/get-permission-info")
     @Operation(summary = "获取登录用户的权限信息")
     public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
-        // 获得用户信息
+        // 1.1 获得用户信息
         AdminUserDO user = userService.getUser(getLoginUserId());
         if (user == null) {
             return null;
         }
-        // 获得角色列表
-        Set<Long> roleIds = permissionService.getUserRoleIdsFromCache(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
-        List<RoleDO> roleList = roleService.getRoleListFromCache(roleIds);
-        // 获得菜单列表
-        List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds,
-                SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType(), MenuTypeEnum.BUTTON.getType()),
-                singleton(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
-        // 拼接结果返回
-        return success(AuthConvert.INSTANCE.convert(user, roleList, menuList));
-    }
 
-    @GetMapping("/list-menus")
-    @Operation(summary = "获得登录用户的菜单列表")
-    public CommonResult<List<AuthMenuRespVO>> getMenuList() {
-        // 获得角色列表
-        Set<Long> roleIds = permissionService.getUserRoleIdsFromCache(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
-        // 获得用户拥有的菜单列表
-        List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds,
-                SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型
-                singleton(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
-        // 转换成 Tree 结构返回
-        return success(AuthConvert.INSTANCE.buildMenuTree(menuList));
+        // 1.2 获得角色列表
+        Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
+        List<RoleDO> roles = roleService.getRoleList(roleIds);
+        roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
+
+        // 1.3 获得菜单列表
+        Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
+        List<MenuDO> menuList = menuService.getMenuList(menuIds);
+        menuList.removeIf(menu -> !CommonStatusEnum.ENABLE.getStatus().equals(menu.getStatus())); // 移除禁用的菜单
+
+        // 2. 拼接结果返回
+        return success(AuthConvert.INSTANCE.convert(user, roles, menuList));
     }
 
     // ========== 短信登录相关 ==========
@@ -149,7 +141,7 @@ public class AuthController {
             @Parameter(name = "redirectUri", description = "回调路径")
     })
     public CommonResult<String> socialLogin(@RequestParam("type") Integer type,
-                                                    @RequestParam("redirectUri") String redirectUri) {
+                                            @RequestParam("redirectUri") String redirectUri) {
         return CommonResult.success(socialUserService.getAuthorizeUrl(type, redirectUri));
     }
 

+ 50 - 2
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java

@@ -6,9 +6,10 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.util.List;
 import java.util.Set;
 
-@Schema(description = "管理后台 - 登录用户的权限信息 Response VO,额外包括用户信息和角色列表")
+@Schema(description = "管理后台 - 登录用户的权限信息 Response VO额外包括用户信息和角色列表")
 @Data
 @NoArgsConstructor
 @AllArgsConstructor
@@ -24,6 +25,9 @@ public class AuthPermissionInfoRespVO {
     @Schema(description = "操作权限数组", requiredMode = Schema.RequiredMode.REQUIRED)
     private Set<String> permissions;
 
+    @Schema(description = "菜单树", required = true)
+    private List<MenuVO> menus;
+
     @Schema(description = "用户信息 VO")
     @Data
     @NoArgsConstructor
@@ -37,9 +41,53 @@ public class AuthPermissionInfoRespVO {
         @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
         private String nickname;
 
-        @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://www.iocoder.cn/xx.jpg")
+        @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.jpg")
         private String avatar;
 
     }
 
+    @Schema(description = "管理后台 - 登录用户的菜单信息 Response VO")
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @Builder
+    public static class MenuVO {
+
+        @Schema(description = "菜单名称", required = true, example = "芋道")
+        private Long id;
+
+        @Schema(description = "父菜单 ID", required = true, example = "1024")
+        private Long parentId;
+
+        @Schema(description = "菜单名称", required = true, example = "芋道")
+        private String name;
+
+        @Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post")
+        private String path;
+
+        @Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index")
+        private String component;
+
+        @Schema(description = "组件名", example = "SystemUser")
+        private String componentName;
+
+        @Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list")
+        private String icon;
+
+        @Schema(description = "是否可见", required = true, example = "false")
+        private Boolean visible;
+
+        @Schema(description = "是否缓存", required = true, example = "false")
+        private Boolean keepAlive;
+
+        @Schema(description = "是否总是显示", example = "false")
+        private Boolean alwaysShow;
+
+        /**
+         * 子路由
+         */
+        private List<MenuVO> children;
+
+    }
+
 }

+ 3 - 3
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/log/MailLogBaseVO.java

@@ -11,9 +11,9 @@ import java.util.Map;
 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
 
 /**
-* 邮件日志 Base VO,提供给添加、修改、详细的子 VO 使用
-* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
-*/
+ * 邮件日志 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
 @Data
 public class MailLogBaseVO {
 

+ 3 - 3
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java

@@ -37,10 +37,10 @@ public class PermissionController {
 
     @Operation(summary = "获得角色拥有的菜单编号")
     @Parameter(name = "roleId", description = "角色编号", required = true)
-    @GetMapping("/list-role-resources")
+    @GetMapping("/list-role-menus")
     @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')")
-    public CommonResult<Set<Long>> listRoleMenus(Long roleId) {
-        return success(permissionService.getRoleMenuIds(roleId));
+    public CommonResult<Set<Long>> getRoleMenuList(Long roleId) {
+        return success(permissionService.getRoleMenuListByRoleId(roleId));
     }
 
     @PostMapping("/assign-role-menu")

+ 0 - 3
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/RoleController.http

@@ -40,6 +40,3 @@ tenant-id: {{adminTenentId}}
 GET {{baseUrl}}/system/role/page?pageNo=1&pageSize=10
 Authorization: Bearer {{token}}
 tenant-id: {{adminTenentId}}
-
-###
-

+ 1 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/permission/PermissionAssignRoleDataScopeReqVO.java

@@ -20,7 +20,7 @@ public class PermissionAssignRoleDataScopeReqVO {
 //    TODO 这里要多一个枚举校验
     private Integer dataScope;
 
-    @Schema(description = "部门编号列表,只有范围类型为 DEPT_CUSTOM 时,该字段才需要", example = "1,3,5")
+    @Schema(description = "部门编号列表只有范围类型为 DEPT_CUSTOM 时,该字段才需要", example = "1,3,5")
     private Set<Long> dataScopeDeptIds = Collections.emptySet(); // 兜底
 
 }

+ 3 - 3
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sensitiveword/vo/SensitiveWordBaseVO.java

@@ -7,9 +7,9 @@ import javax.validation.constraints.NotNull;
 import java.util.List;
 
 /**
-* 敏感词 Base VO,提供给添加、修改、详细的子 VO 使用
-* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
-*/
+ * 敏感词 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
 @Data
 public class SensitiveWordBaseVO {
 

+ 3 - 3
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/tenant/TenantBaseVO.java

@@ -7,9 +7,9 @@ import javax.validation.constraints.*;
 import java.time.LocalDateTime;
 
 /**
-* 租户 Base VO,提供给添加、修改、详细的子 VO 使用
-* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
-*/
+ * 租户 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
 @Data
 public class TenantBaseVO {
 

+ 1 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/profile/UserProfileUpdateReqVO.java

@@ -25,7 +25,7 @@ public class UserProfileUpdateReqVO {
     @Length(min = 11, max = 11, message = "手机号长度必须 11 位")
     private String mobile;
 
-    @Schema(description = "用户性别-参见 SexEnum 枚举类", example = "1")
+    @Schema(description = "用户性别参见 SexEnum 枚举类", example = "1")
     private Integer sex;
 
 }

+ 1 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserExportReqVO.java

@@ -29,7 +29,7 @@ public class UserExportReqVO {
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] createTime;
 
-    @Schema(description = "部门编号,同时筛选子部门", example = "1024")
+    @Schema(description = "部门编号同时筛选子部门", example = "1024")
     private Long deptId;
 
 }

+ 1 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserPageItemRespVO.java

@@ -6,7 +6,7 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 
-@Schema(description = "管理后台 - 用户分页时的信息 Response VO,相比用户基本信息来说,会多部门信息")
+@Schema(description = "管理后台 - 用户分页时的信息 Response VO相比用户基本信息来说,会多部门信息")
 @Data
 @NoArgsConstructor
 @AllArgsConstructor

+ 4 - 2
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserUpdateStatusReqVO.java

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.module.system.controller.admin.user.vo.user;
 
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
@@ -13,9 +15,9 @@ public class UserUpdateStatusReqVO {
     @NotNull(message = "角色编号不能为空")
     private Long id;
 
-    @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @Schema(description = "状态见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @NotNull(message = "状态不能为空")
-//    @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
+    @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
     private Integer status;
 
 }

+ 16 - 9
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java

@@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
+import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
 import org.slf4j.LoggerFactory;
@@ -27,13 +28,16 @@ public interface AuthConvert {
 
     default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) {
         return AuthPermissionInfoRespVO.builder()
-            .user(AuthPermissionInfoRespVO.UserVO.builder().id(user.getId()).nickname(user.getNickname()).avatar(user.getAvatar()).build())
-            .roles(convertSet(roleList, RoleDO::getCode))
-            .permissions(convertSet(menuList, MenuDO::getPermission))
-            .build();
+                .user(AuthPermissionInfoRespVO.UserVO.builder().id(user.getId()).nickname(user.getNickname()).avatar(user.getAvatar()).build())
+                .roles(convertSet(roleList, RoleDO::getCode))
+                // 权限标识信息
+                .permissions(convertSet(menuList, MenuDO::getPermission))
+                // 菜单树
+                .menus(buildMenuTree(menuList))
+                .build();
     }
 
-    AuthMenuRespVO convertTreeNode(MenuDO menu);
+    AuthPermissionInfoRespVO.MenuVO convertTreeNode(MenuDO menu);
 
     /**
      * 将菜单列表,构建成菜单树
@@ -41,20 +45,23 @@ public interface AuthConvert {
      * @param menuList 菜单列表
      * @return 菜单树
      */
-    default List<AuthMenuRespVO> buildMenuTree(List<MenuDO> menuList) {
+    default List<AuthPermissionInfoRespVO.MenuVO> buildMenuTree(List<MenuDO> menuList) {
+        // 移除按钮
+        menuList.removeIf(menu -> menu.getType().equals(MenuTypeEnum.BUTTON.getType()));
         // 排序,保证菜单的有序性
         menuList.sort(Comparator.comparing(MenuDO::getSort));
+
         // 构建菜单树
         // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。
-        Map<Long, AuthMenuRespVO> treeNodeMap = new LinkedHashMap<>();
+        Map<Long, AuthPermissionInfoRespVO.MenuVO> treeNodeMap = new LinkedHashMap<>();
         menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AuthConvert.INSTANCE.convertTreeNode(menu)));
         // 处理父子关系
         treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(ID_ROOT)).forEach(childNode -> {
             // 获得父节点
-            AuthMenuRespVO parentNode = treeNodeMap.get(childNode.getParentId());
+            AuthPermissionInfoRespVO.MenuVO parentNode = treeNodeMap.get(childNode.getParentId());
             if (parentNode == null) {
                 LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]",
-                    childNode.getId(), childNode.getParentId());
+                        childNode.getId(), childNode.getParentId());
                 return;
             }
             // 将自己添加到父节点中

+ 5 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/DeptMapper.java

@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqV
 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.Collection;
 import java.util.List;
 
 @Mapper
@@ -25,4 +26,8 @@ public interface DeptMapper extends BaseMapperX<DeptDO> {
         return selectCount(DeptDO::getParentId, parentId);
     }
 
+    default List<DeptDO> selectListByParentId(Collection<Long> parentIds) {
+        return selectList(DeptDO::getParentId, parentIds);
+    }
+
 }

+ 3 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/MenuMapper.java

@@ -25,4 +25,7 @@ public interface MenuMapper extends BaseMapperX<MenuDO> {
                 .eqIfPresent(MenuDO::getStatus, reqVO.getStatus()));
     }
 
+    default List<MenuDO> selectListByPermission(String permission) {
+        return selectList(MenuDO::getPermission, permission);
+    }
 }

+ 8 - 6
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMenuMapper.java

@@ -3,9 +3,7 @@ package cn.iocoder.yudao.module.system.dal.mysql.permission;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.apache.ibatis.annotations.Mapper;
-import org.springframework.stereotype.Repository;
 
 import java.util.Collection;
 import java.util.List;
@@ -13,14 +11,18 @@ import java.util.List;
 @Mapper
 public interface RoleMenuMapper extends BaseMapperX<RoleMenuDO> {
 
-    @Repository
-    class BatchInsertMapper extends ServiceImpl<RoleMenuMapper, RoleMenuDO> {
-    }
-
     default List<RoleMenuDO> selectListByRoleId(Long roleId) {
         return selectList(RoleMenuDO::getRoleId, roleId);
     }
 
+    default List<RoleMenuDO> selectListByRoleId(Collection<Long> roleIds) {
+        return selectList(RoleMenuDO::getRoleId, roleIds);
+    }
+
+    default List<RoleMenuDO> selectListByMenuId(Long menuId) {
+        return selectList(RoleMenuDO::getMenuId, menuId);
+    }
+
     default void deleteListByRoleIdAndMenuIds(Long roleId, Collection<Long> menuIds) {
         delete(new LambdaQueryWrapper<RoleMenuDO>()
                 .eq(RoleMenuDO::getRoleId, roleId)

+ 5 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sensitiveword/SensitiveWordMapper.java

@@ -7,7 +7,9 @@ import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.Sensitiv
 import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
 
+import java.time.LocalDateTime;
 import java.util.List;
 
 /**
@@ -40,4 +42,7 @@ public interface SensitiveWordMapper extends BaseMapperX<SensitiveWordDO> {
         return selectOne(SensitiveWordDO::getName, name);
     }
 
+    @Select("SELECT COUNT(*) FROM system_sensitive_word WHERE update_time > #{maxUpdateTime}")
+    Long selectCountByUpdateTimeGt(LocalDateTime maxTime);
+
 }

+ 6 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsChannelMapper.java

@@ -6,6 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+import java.time.LocalDateTime;
 
 @Mapper
 public interface SmsChannelMapper extends BaseMapperX<SmsChannelDO> {
@@ -18,4 +21,7 @@ public interface SmsChannelMapper extends BaseMapperX<SmsChannelDO> {
                 .orderByDesc(SmsChannelDO::getId));
     }
 
+    @Select("SELECT COUNT(*) FROM system_sms_channel WHERE update_time > #{maxUpdateTime}")
+    Long selectCountByUpdateTimeGt(LocalDateTime maxTime);
+
 }

+ 86 - 14
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java

@@ -1,12 +1,7 @@
 package cn.iocoder.yudao.module.system.dal.redis;
 
-import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
 
-import java.time.Duration;
-
-import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING;
-
 /**
  * System Redis Key 枚举类
  *
@@ -14,16 +9,93 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.S
  */
 public interface RedisKeyConstants {
 
-    RedisKeyDefine CAPTCHA_CODE = new RedisKeyDefine("验证码的缓存",
-            "captcha_code:%s", // 参数为 uuid
-            STRING, String.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
+    /**
+     * 指定部门的所有子部门编号数组的缓存
+     * <p>
+     * KEY 格式:dept_children_ids:{id}
+     * VALUE 数据类型:String 子部门编号集合
+     */
+    String DEPT_CHILDREN_ID_LIST = "dept_children_ids";
+
+    /**
+     * 角色的缓存
+     * <p>
+     * KEY 格式:role:{id}
+     * VALUE 数据类型:String 角色信息
+     */
+    String ROLE = "role";
+
+    /**
+     * 用户拥有的角色编号的缓存
+     * <p>
+     * KEY 格式:user_role_ids:{userId}
+     * VALUE 数据类型:String 角色编号集合
+     */
+    String USER_ROLE_ID_LIST = "user_role_ids";
+
+    /**
+     * 拥有指定菜单的角色编号的缓存
+     * <p>
+     * KEY 格式:user_role_ids:{menuId}
+     * VALUE 数据类型:String 角色编号集合
+     */
+    String MENU_ROLE_ID_LIST = "menu_role_ids";
+
+    /**
+     * 拥有权限对应的菜单编号数组的缓存
+     * <p>
+     * KEY 格式:permission_menu_ids:{permission}
+     * VALUE 数据类型:String 菜单编号数组
+     */
+    String PERMISSION_MENU_ID_LIST = "permission_menu_ids";
+
+    /**
+     * OAuth2 客户端的缓存
+     * <p>
+     * KEY 格式:user:{id}
+     * VALUE 数据类型:String 客户端信息
+     */
+    String OAUTH_CLIENT = "oauth_client";
+
+    /**
+     * 访问令牌的缓存
+     * <p>
+     * KEY 格式:oauth2_access_token:{token}
+     * VALUE 数据类型:String 访问令牌信息 {@link OAuth2AccessTokenDO}
+     * <p>
+     * 由于动态过期时间,使用 RedisTemplate 操作
+     */
+    String OAUTH2_ACCESS_TOKEN = "oauth2_access_token:%s";
+
+    /**
+     * 站内信模版的缓存
+     * <p>
+     * KEY 格式:notify_template:{code}
+     * VALUE 数据格式:String 模版信息
+     */
+    String NOTIFY_TEMPLATE = "notify_template";
 
-    RedisKeyDefine OAUTH2_ACCESS_TOKEN = new RedisKeyDefine("访问令牌的缓存",
-            "oauth2_access_token:%s", // 参数为访问令牌 token
-            STRING, OAuth2AccessTokenDO.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
+    /**
+     * 邮件账号的缓存
+     * <p>
+     * KEY 格式:sms_template:{id}
+     * VALUE 数据格式:String 账号信息
+     */
+    String MAIL_ACCOUNT = "mail_account";
 
-    RedisKeyDefine SOCIAL_AUTH_STATE = new RedisKeyDefine("社交登陆的 state", // 注意,它是被 JustAuth 的 justauth.type.prefix 使用到
-            "social_auth_state:%s", // 参数为 state
-            STRING, String.class, Duration.ofHours(24)); // 值为 state
+    /**
+     * 邮件模版的缓存
+     * <p>
+     * KEY 格式:mail_template:{code}
+     * VALUE 数据格式:String 模版信息
+     */
+    String MAIL_TEMPLATE = "mail_template";
 
+    /**
+     * 短信模版的缓存
+     * <p>
+     * KEY 格式:sms_template:{id}
+     * VALUE 数据格式:String 模版信息
+     */
+    String SMS_TEMPLATE = "sms_template";
 }

+ 0 - 41
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/common/CaptchaRedisDAO.java

@@ -1,41 +0,0 @@
-package cn.iocoder.yudao.module.system.dal.redis.common;
-
-import org.springframework.data.redis.core.StringRedisTemplate;
-import org.springframework.stereotype.Repository;
-
-import javax.annotation.Resource;
-import java.time.Duration;
-
-import static cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants.CAPTCHA_CODE;
-
-/**
- * 验证码的 Redis DAO
- *
- * @author 芋道源码
- */
-@Repository
-public class CaptchaRedisDAO {
-
-    @Resource
-    private StringRedisTemplate stringRedisTemplate;
-
-    public String get(String uuid) {
-        String redisKey = formatKey(uuid);
-        return stringRedisTemplate.opsForValue().get(redisKey);
-    }
-
-    public void set(String uuid, String code, Duration timeout) {
-        String redisKey = formatKey(uuid);
-        stringRedisTemplate.opsForValue().set(redisKey, code, timeout);
-    }
-
-    public void delete(String uuid) {
-        String redisKey = formatKey(uuid);
-        stringRedisTemplate.delete(redisKey);
-    }
-
-    private static String formatKey(String uuid) {
-        return String.format(CAPTCHA_CODE.getKeyTemplate(), uuid);
-    }
-
-}

+ 1 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/oauth2/OAuth2AccessTokenRedisDAO.java

@@ -53,7 +53,7 @@ public class OAuth2AccessTokenRedisDAO {
     }
 
     private static String formatKey(String accessToken) {
-        return String.format(OAUTH2_ACCESS_TOKEN.getKeyTemplate(), accessToken);
+        return String.format(OAUTH2_ACCESS_TOKEN, accessToken);
     }
 
 }

+ 0 - 29
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/auth/OAuth2ClientRefreshConsumer.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.consumer.auth;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.system.mq.message.auth.OAuth2ClientRefreshMessage;
-import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link OAuth2ClientRefreshMessage} 的消费者
- *
- * @author 芋道源码
- */
-@Component
-@Slf4j
-public class OAuth2ClientRefreshConsumer extends AbstractChannelMessageListener<OAuth2ClientRefreshMessage> {
-
-    @Resource
-    private OAuth2ClientService oauth2ClientService;
-
-    @Override
-    public void onMessage(OAuth2ClientRefreshMessage message) {
-        log.info("[onMessage][收到 OAuth2Client 刷新消息]");
-        oauth2ClientService.initLocalCache();
-    }
-
-}

+ 0 - 29
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/dept/DeptRefreshConsumer.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.consumer.dept;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.system.mq.message.dept.DeptRefreshMessage;
-import cn.iocoder.yudao.module.system.service.dept.DeptService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link DeptRefreshMessage} 的消费者
- *
- * @author 芋道源码
- */
-@Component
-@Slf4j
-public class DeptRefreshConsumer extends AbstractChannelMessageListener<DeptRefreshMessage> {
-
-    @Resource
-    private DeptService deptService;
-
-    @Override
-    public void onMessage(DeptRefreshMessage message) {
-        log.info("[onMessage][收到 Dept 刷新消息]");
-        deptService.initLocalCache();
-    }
-
-}

+ 0 - 31
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailAccountRefreshConsumer.java

@@ -1,31 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.consumer.mail;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.system.mq.message.mail.MailAccountRefreshMessage;
-import cn.iocoder.yudao.module.system.mq.message.mail.MailTemplateRefreshMessage;
-import cn.iocoder.yudao.module.system.service.mail.MailAccountService;
-import cn.iocoder.yudao.module.system.service.mail.MailTemplateService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link MailAccountRefreshMessage} 的消费者
- *
- * @author wangjingyi
- */
-@Component
-@Slf4j
-public class MailAccountRefreshConsumer extends AbstractChannelMessageListener<MailAccountRefreshMessage> {
-
-    @Resource
-    private MailAccountService mailAccountService;
-
-    @Override
-    public void onMessage(MailAccountRefreshMessage message) {
-        log.info("[onMessage][收到 Mail Account 刷新信息]");
-        mailAccountService.initLocalCache();
-    }
-
-}

+ 0 - 29
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailTemplateRefreshConsumer.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.consumer.mail;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.system.mq.message.mail.MailTemplateRefreshMessage;
-import cn.iocoder.yudao.module.system.service.mail.MailTemplateService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link MailTemplateRefreshMessage} 的消费者
- *
- * @author wangjingyi
- */
-@Component
-@Slf4j
-public class MailTemplateRefreshConsumer extends AbstractChannelMessageListener<MailTemplateRefreshMessage> {
-
-    @Resource
-    private MailTemplateService mailTemplateService;
-
-    @Override
-    public void onMessage(MailTemplateRefreshMessage message) {
-        log.info("[onMessage][收到 Mail Template 刷新信息]");
-        mailTemplateService.initLocalCache();
-    }
-
-}

+ 0 - 29
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/notify/NotifyTemplateRefreshConsumer.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.consumer.notify;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.system.mq.message.notify.NotifyTemplateRefreshMessage;
-import cn.iocoder.yudao.module.system.service.notify.NotifyTemplateService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link NotifyTemplateRefreshMessage} 的消费者
- *
- * @author xrcoder
- */
-@Component
-@Slf4j
-public class NotifyTemplateRefreshConsumer extends AbstractChannelMessageListener<NotifyTemplateRefreshMessage> {
-
-    @Resource
-    private NotifyTemplateService notifyTemplateService;
-
-    @Override
-    public void onMessage(NotifyTemplateRefreshMessage message) {
-        log.info("[onMessage][收到 NotifyTemplate 刷新消息]");
-        notifyTemplateService.initLocalCache();
-    }
-
-}

+ 0 - 29
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/permission/MenuRefreshConsumer.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.consumer.permission;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.system.mq.message.permission.MenuRefreshMessage;
-import cn.iocoder.yudao.module.system.service.permission.MenuService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link MenuRefreshMessage} 的消费者
- *
- * @author 芋道源码
- */
-@Component
-@Slf4j
-public class MenuRefreshConsumer extends AbstractChannelMessageListener<MenuRefreshMessage> {
-
-    @Resource
-    private MenuService menuService;
-
-    @Override
-    public void onMessage(MenuRefreshMessage message) {
-        log.info("[onMessage][收到 Menu 刷新消息]");
-        menuService.initLocalCache();
-    }
-
-}

+ 0 - 29
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/permission/RoleMenuRefreshConsumer.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.consumer.permission;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.system.mq.message.permission.RoleMenuRefreshMessage;
-import cn.iocoder.yudao.module.system.service.permission.PermissionService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link RoleMenuRefreshMessage} 的消费者
- *
- * @author 芋道源码
- */
-@Component
-@Slf4j
-public class RoleMenuRefreshConsumer extends AbstractChannelMessageListener<RoleMenuRefreshMessage> {
-
-    @Resource
-    private PermissionService permissionService;
-
-    @Override
-    public void onMessage(RoleMenuRefreshMessage message) {
-        log.info("[onMessage][收到 Role 与 Menu 的关联刷新消息]");
-        permissionService.initLocalCache();
-    }
-
-}

+ 0 - 29
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/permission/RoleRefreshConsumer.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.consumer.permission;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.system.mq.message.permission.RoleRefreshMessage;
-import cn.iocoder.yudao.module.system.service.permission.RoleService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link RoleRefreshMessage} 的消费者
- *
- * @author 芋道源码
- */
-@Component
-@Slf4j
-public class RoleRefreshConsumer extends AbstractChannelMessageListener<RoleRefreshMessage> {
-
-    @Resource
-    private RoleService roleService;
-
-    @Override
-    public void onMessage(RoleRefreshMessage message) {
-        log.info("[onMessage][收到 Role 刷新消息]");
-        roleService.initLocalCache();
-    }
-
-}

+ 0 - 29
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/permission/UserRoleRefreshConsumer.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.consumer.permission;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.system.mq.message.permission.UserRoleRefreshMessage;
-import cn.iocoder.yudao.module.system.service.permission.PermissionService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link UserRoleRefreshMessage} 的消费者
- *
- * @author 芋道源码
- */
-@Component
-@Slf4j
-public class UserRoleRefreshConsumer extends AbstractChannelMessageListener<UserRoleRefreshMessage> {
-
-    @Resource
-    private PermissionService permissionService;
-
-    @Override
-    public void onMessage(UserRoleRefreshMessage message) {
-        log.info("[onMessage][收到 User 与 Role 的关联刷新消息]");
-        permissionService.initLocalCache();
-    }
-
-}

+ 0 - 29
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sensitiveword/SensitiveWordRefreshConsumer.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.consumer.sensitiveword;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.system.mq.message.sensitiveword.SensitiveWordRefreshMessage;
-import cn.iocoder.yudao.module.system.service.sensitiveword.SensitiveWordService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link SensitiveWordRefreshMessage} 的消费者
- *
- * @author 芋道源码
- */
-@Component
-@Slf4j
-public class SensitiveWordRefreshConsumer extends AbstractChannelMessageListener<SensitiveWordRefreshMessage> {
-
-    @Resource
-    private SensitiveWordService sensitiveWordService;
-
-    @Override
-    public void onMessage(SensitiveWordRefreshMessage message) {
-        log.info("[onMessage][收到 SensitiveWord 刷新消息]");
-        sensitiveWordService.initLocalCache();
-    }
-
-}

+ 0 - 29
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsChannelRefreshConsumer.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.system.mq.consumer.sms;
-
-import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
-import cn.iocoder.yudao.module.system.mq.message.sms.SmsChannelRefreshMessage;
-import cn.iocoder.yudao.module.system.service.sms.SmsChannelService;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 针对 {@link SmsChannelRefreshMessage} 的消费者
- *
- * @author 芋道源码
- */
-@Component
-@Slf4j
-public class SmsChannelRefreshConsumer extends AbstractChannelMessageListener<SmsChannelRefreshMessage> {
-
-    @Resource
-    private SmsChannelService smsChannelService;
-
-    @Override
-    public void onMessage(SmsChannelRefreshMessage message) {
-        log.info("[onMessage][收到 SmsChannel 刷新消息]");
-        smsChannelService.initLocalCache();
-    }
-
-}

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott