Commit bf3e848c171c6e63c94f09cbb2df2fee01c2b9b3

Authored by YunaiV
2 parents 6a387387 7a49e45b

Merge branch 'master' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into feature/mall_product

Showing 169 changed files with 2097 additions and 3939 deletions

Too many changes.

To preserve performance only 100 of 169 files are displayed.

Docker-HOWTO.md
1 # Docker Build & Up 1 # Docker Build & Up
2 2
3 目标: 快速部署体验系统,帮助了解系统之间的依赖关系。 3 目标: 快速部署体验系统,帮助了解系统之间的依赖关系。
  4 +依赖:docker compose v2,删除`name: yudao-system`,降低`version`版本为`3.3`以下,支持`docker-compose`。
4 5
5 ## 功能文件列表 6 ## 功能文件列表
6 7
7 ```text 8 ```text
8 . 9 .
9 -├── Docker-HOWTO.md  
10 -├── docker-compose.yml  
11 -├── docker.env 10 +├── Docker-HOWTO.md
  11 +├── docker-compose.yml
  12 +├── docker.env <-- 提供docker-compose环境变量配置
12 ├── yudao-server 13 ├── yudao-server
13 -│ ├── Dockerfile  
14 -│ └── nginx.conf 14 +│ └── Dockerfile
15 └── yudao-ui-admin 15 └── yudao-ui-admin
16 ├── .dockerignore 16 ├── .dockerignore
17 - └── Dockerfile 17 + ├── Dockerfile
  18 + └── nginx.conf <-- 提供基础配置,gzip压缩、api转发
18 ``` 19 ```
19 20
20 -## Maven build (Optional) 21 +## 构建 jar 包
21 22
22 ```shell 23 ```shell
23 # 创建maven缓存volume 24 # 创建maven缓存volume
@@ -30,29 +31,19 @@ docker run -it --rm --name yudao-maven \ @@ -30,29 +31,19 @@ docker run -it --rm --name yudao-maven \
30 maven mvn clean install package '-Dmaven.test.skip=true' 31 maven mvn clean install package '-Dmaven.test.skip=true'
31 ``` 32 ```
32 33
33 -## Docker Compose Build  
34 -  
35 -```shell  
36 -docker compose --env-file docker.env build  
37 -```  
38 -  
39 -## Docker Compose Up 34 +## 构建启动服务
40 35
41 ```shell 36 ```shell
42 docker compose --env-file docker.env up -d 37 docker compose --env-file docker.env up -d
43 ``` 38 ```
44 39
45 -第一次执行,由于数据库未初始化,因此yudao-server容器会运行失败。执行如下命令初始化数据库: 40 +首次运行会自动构建容器。可以通过`docker compose build [service]`来手动构建所有或某个docker镜像
46 41
47 -```shell  
48 -docker compose exec -T mysql \  
49 - sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" --default-character-set=utf8mb4 ruoyi-vue-pro' \  
50 - < ./sql/mysql/ruoyi-vue-pro.sql  
51 -``` 42 +`--env-file docker.env`为可选参数,只是展示了通过`.env`文件配置容器启动的环境变量,`docker-compose.yml`本身已经提供足够的默认参数来正常运行系统。
52 43
53 -## Server:Port 44 +## 服务器的宿主机端口映射
54 45
55 -- admin: http://localhost:8080  
56 -- API: http://localhost:48080  
57 -- mysql: root/123456, port: 3308 46 +- admin ui: http://localhost:8080
  47 +- api server: http://localhost:48080
  48 +- mysql: root/123456, port: 3306
58 - redis: port: 6379 49 - redis: port: 6379
README.md
@@ -102,7 +102,7 @@ @@ -102,7 +102,7 @@
102 102
103 系统内置多种多种业务功能,可以用于快速你的业务系统: 103 系统内置多种多种业务功能,可以用于快速你的业务系统:
104 104
105 -![功能分层](https://static.iocoder.cn/ruoyi-vue-pro-biz.png) 105 +![功能分层](https://static.iocoder.cn/ruoyi-vue-pro-biz.png?imageView2/2/format/webp)
106 106
107 * 系统功能 107 * 系统功能
108 * 基础设施 108 * 基础设施
docker-compose.yml
1 -version: "3.8" 1 +version: "3.4"
2 2
3 name: yudao-system 3 name: yudao-system
4 4
@@ -9,25 +9,22 @@ services: @@ -9,25 +9,22 @@ services:
9 restart: unless-stopped 9 restart: unless-stopped
10 tty: true 10 tty: true
11 ports: 11 ports:
12 - - 13306:3306 12 + - "3306:3306"
13 environment: 13 environment:
14 MYSQL_DATABASE: ${MYSQL_DATABASE:-ruoyi-vue-pro} 14 MYSQL_DATABASE: ${MYSQL_DATABASE:-ruoyi-vue-pro}
15 MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-123456} 15 MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-123456}
16 volumes: 16 volumes:
17 - mysql:/var/lib/mysql/ 17 - mysql:/var/lib/mysql/
18 - networks:  
19 - - yudao-network 18 + - ./sql/mysql/ruoyi-vue-pro.sql:/docker-entrypoint-initdb.d/ruoyi-vue-pro.sql:ro
20 19
21 redis: 20 redis:
22 container_name: yudao-redis 21 container_name: yudao-redis
23 image: redis:6-alpine 22 image: redis:6-alpine
24 restart: unless-stopped 23 restart: unless-stopped
25 ports: 24 ports:
26 - - 16379:6379 25 + - "6379:6379"
27 volumes: 26 volumes:
28 - redis:/data 27 - redis:/data
29 - networks:  
30 - - yudao-network  
31 28
32 server: 29 server:
33 container_name: yudao-server 30 container_name: yudao-server
@@ -36,7 +33,7 @@ services: @@ -36,7 +33,7 @@ services:
36 image: yudao-server 33 image: yudao-server
37 restart: unless-stopped 34 restart: unless-stopped
38 ports: 35 ports:
39 - - 48080:48080 36 + - "48080:48080"
40 environment: 37 environment:
41 # https://github.com/polovyivan/docker-pass-configs-to-container 38 # https://github.com/polovyivan/docker-pass-configs-to-container
42 SPRING_PROFILES_ACTIVE: local 39 SPRING_PROFILES_ACTIVE: local
@@ -54,8 +51,6 @@ services: @@ -54,8 +51,6 @@ services:
54 --spring.datasource.dynamic.datasource.slave.username=${SLAVE_DATASOURCE_USERNAME:-root} 51 --spring.datasource.dynamic.datasource.slave.username=${SLAVE_DATASOURCE_USERNAME:-root}
55 --spring.datasource.dynamic.datasource.slave.password=${SLAVE_DATASOURCE_PASSWORD:-123456} 52 --spring.datasource.dynamic.datasource.slave.password=${SLAVE_DATASOURCE_PASSWORD:-123456}
56 --spring.redis.host=${REDIS_HOST:-yudao-redis} 53 --spring.redis.host=${REDIS_HOST:-yudao-redis}
57 - networks:  
58 - - yudao-network  
59 depends_on: 54 depends_on:
60 - mysql 55 - mysql
61 - redis 56 - redis
@@ -78,16 +73,10 @@ services: @@ -78,16 +73,10 @@ services:
78 image: yudao-admin 73 image: yudao-admin
79 restart: unless-stopped 74 restart: unless-stopped
80 ports: 75 ports:
81 - - 8080:80  
82 - networks:  
83 - - yudao-network 76 + - "8080:80"
84 depends_on: 77 depends_on:
85 - server 78 - server
86 79
87 -networks:  
88 - yudao-network:  
89 - driver: bridge  
90 -  
91 volumes: 80 volumes:
92 mysql: 81 mysql:
93 driver: local 82 driver: local
@@ -30,7 +30,7 @@ @@ -30,7 +30,7 @@
30 <url>https://github.com/YunaiV/ruoyi-vue-pro</url> 30 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
31 31
32 <properties> 32 <properties>
33 - <revision>1.7.3-snapshot</revision> 33 + <revision>1.8.0-snapshot</revision>
34 <!-- Maven 相关 --> 34 <!-- Maven 相关 -->
35 <java.version>1.8</java.version> 35 <java.version>1.8</java.version>
36 <maven.compiler.source>${java.version}</maven.compiler.source> 36 <maven.compiler.source>${java.version}</maven.compiler.source>
yudao-dependencies/pom.xml
@@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
14 <url>https://github.com/YunaiV/ruoyi-vue-pro</url> 14 <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
15 15
16 <properties> 16 <properties>
17 - <revision>1.7.3-snapshot</revision> 17 + <revision>1.8.0-snapshot</revision>
18 <!-- 统一依赖管理 --> 18 <!-- 统一依赖管理 -->
19 <spring.boot.version>2.7.13</spring.boot.version> 19 <spring.boot.version>2.7.13</spring.boot.version>
20 <!-- Web 相关 --> 20 <!-- Web 相关 -->
@@ -71,7 +71,7 @@ @@ -71,7 +71,7 @@
71 <justauth.version>1.0.1</justauth.version> 71 <justauth.version>1.0.1</justauth.version>
72 <jimureport.version>1.5.8</jimureport.version> 72 <jimureport.version>1.5.8</jimureport.version>
73 <xercesImpl.version>2.12.2</xercesImpl.version> 73 <xercesImpl.version>2.12.2</xercesImpl.version>
74 - <wx-java-mp.version>4.5.0</wx-java-mp.version> 74 + <weixin-java.version>4.5.0</weixin-java.version>
75 </properties> 75 </properties>
76 76
77 <dependencyManagement> 77 <dependencyManagement>
@@ -216,10 +216,9 @@ @@ -216,10 +216,9 @@
216 <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <!-- 多数据源 --> 216 <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <!-- 多数据源 -->
217 <version>${dynamic-datasource.version}</version> 217 <version>${dynamic-datasource.version}</version>
218 </dependency> 218 </dependency>
219 -  
220 <dependency> 219 <dependency>
221 <groupId>com.github.yulichang</groupId> 220 <groupId>com.github.yulichang</groupId>
222 - <artifactId>mybatis-plus-join-boot-starter</artifactId> 221 + <artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 -->
223 <version>${mybatis-plus-join-boot-starter.version}</version> 222 <version>${mybatis-plus-join-boot-starter.version}</version>
224 </dependency> 223 </dependency>
225 224
@@ -601,8 +600,23 @@ @@ -601,8 +600,23 @@
601 600
602 <dependency> 601 <dependency>
603 <groupId>com.github.binarywang</groupId> 602 <groupId>com.github.binarywang</groupId>
  603 + <artifactId>weixin-java-pay</artifactId>
  604 + <version>${weixin-java.version}</version>
  605 + </dependency>
  606 + <dependency>
  607 + <groupId>com.github.binarywang</groupId>
  608 + <artifactId>weixin-java-mp</artifactId>
  609 + <version>${weixin-java.version}</version>
  610 + </dependency>
  611 + <dependency>
  612 + <groupId>com.github.binarywang</groupId>
604 <artifactId>wx-java-mp-spring-boot-starter</artifactId> 613 <artifactId>wx-java-mp-spring-boot-starter</artifactId>
605 - <version>${wx-java-mp.version}</version> 614 + <version>${weixin-java.version}</version>
  615 + </dependency>
  616 + <dependency>
  617 + <groupId>com.github.binarywang</groupId>
  618 + <artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
  619 + <version>${weixin-java.version}</version>
606 </dependency> 620 </dependency>
607 621
608 <!-- 积木报表--> 622 <!-- 积木报表-->
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
@@ -164,7 +164,7 @@ public class CollectionUtils { @@ -164,7 +164,7 @@ public class CollectionUtils {
164 return from.stream().filter(predicate).findFirst().orElse(null); 164 return from.stream().filter(predicate).findFirst().orElse(null);
165 } 165 }
166 166
167 - public static <T, V extends Comparable<? super V>> V getMaxValue(List<T> from, Function<T, V> valueFunc) { 167 + public static <T, V extends Comparable<? super V>> V getMaxValue(Collection<T> from, Function<T, V> valueFunc) {
168 if (CollUtil.isEmpty(from)) { 168 if (CollUtil.isEmpty(from)) {
169 return null; 169 return null;
170 } 170 }
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; @@ -4,11 +4,11 @@ import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.ReflectUtil; 4 import cn.hutool.core.util.ReflectUtil;
5 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 5 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
6 import cn.iocoder.yudao.framework.common.util.collection.SetUtils; 6 import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
7 -import cn.iocoder.yudao.module.system.api.permission.PermissionApi;  
8 -import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;  
9 import cn.iocoder.yudao.framework.security.core.LoginUser; 7 import cn.iocoder.yudao.framework.security.core.LoginUser;
10 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; 8 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
11 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; 9 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
  10 +import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
  11 +import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
12 import net.sf.jsqlparser.expression.Alias; 12 import net.sf.jsqlparser.expression.Alias;
13 import net.sf.jsqlparser.expression.Expression; 13 import net.sf.jsqlparser.expression.Expression;
14 import org.junit.jupiter.api.BeforeEach; 14 import org.junit.jupiter.api.BeforeEach;
@@ -23,6 +23,7 @@ import static cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataP @@ -23,6 +23,7 @@ import static cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataP
23 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; 23 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
24 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; 24 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
25 import static org.junit.jupiter.api.Assertions.*; 25 import static org.junit.jupiter.api.Assertions.*;
  26 +import static org.mockito.ArgumentMatchers.eq;
26 import static org.mockito.ArgumentMatchers.same; 27 import static org.mockito.ArgumentMatchers.same;
27 import static org.mockito.Mockito.mockStatic; 28 import static org.mockito.Mockito.mockStatic;
28 import static org.mockito.Mockito.when; 29 import static org.mockito.Mockito.when;
@@ -73,6 +74,8 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { @@ -73,6 +74,8 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
73 LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) 74 LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
74 .setUserType(UserTypeEnum.ADMIN.getValue())); 75 .setUserType(UserTypeEnum.ADMIN.getValue()));
75 securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); 76 securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
  77 + // mock 方法(permissionApi 返回 null)
  78 + when(permissionApi.getDeptDataPermission(eq(loginUser.getId()))).thenReturn(null);
76 79
77 // 调用 80 // 调用
78 NullPointerException exception = assertThrows(NullPointerException.class, 81 NullPointerException exception = assertThrows(NullPointerException.class,
yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml
@@ -63,9 +63,7 @@ @@ -63,9 +63,7 @@
63 <dependency> 63 <dependency>
64 <groupId>com.github.binarywang</groupId> 64 <groupId>com.github.binarywang</groupId>
65 <artifactId>weixin-java-pay</artifactId> 65 <artifactId>weixin-java-pay</artifactId>
66 - <version>4.5.0</version>  
67 </dependency> 66 </dependency>
68 - <!-- TODO 芋艿:清理 -->  
69 67
70 <!-- Test 测试相关 --> 68 <!-- Test 测试相关 -->
71 <dependency> 69 <dependency>
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisKeyDefine.java deleted
1 -package cn.iocoder.yudao.framework.tenant.core.redis;  
2 -  
3 -import cn.hutool.core.util.ArrayUtil;  
4 -import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;  
5 -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;  
6 -  
7 -import java.time.Duration;  
8 -  
9 -/**  
10 - * 多租户拓展的 RedisKeyDefine 实现类  
11 - *  
12 - * 由于 Redis 不同于 MySQL 有 column 字段,无法通过类似 WHERE tenant_id = ? 的方式过滤  
13 - * 所以需要通过在 Redis Key 上增加后缀的方式,进行租户之间的隔离。具体的步骤是:  
14 - * 1. 假设 Redis Key 是 user:%d,示例是 user:1;对应到多租户的 Redis Key 是 user:%d:%d,  
15 - * 2. 在 Redis DAO 中,需要使用 {@link #formatKey(Object...)} 方法,进行 Redis Key 的格式化  
16 - *  
17 - * 注意,大多数情况下,并不用使用 TenantRedisKeyDefine 实现。主要的使用场景,还是 Redis Key 可能存在冲突的情况。  
18 - * 例如说,租户 1 和 2 都有一个手机号作为 Key,则他们会存在冲突的问题  
19 - *  
20 - * @author 芋道源码  
21 - */  
22 -public class TenantRedisKeyDefine extends RedisKeyDefine {  
23 -  
24 - /**  
25 - * 多租户的 KEY 模板  
26 - */  
27 - private static final String KEY_TEMPLATE_SUFFIX = ":%d";  
28 -  
29 - public TenantRedisKeyDefine(String memo, String keyTemplate, KeyTypeEnum keyType, Class<?> valueType, Duration timeout) {  
30 - super(memo, buildKeyTemplate(keyTemplate), keyType, valueType, timeout);  
31 - }  
32 -  
33 - public TenantRedisKeyDefine(String memo, String keyTemplate, KeyTypeEnum keyType, Class<?> valueType, TimeoutTypeEnum timeoutType) {  
34 - super(memo, buildKeyTemplate(keyTemplate), keyType, valueType, timeoutType);  
35 - }  
36 -  
37 - private static String buildKeyTemplate(String keyTemplate) {  
38 - return keyTemplate + KEY_TEMPLATE_SUFFIX;  
39 - }  
40 -  
41 - @Override  
42 - public String formatKey(Object... args) {  
43 - args = ArrayUtil.append(args, TenantContextHolder.getRequiredTenantId());  
44 - return super.formatKey(args);  
45 - }  
46 -  
47 -}  
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/test/java/cn/iocoder/yudao/framework/tenant/core/redis/TenantRedisKeyDefineTest.java deleted
1 -package cn.iocoder.yudao.framework.tenant.core.redis;  
2 -  
3 -import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;  
4 -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;  
5 -import org.junit.jupiter.api.Test;  
6 -  
7 -import static org.junit.jupiter.api.Assertions.assertEquals;  
8 -  
9 -class TenantRedisKeyDefineTest {  
10 -  
11 - @Test  
12 - public void testFormatKey() {  
13 - Long tenantId = 30L;  
14 - TenantContextHolder.setTenantId(tenantId);  
15 - // 准备参数  
16 - TenantRedisKeyDefine define = new TenantRedisKeyDefine("", "user:%d:%d", RedisKeyDefine.KeyTypeEnum.HASH,  
17 - Object.class, RedisKeyDefine.TimeoutTypeEnum.FIXED);  
18 - Long userId = 10L;  
19 - Integer userType = 1;  
20 -  
21 - // 调用  
22 - String key = define.formatKey(userId, userType);  
23 - // 断言  
24 - assertEquals("user:10:1:30", key);  
25 - }  
26 -  
27 -}  
yudao-framework/yudao-spring-boot-starter-biz-weixin/pom.xml
@@ -34,16 +34,12 @@ @@ -34,16 +34,12 @@
34 <!-- 三方云服务相关 --> 34 <!-- 三方云服务相关 -->
35 <dependency> 35 <dependency>
36 <groupId>com.github.binarywang</groupId> 36 <groupId>com.github.binarywang</groupId>
37 -<!-- <artifactId>weixin-java-mp</artifactId>-->  
38 <artifactId>wx-java-mp-spring-boot-starter</artifactId> 37 <artifactId>wx-java-mp-spring-boot-starter</artifactId>
39 - <version>4.5.0</version>  
40 </dependency> 38 </dependency>
41 <dependency> 39 <dependency>
42 <groupId>com.github.binarywang</groupId> 40 <groupId>com.github.binarywang</groupId>
43 <artifactId>wx-java-miniapp-spring-boot-starter</artifactId> 41 <artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
44 - <version>4.5.0</version>  
45 </dependency> 42 </dependency>
46 - <!-- TODO 芋艿:清理 -->  
47 </dependencies> 43 </dependencies>
48 44
49 </project> 45 </project>
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/config/YudaoCaptchaConfiguration.java
1 package cn.iocoder.yudao.framework.captcha.config; 1 package cn.iocoder.yudao.framework.captcha.config;
2 2
3 -import cn.hutool.core.util.ClassUtil;  
4 -import cn.iocoder.yudao.framework.captcha.core.enums.CaptchaRedisKeyConstants;  
5 import cn.iocoder.yudao.framework.captcha.core.service.RedisCaptchaServiceImpl; 3 import cn.iocoder.yudao.framework.captcha.core.service.RedisCaptchaServiceImpl;
6 import com.xingyuv.captcha.properties.AjCaptchaProperties; 4 import com.xingyuv.captcha.properties.AjCaptchaProperties;
7 import com.xingyuv.captcha.service.CaptchaCacheService; 5 import com.xingyuv.captcha.service.CaptchaCacheService;
@@ -15,12 +13,6 @@ import javax.annotation.Resource; @@ -15,12 +13,6 @@ import javax.annotation.Resource;
15 @AutoConfiguration 13 @AutoConfiguration
16 public class YudaoCaptchaConfiguration { 14 public class YudaoCaptchaConfiguration {
17 15
18 - static {  
19 - // 手动加载 Lock4jRedisKeyConstants 类,因为它不会被使用到  
20 - // 如果不加载,会导致 Redis 监控,看到它的 Redis Key 枚举  
21 - ClassUtil.loadClass(CaptchaRedisKeyConstants.class.getName());  
22 - }  
23 -  
24 @Resource 16 @Resource
25 private StringRedisTemplate stringRedisTemplate; 17 private StringRedisTemplate stringRedisTemplate;
26 18
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/core/enums/CaptchaRedisKeyConstants.java
1 package cn.iocoder.yudao.framework.captcha.core.enums; 1 package cn.iocoder.yudao.framework.captcha.core.enums;
2 2
3 -import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;  
4 -import com.xingyuv.captcha.model.vo.PointVO;  
5 -  
6 -import java.time.Duration;  
7 -  
8 -import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING;  
9 -  
10 /** 3 /**
11 * 验证码 Redis Key 枚举类 4 * 验证码 Redis Key 枚举类
12 * 5 *
@@ -14,12 +7,22 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.S @@ -14,12 +7,22 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.S
14 */ 7 */
15 public interface CaptchaRedisKeyConstants { 8 public interface CaptchaRedisKeyConstants {
16 9
17 - RedisKeyDefine AJ_CAPTCHA_REQ_LIMIT = new RedisKeyDefine("验证码的请求限流",  
18 - "AJ.CAPTCHA.REQ.LIMIT-%s-%s",  
19 - STRING, Integer.class, Duration.ofSeconds(60)); // 例如说:验证失败 5 次,get 接口锁定 10 + /**
  11 + * 验证码的请求限流
  12 + *
  13 + * KEY 格式:AJ.CAPTCHA.REQ.LIMIT-%s-%s
  14 + * VALUE 数据类型:String // 例如说:验证失败 5 次,get 接口锁定
  15 + * 过期时间:60 秒
  16 + */
  17 + String AJ_CAPTCHA_REQ_LIMIT = "AJ.CAPTCHA.REQ.LIMIT-%s-%s";
20 18
21 - RedisKeyDefine AJ_CAPTCHA_RUNNING = new RedisKeyDefine("验证码的坐标",  
22 - "RUNNING:CAPTCHA:%s", // AbstractCaptchaService.REDIS_CAPTCHA_KEY  
23 - STRING, PointVO.class, Duration.ofSeconds(120)); // {"secretKey":"PP1w2Frr2KEejD2m","x":162,"y":5} 19 + /**
  20 + * 验证码的坐标
  21 + *
  22 + * KEY 格式:RUNNING:CAPTCHA:%s // AbstractCaptchaService.REDIS_CAPTCHA_KEY
  23 + * VALUE 数据类型:String // PointVO.class {"secretKey":"PP1w2Frr2KEejD2m","x":162,"y":5}
  24 + * 过期时间:120 秒
  25 + */
  26 + String AJ_CAPTCHA_RUNNING = "RUNNING:CAPTCHA:%s";
24 27
25 } 28 }
yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
@@ -64,9 +64,8 @@ @@ -64,9 +64,8 @@
64 64
65 <dependency> 65 <dependency>
66 <groupId>com.github.yulichang</groupId> 66 <groupId>com.github.yulichang</groupId>
67 - <artifactId>mybatis-plus-join-boot-starter</artifactId> 67 + <artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 -->
68 </dependency> 68 </dependency>
69 -  
70 </dependencies> 69 </dependencies>
71 70
72 </project> 71 </project>
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; @@ -6,10 +6,10 @@ import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
6 import com.baomidou.mybatisplus.core.conditions.Wrapper; 6 import com.baomidou.mybatisplus.core.conditions.Wrapper;
7 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 7 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
8 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 8 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  9 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
9 import com.baomidou.mybatisplus.core.metadata.IPage; 10 import com.baomidou.mybatisplus.core.metadata.IPage;
10 import com.baomidou.mybatisplus.core.toolkit.support.SFunction; 11 import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
11 import com.baomidou.mybatisplus.extension.toolkit.Db; 12 import com.baomidou.mybatisplus.extension.toolkit.Db;
12 -import com.github.yulichang.base.MPJBaseMapper;  
13 import org.apache.ibatis.annotations.Param; 13 import org.apache.ibatis.annotations.Param;
14 14
15 import java.util.Collection; 15 import java.util.Collection;
@@ -17,10 +17,8 @@ import java.util.List; @@ -17,10 +17,8 @@ import java.util.List;
17 17
18 /** 18 /**
19 * 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力 19 * 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力
20 - * <p>  
21 - * 为什么继承 MPJBaseMapper 接口?支持 MyBatis Plus 多表 Join 的能力。  
22 */ 20 */
23 -public interface BaseMapperX<T> extends MPJBaseMapper<T> { 21 +public interface BaseMapperX<T> extends BaseMapper<T> {
24 22
25 default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) { 23 default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) {
26 // MyBatis Plus 查询 24 // MyBatis Plus 查询
@@ -46,18 +44,6 @@ public interface BaseMapperX&lt;T&gt; extends MPJBaseMapper&lt;T&gt; { @@ -46,18 +44,6 @@ public interface BaseMapperX&lt;T&gt; extends MPJBaseMapper&lt;T&gt; {
46 return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)); 44 return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
47 } 45 }
48 46
49 - default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2,  
50 - SFunction<T, ?> field3, Object value3) {  
51 - return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)  
52 - .eq(field3, value3));  
53 - }  
54 -  
55 - default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2,  
56 - SFunction<T, ?> field3, Object value3, SFunction<T, ?> field4, Object value4) {  
57 - return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)  
58 - .eq(field3, value3).eq(field4, value4));  
59 - }  
60 -  
61 default Long selectCount() { 47 default Long selectCount() {
62 return selectCount(new QueryWrapper<T>()); 48 return selectCount(new QueryWrapper<T>());
63 } 49 }
@@ -117,11 +103,6 @@ public interface BaseMapperX&lt;T&gt; extends MPJBaseMapper&lt;T&gt; { @@ -117,11 +103,6 @@ public interface BaseMapperX&lt;T&gt; extends MPJBaseMapper&lt;T&gt; {
117 update(update, new QueryWrapper<>()); 103 update(update, new QueryWrapper<>());
118 } 104 }
119 105
120 - /**  
121 - * 根据ID 批量更新,适合大量数据更新  
122 - *  
123 - * @param entities 实体们  
124 - */  
125 default void updateBatch(Collection<T> entities) { 106 default void updateBatch(Collection<T> entities) {
126 Db.updateBatchById(entities); 107 Db.updateBatchById(entities);
127 } 108 }
@@ -130,13 +111,8 @@ public interface BaseMapperX&lt;T&gt; extends MPJBaseMapper&lt;T&gt; { @@ -130,13 +111,8 @@ public interface BaseMapperX&lt;T&gt; extends MPJBaseMapper&lt;T&gt; {
130 Db.updateBatchById(entities, size); 111 Db.updateBatchById(entities, size);
131 } 112 }
132 113
133 - /**  
134 - * 批量修改插入, 会根据实体的主键是否为空,更新还是修改。默认为 1000  
135 - *  
136 - * @param entities 实体们  
137 - */  
138 - default void saveOrUpdateBatch(Collection<T> entities){  
139 - Db.saveOrUpdateBatch(entities); 114 + default void saveOrUpdateBatch(Collection<T> collection) {
  115 + Db.saveOrUpdateBatch(collection);
140 } 116 }
141 117
142 } 118 }
yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/redis/IdempotentRedisDAO.java
1 package cn.iocoder.yudao.framework.idempotent.core.redis; 1 package cn.iocoder.yudao.framework.idempotent.core.redis;
2 2
3 -import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;  
4 import lombok.AllArgsConstructor; 3 import lombok.AllArgsConstructor;
5 import org.springframework.data.redis.core.StringRedisTemplate; 4 import org.springframework.data.redis.core.StringRedisTemplate;
6 5
7 import java.util.concurrent.TimeUnit; 6 import java.util.concurrent.TimeUnit;
8 7
9 -import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING;  
10 -  
11 /** 8 /**
12 * 幂等 Redis DAO 9 * 幂等 Redis DAO
13 * 10 *
@@ -16,9 +13,14 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.S @@ -16,9 +13,14 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.S
16 @AllArgsConstructor 13 @AllArgsConstructor
17 public class IdempotentRedisDAO { 14 public class IdempotentRedisDAO {
18 15
19 - private static final RedisKeyDefine IDEMPOTENT = new RedisKeyDefine("幂等操作",  
20 - "idempotent:%s", // 参数为 uuid  
21 - STRING, String.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); 16 + /**
  17 + * 幂等操作
  18 + *
  19 + * KEY 格式:idempotent:%s // 参数为 uuid
  20 + * VALUE 格式:String
  21 + * 过期时间:不固定
  22 + */
  23 + private static final String IDEMPOTENT = "idempotent:%s";
22 24
23 private final StringRedisTemplate redisTemplate; 25 private final StringRedisTemplate redisTemplate;
24 26
@@ -28,7 +30,7 @@ public class IdempotentRedisDAO { @@ -28,7 +30,7 @@ public class IdempotentRedisDAO {
28 } 30 }
29 31
30 private static String formatKey(String key) { 32 private static String formatKey(String key) {
31 - return String.format(IDEMPOTENT.getKeyTemplate(), key); 33 + return String.format(IDEMPOTENT, key);
32 } 34 }
33 35
34 } 36 }
yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java
1 package cn.iocoder.yudao.framework.lock4j.config; 1 package cn.iocoder.yudao.framework.lock4j.config;
2 2
3 -import cn.hutool.core.util.ClassUtil;  
4 -import com.baomidou.lock.spring.boot.autoconfigure.LockAutoConfiguration;  
5 import cn.iocoder.yudao.framework.lock4j.core.DefaultLockFailureStrategy; 3 import cn.iocoder.yudao.framework.lock4j.core.DefaultLockFailureStrategy;
6 -import cn.iocoder.yudao.framework.lock4j.core.Lock4jRedisKeyConstants; 4 +import com.baomidou.lock.spring.boot.autoconfigure.LockAutoConfiguration;
7 import org.springframework.boot.autoconfigure.AutoConfiguration; 5 import org.springframework.boot.autoconfigure.AutoConfiguration;
8 import org.springframework.context.annotation.Bean; 6 import org.springframework.context.annotation.Bean;
9 7
10 @AutoConfiguration(before = LockAutoConfiguration.class) 8 @AutoConfiguration(before = LockAutoConfiguration.class)
11 public class YudaoLock4jConfiguration { 9 public class YudaoLock4jConfiguration {
12 10
13 - static {  
14 - // 手动加载 Lock4jRedisKeyConstants 类,因为它不会被使用到  
15 - // 如果不加载,会导致 Redis 监控,看到它的 Redis Key 枚举  
16 - ClassUtil.loadClass(Lock4jRedisKeyConstants.class.getName());  
17 - }  
18 -  
19 @Bean 11 @Bean
20 public DefaultLockFailureStrategy lockFailureStrategy() { 12 public DefaultLockFailureStrategy lockFailureStrategy() {
21 return new DefaultLockFailureStrategy(); 13 return new DefaultLockFailureStrategy();
yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/Lock4jRedisKeyConstants.java
1 package cn.iocoder.yudao.framework.lock4j.core; 1 package cn.iocoder.yudao.framework.lock4j.core;
2 2
3 -import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;  
4 -import org.redisson.api.RLock;  
5 -  
6 -import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.HASH;  
7 -  
8 /** 3 /**
9 * Lock4j Redis Key 枚举类 4 * Lock4j Redis Key 枚举类
10 * 5 *
@@ -12,8 +7,13 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.H @@ -12,8 +7,13 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.H
12 */ 7 */
13 public interface Lock4jRedisKeyConstants { 8 public interface Lock4jRedisKeyConstants {
14 9
15 - RedisKeyDefine LOCK4J = new RedisKeyDefine("分布式锁",  
16 - "lock4j:%s", // 参数来自 DefaultLockKeyBuilder 类  
17 - HASH, RLock.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); // Redisson 的 Lock 锁,使用 Hash 数据结构 10 + /**
  11 + * 分布式锁
  12 + *
  13 + * KEY 格式:lock4j:%s // 参数来自 DefaultLockKeyBuilder 类
  14 + * VALUE 数据格式:HASH // RLock.class:Redisson 的 Lock 锁,使用 Hash 数据结构
  15 + * 过期时间:不固定
  16 + */
  17 + String LOCK4J = "lock4j:%s";
18 18
19 } 19 }
yudao-framework/yudao-spring-boot-starter-redis/pom.xml
@@ -37,6 +37,11 @@ @@ -37,6 +37,11 @@
37 <artifactId>netty-all</artifactId> 37 <artifactId>netty-all</artifactId>
38 </dependency> 38 </dependency>
39 39
  40 +
  41 + <dependency>
  42 + <groupId>com.fasterxml.jackson.datatype</groupId>
  43 + <artifactId>jackson-datatype-jsr310</artifactId>
  44 + </dependency>
40 </dependencies> 45 </dependencies>
41 46
42 </project> 47 </project>
yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java
1 package cn.iocoder.yudao.framework.redis.config; 1 package cn.iocoder.yudao.framework.redis.config;
2 2
  3 +import cn.hutool.core.util.StrUtil;
  4 +import cn.iocoder.yudao.framework.redis.core.TimeoutRedisCacheManager;
3 import org.springframework.boot.autoconfigure.AutoConfiguration; 5 import org.springframework.boot.autoconfigure.AutoConfiguration;
4 import org.springframework.boot.autoconfigure.cache.CacheProperties; 6 import org.springframework.boot.autoconfigure.cache.CacheProperties;
5 import org.springframework.boot.context.properties.EnableConfigurationProperties; 7 import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -7,8 +9,15 @@ import org.springframework.cache.annotation.EnableCaching; @@ -7,8 +9,15 @@ import org.springframework.cache.annotation.EnableCaching;
7 import org.springframework.context.annotation.Bean; 9 import org.springframework.context.annotation.Bean;
8 import org.springframework.context.annotation.Primary; 10 import org.springframework.context.annotation.Primary;
9 import org.springframework.data.redis.cache.RedisCacheConfiguration; 11 import org.springframework.data.redis.cache.RedisCacheConfiguration;
  12 +import org.springframework.data.redis.cache.RedisCacheManager;
  13 +import org.springframework.data.redis.cache.RedisCacheWriter;
  14 +import org.springframework.data.redis.connection.RedisConnectionFactory;
  15 +import org.springframework.data.redis.core.RedisTemplate;
10 import org.springframework.data.redis.serializer.RedisSerializationContext; 16 import org.springframework.data.redis.serializer.RedisSerializationContext;
11 -import org.springframework.data.redis.serializer.RedisSerializer; 17 +
  18 +import java.util.Objects;
  19 +
  20 +import static cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration.buildRedisSerializer;
12 21
13 /** 22 /**
14 * Cache 配置类,基于 Redis 实现 23 * Cache 配置类,基于 Redis 实现
@@ -20,15 +29,19 @@ public class YudaoCacheAutoConfiguration { @@ -20,15 +29,19 @@ public class YudaoCacheAutoConfiguration {
20 29
21 /** 30 /**
22 * RedisCacheConfiguration Bean 31 * RedisCacheConfiguration Bean
23 - * 32 + * <p>
24 * 参考 org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration 的 createConfiguration 方法 33 * 参考 org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration 的 createConfiguration 方法
25 */ 34 */
26 @Bean 35 @Bean
27 @Primary 36 @Primary
28 public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) { 37 public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
29 - // 设置使用 JSON 序列化方式  
30 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); 38 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
31 - config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json())); 39 + // 设置使用 : 单冒号,而不是双 :: 冒号,避免 Redis Desktop Manager 多余空格
  40 + // 详细可见 https://blog.csdn.net/chuixue24/article/details/103928965 博客
  41 + config = config.computePrefixWith(cacheName -> cacheName + StrUtil.COLON);
  42 + // 设置使用 JSON 序列化方式
  43 + config = config.serializeValuesWith(
  44 + RedisSerializationContext.SerializationPair.fromSerializer(buildRedisSerializer()));
32 45
33 // 设置 CacheProperties.Redis 的属性 46 // 设置 CacheProperties.Redis 的属性
34 CacheProperties.Redis redisProperties = cacheProperties.getRedis(); 47 CacheProperties.Redis redisProperties = cacheProperties.getRedis();
@@ -47,4 +60,14 @@ public class YudaoCacheAutoConfiguration { @@ -47,4 +60,14 @@ public class YudaoCacheAutoConfiguration {
47 return config; 60 return config;
48 } 61 }
49 62
  63 + @Bean
  64 + public RedisCacheManager redisCacheManager(RedisTemplate<String, Object> redisTemplate,
  65 + RedisCacheConfiguration redisCacheConfiguration) {
  66 + // 创建 RedisCacheWriter 对象
  67 + RedisConnectionFactory connectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory());
  68 + RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
  69 + // 创建 TenantRedisCacheManager 对象
  70 + return new TimeoutRedisCacheManager(cacheWriter, redisCacheConfiguration);
  71 + }
  72 +
50 } 73 }
yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java
1 package cn.iocoder.yudao.framework.redis.config; 1 package cn.iocoder.yudao.framework.redis.config;
2 2
  3 +import cn.hutool.core.util.ReflectUtil;
  4 +import com.fasterxml.jackson.databind.ObjectMapper;
  5 +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
3 import org.springframework.boot.autoconfigure.AutoConfiguration; 6 import org.springframework.boot.autoconfigure.AutoConfiguration;
4 import org.springframework.context.annotation.Bean; 7 import org.springframework.context.annotation.Bean;
5 import org.springframework.data.redis.connection.RedisConnectionFactory; 8 import org.springframework.data.redis.connection.RedisConnectionFactory;
@@ -25,9 +28,17 @@ public class YudaoRedisAutoConfiguration { @@ -25,9 +28,17 @@ public class YudaoRedisAutoConfiguration {
25 template.setKeySerializer(RedisSerializer.string()); 28 template.setKeySerializer(RedisSerializer.string());
26 template.setHashKeySerializer(RedisSerializer.string()); 29 template.setHashKeySerializer(RedisSerializer.string());
27 // 使用 JSON 序列化方式(库是 Jackson ),序列化 VALUE 。 30 // 使用 JSON 序列化方式(库是 Jackson ),序列化 VALUE 。
28 - template.setValueSerializer(RedisSerializer.json());  
29 - template.setHashValueSerializer(RedisSerializer.json()); 31 + template.setValueSerializer(buildRedisSerializer());
  32 + template.setHashValueSerializer(buildRedisSerializer());
30 return template; 33 return template;
31 } 34 }
32 35
  36 + public static RedisSerializer<?> buildRedisSerializer() {
  37 + RedisSerializer<Object> json = RedisSerializer.json();
  38 + // 解决 LocalDateTime 的序列化
  39 + ObjectMapper objectMapper = (ObjectMapper) ReflectUtil.getFieldValue(json, "mapper");
  40 + objectMapper.registerModules(new JavaTimeModule());
  41 + return json;
  42 + }
  43 +
33 } 44 }
yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/RedisKeyDefine.java deleted
1 -package cn.iocoder.yudao.framework.redis.core;  
2 -  
3 -import com.fasterxml.jackson.annotation.JsonValue;  
4 -import lombok.AllArgsConstructor;  
5 -import lombok.Data;  
6 -import lombok.Getter;  
7 -  
8 -import java.time.Duration;  
9 -  
10 -/**  
11 - * Redis Key 定义类  
12 - *  
13 - * @author 芋道源码  
14 - */  
15 -@Data  
16 -public class RedisKeyDefine {  
17 -  
18 - @Getter  
19 - @AllArgsConstructor  
20 - public enum KeyTypeEnum {  
21 -  
22 - STRING("String"),  
23 - LIST("List"),  
24 - HASH("Hash"),  
25 - SET("Set"),  
26 - ZSET("Sorted Set"),  
27 - STREAM("Stream"),  
28 - PUBSUB("Pub/Sub");  
29 -  
30 - /**  
31 - * 类型  
32 - */  
33 - @JsonValue  
34 - private final String type;  
35 -  
36 - }  
37 -  
38 - @Getter  
39 - @AllArgsConstructor  
40 - public enum TimeoutTypeEnum {  
41 -  
42 - FOREVER(1), // 永不超时  
43 - DYNAMIC(2), // 动态超时  
44 - FIXED(3); // 固定超时  
45 -  
46 - /**  
47 - * 类型  
48 - */  
49 - @JsonValue  
50 - private final Integer type;  
51 -  
52 - }  
53 -  
54 - /**  
55 - * Key 模板  
56 - */  
57 - private final String keyTemplate;  
58 - /**  
59 - * Key 类型的枚举  
60 - */  
61 - private final KeyTypeEnum keyType;  
62 - /**  
63 - * Value 类型  
64 - *  
65 - * 如果是使用分布式锁,设置为 {@link java.util.concurrent.locks.Lock} 类型  
66 - */  
67 - private final Class<?> valueType;  
68 - /**  
69 - * 超时类型  
70 - */  
71 - private final TimeoutTypeEnum timeoutType;  
72 - /**  
73 - * 过期时间  
74 - */  
75 - private final Duration timeout;  
76 - /**  
77 - * 备注  
78 - */  
79 - private final String memo;  
80 -  
81 - private RedisKeyDefine(String memo, String keyTemplate, KeyTypeEnum keyType, Class<?> valueType,  
82 - TimeoutTypeEnum timeoutType, Duration timeout) {  
83 - this.memo = memo;  
84 - this.keyTemplate = keyTemplate;  
85 - this.keyType = keyType;  
86 - this.valueType = valueType;  
87 - this.timeout = timeout;  
88 - this.timeoutType = timeoutType;  
89 - // 添加注册表  
90 - RedisKeyRegistry.add(this);  
91 - }  
92 -  
93 - public RedisKeyDefine(String memo, String keyTemplate, KeyTypeEnum keyType, Class<?> valueType, Duration timeout) {  
94 - this(memo, keyTemplate, keyType, valueType, TimeoutTypeEnum.FIXED, timeout);  
95 - }  
96 -  
97 - public RedisKeyDefine(String memo, String keyTemplate, KeyTypeEnum keyType, Class<?> valueType, TimeoutTypeEnum timeoutType) {  
98 - this(memo, keyTemplate, keyType, valueType, timeoutType, Duration.ZERO);  
99 - }  
100 -  
101 - /**  
102 - * 格式化 Key  
103 - *  
104 - * 注意,内部采用 {@link String#format(String, Object...)} 实现  
105 - *  
106 - * @param args 格式化的参数  
107 - * @return Key  
108 - */  
109 - public String formatKey(Object... args) {  
110 - return String.format(keyTemplate, args);  
111 - }  
112 -  
113 -}  
yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/RedisKeyRegistry.java deleted
1 -package cn.iocoder.yudao.framework.redis.core;  
2 -  
3 -import java.util.ArrayList;  
4 -import java.util.List;  
5 -  
6 -/**  
7 - * {@link RedisKeyDefine} 注册表  
8 - */  
9 -public class RedisKeyRegistry {  
10 -  
11 - /**  
12 - * Redis RedisKeyDefine 数组  
13 - */  
14 - private static final List<RedisKeyDefine> DEFINES = new ArrayList<>();  
15 -  
16 - public static void add(RedisKeyDefine define) {  
17 - DEFINES.add(define);  
18 - }  
19 -  
20 - public static List<RedisKeyDefine> list() {  
21 - return DEFINES;  
22 - }  
23 -  
24 - public static int size() {  
25 - return DEFINES.size();  
26 - }  
27 -  
28 -}  
yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/TimeoutRedisCacheManager.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.redis.core;
  2 +
  3 +import cn.hutool.core.util.StrUtil;
  4 +import org.springframework.boot.convert.DurationStyle;
  5 +import org.springframework.cache.annotation.Cacheable;
  6 +import org.springframework.data.redis.cache.RedisCache;
  7 +import org.springframework.data.redis.cache.RedisCacheConfiguration;
  8 +import org.springframework.data.redis.cache.RedisCacheManager;
  9 +import org.springframework.data.redis.cache.RedisCacheWriter;
  10 +
  11 +import java.time.Duration;
  12 +import java.time.temporal.ChronoUnit;
  13 +
  14 +/**
  15 + * 支持自定义过期时间的 {@link RedisCacheManager} 实现类
  16 + *
  17 + * 在 {@link Cacheable#cacheNames()} 格式为 "key#ttl" 时,# 后面的 ttl 为过期时间,单位为秒
  18 + *
  19 + * @author 芋道源码
  20 + */
  21 +public class TimeoutRedisCacheManager extends RedisCacheManager {
  22 +
  23 + private static final String SPLIT = "#";
  24 +
  25 + public TimeoutRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
  26 + super(cacheWriter, defaultCacheConfiguration);
  27 + }
  28 +
  29 + @Override
  30 + protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
  31 + if (StrUtil.isEmpty(name)) {
  32 + return super.createRedisCache(name, cacheConfig);
  33 + }
  34 + // 如果使用 # 分隔,大小不为 2,则说明不使用自定义过期时间
  35 + String[] names = StrUtil.splitToArray(name, SPLIT);
  36 + if (names.length != 2) {
  37 + return super.createRedisCache(name, cacheConfig);
  38 + }
  39 +
  40 + // 核心:通过修改 cacheConfig 的过期时间,实现自定义过期时间
  41 + if (cacheConfig != null) {
  42 + // 移除 # 后面的 : 以及后面的内容,避免影响解析
  43 + names[1] = StrUtil.subBefore(names[1], StrUtil.COLON, false);
  44 + // 解析时间
  45 + Duration duration = DurationStyle.detectAndParse(names[1], ChronoUnit.SECONDS);
  46 + cacheConfig = cacheConfig.entryTtl(duration);
  47 + }
  48 + return super.createRedisCache(names[0], cacheConfig);
  49 + }
  50 +
  51 +}
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 { @@ -60,7 +60,7 @@ public class YudaoWebSecurityConfigurerAdapter {
60 /** 60 /**
61 * 自定义的权限映射 Bean 们 61 * 自定义的权限映射 Bean 们
62 * 62 *
63 - * @see #configure(HttpSecurity) 63 + * @see #filterChain(HttpSecurity)
64 */ 64 */
65 @Resource 65 @Resource
66 private List<AuthorizeRequestsCustomizer> authorizeRequestsCustomizers; 66 private List<AuthorizeRequestsCustomizer> authorizeRequestsCustomizers;
@@ -79,7 +79,7 @@ public class YudaoWebSecurityConfigurerAdapter { @@ -79,7 +79,7 @@ public class YudaoWebSecurityConfigurerAdapter {
79 79
80 /** 80 /**
81 * 配置 URL 的安全配置 81 * 配置 URL 的安全配置
82 - * <p> 82 + *
83 * anyRequest | 匹配所有请求路径 83 * anyRequest | 匹配所有请求路径
84 * access | SpringEl表达式结果为true时可以访问 84 * access | SpringEl表达式结果为true时可以访问
85 * anonymous | 匿名可以访问 85 * anonymous | 匿名可以访问
@@ -141,7 +141,6 @@ public class YudaoWebSecurityConfigurerAdapter { @@ -141,7 +141,6 @@ public class YudaoWebSecurityConfigurerAdapter {
141 141
142 // 添加 Token Filter 142 // 添加 Token Filter
143 httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); 143 httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
144 -  
145 return httpSecurity.build(); 144 return httpSecurity.build();
146 } 145 }
147 146
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 { @@ -40,6 +40,7 @@ public class BaseDbAndRedisUnitTest {
40 40
41 // Redis 配置类 41 // Redis 配置类
42 RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer 42 RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer
  43 +// RedisAutoConfiguration.class, // Spring Redis 自动配置类
43 YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类 44 YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
44 RedissonAutoConfiguration.class, // Redisson 自动高配置类 45 RedissonAutoConfiguration.class, // Redisson 自动高配置类
45 }) 46 })
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 { @@ -52,7 +52,8 @@ public class YudaoSwaggerAutoConfiguration {
52 // 接口信息 52 // 接口信息
53 .info(buildInfo(properties)) 53 .info(buildInfo(properties))
54 // 接口安全配置 54 // 接口安全配置
55 - .components(new Components().securitySchemes(securitySchemas)); 55 + .components(new Components().securitySchemes(securitySchemas))
  56 + .addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION));
56 securitySchemas.keySet().forEach(key -> openAPI.addSecurityItem(new SecurityRequirement().addList(key))); 57 securitySchemas.keySet().forEach(key -> openAPI.addSecurityItem(new SecurityRequirement().addList(key)));
57 return openAPI; 58 return openAPI;
58 } 59 }
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 { @@ -47,7 +47,7 @@ public class BpmTaskController {
47 @Parameter(name = "processInstanceId", description = "流程实例的编号", required = true) 47 @Parameter(name = "processInstanceId", description = "流程实例的编号", required = true)
48 @PreAuthorize("@ss.hasPermission('bpm:task:query')") 48 @PreAuthorize("@ss.hasPermission('bpm:task:query')")
49 public CommonResult<List<BpmTaskRespVO>> getTaskListByProcessInstanceId( 49 public CommonResult<List<BpmTaskRespVO>> getTaskListByProcessInstanceId(
50 - @RequestParam("processInstanceId") String processInstanceId) { 50 + @RequestParam("processInstanceId") String processInstanceId) {
51 return success(taskService.getTaskListByProcessInstanceId(processInstanceId)); 51 return success(taskService.getTaskListByProcessInstanceId(processInstanceId));
52 } 52 }
53 53
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 { @@ -73,11 +73,13 @@ public interface BpmTaskConvert {
73 73
74 BpmTaskDonePageItemRespVO convert2(HistoricTaskInstance bean); 74 BpmTaskDonePageItemRespVO convert2(HistoricTaskInstance bean);
75 75
76 - @Mappings({@Mapping(source = "processInstance.id", target = "id"),  
77 - @Mapping(source = "processInstance.name", target = "name"),  
78 - @Mapping(source = "processInstance.startUserId", target = "startUserId"),  
79 - @Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"),  
80 - @Mapping(source = "startUser.nickname", target = "startUserNickname")}) 76 + @Mappings({
  77 + @Mapping(source = "processInstance.id", target = "id"),
  78 + @Mapping(source = "processInstance.name", target = "name"),
  79 + @Mapping(source = "processInstance.startUserId", target = "startUserId"),
  80 + @Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"),
  81 + @Mapping(source = "startUser.nickname", target = "startUserNickname")
  82 + })
81 BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser); 83 BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser);
82 84
83 default List<BpmTaskRespVO> convertList3(List<HistoricTaskInstance> tasks, 85 default List<BpmTaskRespVO> convertList3(List<HistoricTaskInstance> tasks,
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; @@ -15,8 +15,8 @@ import cn.iocoder.yudao.module.bpm.convert.definition.BpmTaskAssignRuleConvert;
15 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; 15 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
16 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; 16 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
17 import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; 17 import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper;
18 -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;  
19 import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants; 18 import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants;
  19 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
20 import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; 20 import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript;
21 import cn.iocoder.yudao.module.system.api.dept.DeptApi; 21 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
22 import cn.iocoder.yudao.module.system.api.dept.PostApi; 22 import cn.iocoder.yudao.module.system.api.dept.PostApi;
@@ -89,7 +89,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @@ -89,7 +89,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
89 89
90 @Override 90 @Override
91 public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId, 91 public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId,
92 - String taskDefinitionKey) { 92 + String taskDefinitionKey) {
93 return taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, taskDefinitionKey); 93 return taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, taskDefinitionKey);
94 } 94 }
95 95
@@ -128,14 +128,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @@ -128,14 +128,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
128 validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions()); 128 validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions());
129 // 校验是否已经配置 129 // 校验是否已经配置
130 BpmTaskAssignRuleDO existRule = 130 BpmTaskAssignRuleDO existRule =
131 - taskRuleMapper.selectListByModelIdAndTaskDefinitionKey(reqVO.getModelId(), reqVO.getTaskDefinitionKey()); 131 + taskRuleMapper.selectListByModelIdAndTaskDefinitionKey(reqVO.getModelId(), reqVO.getTaskDefinitionKey());
132 if (existRule != null) { 132 if (existRule != null) {
133 throw exception(TASK_ASSIGN_RULE_EXISTS, reqVO.getModelId(), reqVO.getTaskDefinitionKey()); 133 throw exception(TASK_ASSIGN_RULE_EXISTS, reqVO.getModelId(), reqVO.getTaskDefinitionKey());
134 } 134 }
135 135
136 // 存储 136 // 存储
137 BpmTaskAssignRuleDO rule = BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO) 137 BpmTaskAssignRuleDO rule = BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO)
138 - .setProcessDefinitionId(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL); // 只有流程模型,才允许新建 138 + .setProcessDefinitionId(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL); // 只有流程模型,才允许新建
139 taskRuleMapper.insert(rule); 139 taskRuleMapper.insert(rule);
140 return rule.getId(); 140 return rule.getId();
141 } 141 }
@@ -169,14 +169,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @@ -169,14 +169,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
169 169
170 // 遍历,匹配对应的规则 170 // 遍历,匹配对应的规则
171 Map<String, BpmTaskAssignRuleRespVO> processInstanceRuleMap = 171 Map<String, BpmTaskAssignRuleRespVO> processInstanceRuleMap =
172 - CollectionUtils.convertMap(processInstanceRules, BpmTaskAssignRuleRespVO::getTaskDefinitionKey); 172 + CollectionUtils.convertMap(processInstanceRules, BpmTaskAssignRuleRespVO::getTaskDefinitionKey);
173 for (BpmTaskAssignRuleRespVO modelRule : modelRules) { 173 for (BpmTaskAssignRuleRespVO modelRule : modelRules) {
174 BpmTaskAssignRuleRespVO processInstanceRule = processInstanceRuleMap.get(modelRule.getTaskDefinitionKey()); 174 BpmTaskAssignRuleRespVO processInstanceRule = processInstanceRuleMap.get(modelRule.getTaskDefinitionKey());
175 if (processInstanceRule == null) { 175 if (processInstanceRule == null) {
176 return false; 176 return false;
177 } 177 }
178 if (!ObjectUtil.equals(modelRule.getType(), processInstanceRule.getType()) || !ObjectUtil.equal( 178 if (!ObjectUtil.equals(modelRule.getType(), processInstanceRule.getType()) || !ObjectUtil.equal(
179 - modelRule.getOptions(), processInstanceRule.getOptions())) { 179 + modelRule.getOptions(), processInstanceRule.getOptions())) {
180 return false; 180 return false;
181 } 181 }
182 } 182 }
@@ -192,7 +192,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @@ -192,7 +192,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
192 // 开始复制 192 // 开始复制
193 List<BpmTaskAssignRuleDO> newRules = BpmTaskAssignRuleConvert.INSTANCE.convertList2(rules); 193 List<BpmTaskAssignRuleDO> newRules = BpmTaskAssignRuleConvert.INSTANCE.convertList2(rules);
194 newRules.forEach(rule -> rule.setProcessDefinitionId(toProcessDefinitionId).setId(null).setCreateTime(null) 194 newRules.forEach(rule -> rule.setProcessDefinitionId(toProcessDefinitionId).setId(null).setCreateTime(null)
195 - .setUpdateTime(null)); 195 + .setUpdateTime(null));
196 taskRuleMapper.insertBatch(newRules); 196 taskRuleMapper.insertBatch(newRules);
197 } 197 }
198 198
@@ -215,7 +215,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @@ -215,7 +215,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
215 if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.ROLE.getType())) { 215 if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.ROLE.getType())) {
216 roleApi.validRoleList(options); 216 roleApi.validRoleList(options);
217 } else if (ObjectUtils.equalsAny(type, BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), 217 } else if (ObjectUtils.equalsAny(type, BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(),
218 - BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) { 218 + BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) {
219 deptApi.validateDeptList(options); 219 deptApi.validateDeptList(options);
220 } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.POST.getType())) { 220 } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.POST.getType())) {
221 postApi.validPostList(options); 221 postApi.validPostList(options);
@@ -225,7 +225,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @@ -225,7 +225,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
225 userGroupService.validUserGroups(options); 225 userGroupService.validUserGroups(options);
226 } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.SCRIPT.getType())) { 226 } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.SCRIPT.getType())) {
227 dictDataApi.validateDictDataList(DictTypeConstants.TASK_ASSIGN_SCRIPT, 227 dictDataApi.validateDictDataList(DictTypeConstants.TASK_ASSIGN_SCRIPT,
228 - CollectionUtils.convertSet(options, String::valueOf)); 228 + CollectionUtils.convertSet(options, String::valueOf));
229 } else { 229 } else {
230 throw new IllegalArgumentException(format("未知的规则类型({})", type)); 230 throw new IllegalArgumentException(format("未知的规则类型({})", type));
231 } 231 }
@@ -298,7 +298,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @@ -298,7 +298,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
298 } 298 }
299 299
300 private Set<Long> calculateTaskCandidateUsersByPost(BpmTaskAssignRuleDO rule) { 300 private Set<Long> calculateTaskCandidateUsersByPost(BpmTaskAssignRuleDO rule) {
301 - List<AdminUserRespDTO> users = adminUserApi.getUsersByPostIds(rule.getOptions()); 301 + List<AdminUserRespDTO> users = adminUserApi.getUserListByPostIds(rule.getOptions());
302 return convertSet(users, AdminUserRespDTO::getId); 302 return convertSet(users, AdminUserRespDTO::getId);
303 } 303 }
304 304
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
1 -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.time.LocalDateTime; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" /> * * HistoricProcessInstance & ProcessInstance 的关系: * 1. <a href=" https://my.oschina.net/843294669/blog/71902" /> * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private BpmMessageService messageService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List<ProcessInstance> getProcessInstances(Set<String> ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult<BpmProcessInstanceExtDO> pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List<String> processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String)event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map<String, Object> variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables)); return instance.getId(); } }  
2 \ No newline at end of file 1 \ No newline at end of file
  2 +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.time.LocalDateTime; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" /> * * HistoricProcessInstance & ProcessInstance 的关系: * 1. <a href=" https://my.oschina.net/843294669/blog/71902" /> * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private BpmMessageService messageService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List<ProcessInstance> getProcessInstances(Set<String> ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult<BpmProcessInstanceExtDO> pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List<String> processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String)event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map<String, Object> variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables)); return instance.getId(); } }
3 \ No newline at end of file 3 \ No newline at end of file
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 { @@ -40,6 +40,8 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest {
40 // mock 方法(startUser) 40 // mock 方法(startUser)
41 AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L)); 41 AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L));
42 when(adminUserApi.getUser(eq(1L))).thenReturn(startUser); 42 when(adminUserApi.getUser(eq(1L))).thenReturn(startUser);
  43 + // mock 方法(getStartUserDept)没有部门
  44 + when(deptApi.getDept(eq(10L))).thenReturn(null);
43 45
44 // 调用 46 // 调用
45 Set<Long> result = script.calculateTaskCandidateUsers(execution); 47 Set<Long> result = script.calculateTaskCandidateUsers(execution);
@@ -56,7 +58,9 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest { @@ -56,7 +58,9 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest {
56 when(adminUserApi.getUser(eq(1L))).thenReturn(startUser); 58 when(adminUserApi.getUser(eq(1L))).thenReturn(startUser);
57 DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L) 59 DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L)
58 .setLeaderUserId(20L)); 60 .setLeaderUserId(20L));
  61 + // mock 方法(getDept)
59 when(deptApi.getDept(eq(10L))).thenReturn(startUserDept); 62 when(deptApi.getDept(eq(10L))).thenReturn(startUserDept);
  63 + when(deptApi.getDept(eq(100L))).thenReturn(null);
60 64
61 // 调用 65 // 调用
62 Set<Long> result = script.calculateTaskCandidateUsers(execution); 66 Set<Long> result = script.calculateTaskCandidateUsers(execution);
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 { @@ -120,7 +120,7 @@ public class BpmTaskAssignRuleServiceImplTest extends BaseDbUnitTest {
120 // mock 方法 120 // mock 方法
121 List<AdminUserRespDTO> users = CollectionUtils.convertList(asSet(11L, 22L), 121 List<AdminUserRespDTO> users = CollectionUtils.convertList(asSet(11L, 22L),
122 id -> new AdminUserRespDTO().setId(id)); 122 id -> new AdminUserRespDTO().setId(id));
123 - when(adminUserApi.getUsersByPostIds(eq(rule.getOptions()))).thenReturn(users); 123 + when(adminUserApi.getUserListByPostIds(eq(rule.getOptions()))).thenReturn(users);
124 mockGetUserMap(asSet(11L, 22L)); 124 mockGetUserMap(asSet(11L, 22L));
125 125
126 // 调用 126 // 调用
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 @@ -23,10 +23,10 @@ import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgn
23 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_NOT_EXISTS; 23 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_NOT_EXISTS;
24 24
25 /** 25 /**
26 -* {@link BpmUserGroupServiceImpl} 的单元测试类  
27 -*  
28 -* @author 芋道源码  
29 -*/ 26 + * {@link BpmUserGroupServiceImpl} 的单元测试类
  27 + *
  28 + * @author 芋道源码
  29 + */
30 @Import(BpmUserGroupServiceImpl.class) 30 @Import(BpmUserGroupServiceImpl.class)
31 public class BpmUserGroupServiceTest extends BaseDbUnitTest { 31 public class BpmUserGroupServiceTest extends BaseDbUnitTest {
32 32
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.http
@@ -2,8 +2,3 @@ @@ -2,8 +2,3 @@
2 GET {{baseUrl}}/infra/redis/get-monitor-info 2 GET {{baseUrl}}/infra/redis/get-monitor-info
3 Authorization: Bearer {{token}} 3 Authorization: Bearer {{token}}
4 tenant-id: {{adminTenentId}} 4 tenant-id: {{adminTenentId}}
5 -  
6 -### 请求 /infra/redis/get-key-list 接口 => 成功  
7 -GET {{baseUrl}}/infra/redis/get-key-list  
8 -Authorization: Bearer {{token}}  
9 -tenant-id: {{adminTenentId}}  
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.java
1 package cn.iocoder.yudao.module.infra.controller.admin.redis; 1 package cn.iocoder.yudao.module.infra.controller.admin.redis;
2 2
3 -import cn.hutool.core.collection.CollUtil;  
4 -import cn.hutool.core.util.StrUtil;  
5 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 -import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;  
7 -import cn.iocoder.yudao.framework.redis.core.RedisKeyRegistry;  
8 -import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyDefineRespVO;  
9 -import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyValueRespVO;  
10 import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO; 4 import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO;
11 import cn.iocoder.yudao.module.infra.convert.redis.RedisConvert; 5 import cn.iocoder.yudao.module.infra.convert.redis.RedisConvert;
12 -import io.swagger.v3.oas.annotations.tags.Tag;  
13 -import io.swagger.v3.oas.annotations.Parameter;  
14 import io.swagger.v3.oas.annotations.Operation; 6 import io.swagger.v3.oas.annotations.Operation;
  7 +import io.swagger.v3.oas.annotations.tags.Tag;
15 import org.springframework.data.redis.connection.RedisServerCommands; 8 import org.springframework.data.redis.connection.RedisServerCommands;
16 -import org.springframework.data.redis.core.Cursor;  
17 import org.springframework.data.redis.core.RedisCallback; 9 import org.springframework.data.redis.core.RedisCallback;
18 -import org.springframework.data.redis.core.ScanOptions;  
19 import org.springframework.data.redis.core.StringRedisTemplate; 10 import org.springframework.data.redis.core.StringRedisTemplate;
20 import org.springframework.security.access.prepost.PreAuthorize; 11 import org.springframework.security.access.prepost.PreAuthorize;
21 -import org.springframework.web.bind.annotation.*; 12 +import org.springframework.web.bind.annotation.GetMapping;
  13 +import org.springframework.web.bind.annotation.RequestMapping;
  14 +import org.springframework.web.bind.annotation.RestController;
22 15
23 import javax.annotation.Resource; 16 import javax.annotation.Resource;
24 -import java.util.*; 17 +import java.util.Properties;
25 18
26 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 19 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
27 20
@@ -47,66 +40,4 @@ public class RedisController { @@ -47,66 +40,4 @@ public class RedisController {
47 return success(RedisConvert.INSTANCE.build(info, dbSize, commandStats)); 40 return success(RedisConvert.INSTANCE.build(info, dbSize, commandStats));
48 } 41 }
49 42
50 - @GetMapping("/get-key-define-list")  
51 - @Operation(summary = "获得 Redis Key 模板列表")  
52 - @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")  
53 - public CommonResult<List<RedisKeyDefineRespVO>> getKeyDefineList() {  
54 - List<RedisKeyDefine> keyDefines = RedisKeyRegistry.list();  
55 - return success(RedisConvert.INSTANCE.convertList(keyDefines));  
56 - }  
57 -  
58 - @GetMapping("/get-key-list")  
59 - @Operation(summary = "获得 Redis keys 键名列表")  
60 - @Parameter(name = "keyTemplate", description = "Redis Key 定义", example = "true")  
61 - @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")  
62 - public CommonResult<Set<String>> getKeyDefineList(@RequestParam("keyTemplate") String keyTemplate) {  
63 - return success(getKeyDefineList0(keyTemplate));  
64 - }  
65 -  
66 - private Set<String> getKeyDefineList0(String keyTemplate) {  
67 - // key 格式化  
68 - String key = StrUtil.replace(keyTemplate, "%[s|c|b|d|x|o|f|a|e|g]", parameter -> "*");  
69 - // scan 扫描 key  
70 - Set<String> keys = new LinkedHashSet<>();  
71 - stringRedisTemplate.execute((RedisCallback<Set<String>>) connection -> {  
72 - try (Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(key).count(100).build())) {  
73 - cursor.forEachRemaining(value -> keys.add(StrUtil.utf8Str(value)));  
74 - } catch (Exception e) {  
75 - throw new RuntimeException(e);  
76 - }  
77 - return keys;  
78 - });  
79 - return keys;  
80 - }  
81 -  
82 - @GetMapping("/get-key-value")  
83 - @Operation(summary = "获得 Redis key 内容")  
84 - @Parameter(name = "key", description = "Redis Key", example = "oauth2_access_token:233")  
85 - @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")  
86 - public CommonResult<RedisKeyValueRespVO> getKeyValue(@RequestParam("key") String key) {  
87 - String value = stringRedisTemplate.opsForValue().get(key);  
88 - return success(new RedisKeyValueRespVO(key, value));  
89 - }  
90 -  
91 - @DeleteMapping("/delete-key")  
92 - @Operation(summary = "删除 Redis Key")  
93 - @Parameter(name = "key", description = "Redis Key", example = "oauth2_access_token:233")  
94 - @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")  
95 - public CommonResult<Boolean> deleteKey(@RequestParam("key") String key) {  
96 - stringRedisTemplate.delete(key);  
97 - return success(Boolean.TRUE);  
98 - }  
99 -  
100 - @DeleteMapping("/delete-keys")  
101 - @Operation(summary = "删除 Redis Key 根据模板")  
102 - @Parameter(name = "keyTemplate", description = "Redis Key 定义", example = "true")  
103 - @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")  
104 - public CommonResult<Boolean> deleteKeys(@RequestParam("keyTemplate") String keyTemplate) {  
105 - Set<String> keys = getKeyDefineList0(keyTemplate);  
106 - if (CollUtil.isNotEmpty(keys)) {  
107 - stringRedisTemplate.delete(keys);  
108 - }  
109 - return success(Boolean.TRUE);  
110 - }  
111 -  
112 } 43 }
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisKeyDefineRespVO.java deleted
1 -package cn.iocoder.yudao.module.infra.controller.admin.redis.vo;  
2 -  
3 -import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;  
4 -import io.swagger.v3.oas.annotations.media.Schema;  
5 -import lombok.AllArgsConstructor;  
6 -import lombok.Builder;  
7 -import lombok.Data;  
8 -  
9 -import java.time.Duration;  
10 -  
11 -@Schema(description = "管理后台 - Redis Key 信息 Response VO")  
12 -@Data  
13 -@Builder  
14 -@AllArgsConstructor  
15 -public class RedisKeyDefineRespVO {  
16 -  
17 - @Schema(description = "Key 模板", requiredMode = Schema.RequiredMode.REQUIRED, example = "login_user:%s")  
18 - private String keyTemplate;  
19 -  
20 - @Schema(description = "Key 类型的枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "String")  
21 - private RedisKeyDefine.KeyTypeEnum keyType;  
22 -  
23 - @Schema(description = "Value 类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "java.lang.String")  
24 - private Class<?> valueType;  
25 -  
26 - @Schema(description = "超时类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
27 - private RedisKeyDefine.TimeoutTypeEnum timeoutType;  
28 -  
29 - @Schema(description = "过期时间,单位:毫秒", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")  
30 - private Duration timeout;  
31 -  
32 - @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "啦啦啦啦~")  
33 - private String memo;  
34 -  
35 -}  
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisKeyValueRespVO.java deleted
1 -package cn.iocoder.yudao.module.infra.controller.admin.redis.vo;  
2 -  
3 -import io.swagger.v3.oas.annotations.media.Schema;  
4 -import lombok.AllArgsConstructor;  
5 -import lombok.Data;  
6 -  
7 -@Schema(description = "管理后台 - 单个 Redis Key Value Response VO")  
8 -@Data  
9 -@AllArgsConstructor  
10 -public class RedisKeyValueRespVO {  
11 -  
12 - @Schema(description = "c5f6990767804a928f4bb96ca249febf", requiredMode = Schema.RequiredMode.REQUIRED, example = "String")  
13 - private String key;  
14 -  
15 - @Schema(requiredMode = Schema.RequiredMode.REQUIRED, example = "String")  
16 - private String value;  
17 -  
18 -}  
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/redis/RedisConvert.java
1 package cn.iocoder.yudao.module.infra.convert.redis; 1 package cn.iocoder.yudao.module.infra.convert.redis;
2 2
3 import cn.hutool.core.util.StrUtil; 3 import cn.hutool.core.util.StrUtil;
4 -import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;  
5 -import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyDefineRespVO;  
6 import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO; 4 import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO;
7 import org.mapstruct.Mapper; 5 import org.mapstruct.Mapper;
8 import org.mapstruct.factory.Mappers; 6 import org.mapstruct.factory.Mappers;
9 7
10 import java.util.ArrayList; 8 import java.util.ArrayList;
11 -import java.util.List;  
12 import java.util.Properties; 9 import java.util.Properties;
13 10
14 @Mapper 11 @Mapper
@@ -29,6 +26,4 @@ public interface RedisConvert { @@ -29,6 +26,4 @@ public interface RedisConvert {
29 return respVO; 26 return respVO;
30 } 27 }
31 28
32 - List<RedisKeyDefineRespVO> convertList(List<RedisKeyDefine> list);  
33 -  
34 } 29 }
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; @@ -6,6 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; 6 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO;
7 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; 7 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
  9 +import org.apache.ibatis.annotations.Select;
  10 +
  11 +import java.time.LocalDateTime;
9 12
10 @Mapper 13 @Mapper
11 public interface FileConfigMapper extends BaseMapperX<FileConfigDO> { 14 public interface FileConfigMapper extends BaseMapperX<FileConfigDO> {
@@ -18,4 +21,7 @@ public interface FileConfigMapper extends BaseMapperX&lt;FileConfigDO&gt; { @@ -18,4 +21,7 @@ public interface FileConfigMapper extends BaseMapperX&lt;FileConfigDO&gt; {
18 .orderByDesc(FileConfigDO::getId)); 21 .orderByDesc(FileConfigDO::getId));
19 } 22 }
20 23
  24 + @Select("SELECT COUNT(*) FROM infra_file_config WHERE update_time > #{maxUpdateTime}")
  25 + Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
  26 +
21 } 27 }
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/file/FileConfigRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.infra.mq.consumer.file;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
4 -import cn.iocoder.yudao.module.infra.mq.message.file.FileConfigRefreshMessage;  
5 -import cn.iocoder.yudao.module.infra.service.file.FileConfigService;  
6 -import lombok.extern.slf4j.Slf4j;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 针对 {@link FileConfigRefreshMessage} 的消费者  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Component  
17 -@Slf4j  
18 -public class FileConfigRefreshConsumer extends AbstractChannelMessageListener<FileConfigRefreshMessage> {  
19 -  
20 - @Resource  
21 - private FileConfigService fileConfigService;  
22 -  
23 - @Override  
24 - public void onMessage(FileConfigRefreshMessage message) {  
25 - log.info("[onMessage][收到 FileConfig 刷新消息]");  
26 - fileConfigService.initLocalCache();  
27 - }  
28 -  
29 -}  
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/package-info.java
1 /** 1 /**
2 - * 占位符,避免缩进 2 + * 消息队列的消费者
3 */ 3 */
4 package cn.iocoder.yudao.module.infra.mq.consumer; 4 package cn.iocoder.yudao.module.infra.mq.consumer;
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/file/FileConfigRefreshMessage.java deleted
1 -package cn.iocoder.yudao.module.infra.mq.message.file;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;  
4 -import lombok.Data;  
5 -  
6 -/**  
7 - * 文件配置数据刷新 Message  
8 - */  
9 -@Data  
10 -public class FileConfigRefreshMessage extends AbstractChannelMessage {  
11 -  
12 - @Override  
13 - public String getChannel() {  
14 - return "infra.file-config.refresh";  
15 - }  
16 -  
17 -}  
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/message/package-info.java
1 /** 1 /**
2 - * 占位符,避免缩进 2 + * 消息队列的消息
3 */ 3 */
4 package cn.iocoder.yudao.module.infra.mq.message; 4 package cn.iocoder.yudao.module.infra.mq.message;
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/file/FileConfigProducer.java deleted
1 -package cn.iocoder.yudao.module.infra.mq.producer.file;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;  
4 -import cn.iocoder.yudao.module.infra.mq.message.file.FileConfigRefreshMessage;  
5 -import org.springframework.stereotype.Component;  
6 -  
7 -import javax.annotation.Resource;  
8 -  
9 -/**  
10 - * 文件配置相关消息的 Producer  
11 - */  
12 -@Component  
13 -public class FileConfigProducer {  
14 -  
15 - @Resource  
16 - private RedisMQTemplate redisMQTemplate;  
17 -  
18 - /**  
19 - * 发送 {@link FileConfigRefreshMessage} 消息  
20 - */  
21 - public void sendFileConfigRefreshMessage() {  
22 - FileConfigRefreshMessage message = new FileConfigRefreshMessage();  
23 - redisMQTemplate.send(message);  
24 - }  
25 -  
26 -}  
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/package-info.java
1 /** 1 /**
2 - * 占位符,避免缩进 2 + * 消息队列的生产者
3 */ 3 */
4 package cn.iocoder.yudao.module.infra.mq.producer; 4 package cn.iocoder.yudao.module.infra.mq.producer;
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigService.java
@@ -17,11 +17,6 @@ import javax.validation.Valid; @@ -17,11 +17,6 @@ import javax.validation.Valid;
17 public interface FileConfigService { 17 public interface FileConfigService {
18 18
19 /** 19 /**
20 - * 初始化文件客户端  
21 - */  
22 - void initLocalCache();  
23 -  
24 - /**  
25 * 创建文件配置 20 * 创建文件配置
26 * 21 *
27 * @param createReqVO 创建信息 22 * @param createReqVO 创建信息
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java
1 package cn.iocoder.yudao.module.infra.service.file; 1 package cn.iocoder.yudao.module.infra.service.file;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.hutool.core.io.resource.ResourceUtil; 4 import cn.hutool.core.io.resource.ResourceUtil;
4 import cn.hutool.core.util.IdUtil; 5 import cn.hutool.core.util.IdUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 8 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
7 import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; 9 import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
8 import cn.iocoder.yudao.framework.file.core.client.FileClient; 10 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 @@ -15,20 +17,20 @@ import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigU
15 import cn.iocoder.yudao.module.infra.convert.file.FileConfigConvert; 17 import cn.iocoder.yudao.module.infra.convert.file.FileConfigConvert;
16 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; 18 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO;
17 import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper; 19 import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper;
18 -import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer;  
19 import lombok.Getter; 20 import lombok.Getter;
20 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
  22 +import org.springframework.scheduling.annotation.Scheduled;
21 import org.springframework.stereotype.Service; 23 import org.springframework.stereotype.Service;
22 import org.springframework.transaction.annotation.Transactional; 24 import org.springframework.transaction.annotation.Transactional;
23 -import org.springframework.transaction.support.TransactionSynchronization;  
24 -import org.springframework.transaction.support.TransactionSynchronizationManager;  
25 import org.springframework.validation.annotation.Validated; 25 import org.springframework.validation.annotation.Validated;
26 26
27 import javax.annotation.PostConstruct; 27 import javax.annotation.PostConstruct;
28 import javax.annotation.Resource; 28 import javax.annotation.Resource;
29 import javax.validation.Validator; 29 import javax.validation.Validator;
  30 +import java.time.LocalDateTime;
30 import java.util.List; 31 import java.util.List;
31 import java.util.Map; 32 import java.util.Map;
  33 +import java.util.concurrent.TimeUnit;
32 34
33 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 35 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
34 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_DELETE_FAIL_MASTER; 36 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_DELETE_FAIL_MASTER;
@@ -46,6 +48,12 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -46,6 +48,12 @@ public class FileConfigServiceImpl implements FileConfigService {
46 48
47 @Resource 49 @Resource
48 private FileClientFactory fileClientFactory; 50 private FileClientFactory fileClientFactory;
  51 +
  52 + /**
  53 + * 文件配置的缓存
  54 + */
  55 + @Getter
  56 + private List<FileConfigDO> fileConfigCache;
49 /** 57 /**
50 * Master FileClient 对象,有且仅有一个,即 {@link FileConfigDO#getMaster()} 对应的 58 * Master FileClient 对象,有且仅有一个,即 {@link FileConfigDO#getMaster()} 对应的
51 */ 59 */
@@ -56,12 +64,8 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -56,12 +64,8 @@ public class FileConfigServiceImpl implements FileConfigService {
56 private FileConfigMapper fileConfigMapper; 64 private FileConfigMapper fileConfigMapper;
57 65
58 @Resource 66 @Resource
59 - private FileConfigProducer fileConfigProducer;  
60 -  
61 - @Resource  
62 private Validator validator; 67 private Validator validator;
63 68
64 - @Override  
65 @PostConstruct 69 @PostConstruct
66 public void initLocalCache() { 70 public void initLocalCache() {
67 // 第一步:查询数据 71 // 第一步:查询数据
@@ -76,6 +80,27 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -76,6 +80,27 @@ public class FileConfigServiceImpl implements FileConfigService {
76 masterFileClient = fileClientFactory.getFileClient(config.getId()); 80 masterFileClient = fileClientFactory.getFileClient(config.getId());
77 } 81 }
78 }); 82 });
  83 + this.fileConfigCache = configs;
  84 + }
  85 +
  86 + /**
  87 + * 通过定时任务轮询,刷新缓存
  88 + *
  89 + * 目的:多节点部署时,通过轮询”通知“所有节点,进行刷新
  90 + */
  91 + @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS)
  92 + public void refreshLocalCache() {
  93 + // 情况一:如果缓存里没有数据,则直接刷新缓存
  94 + if (CollUtil.isEmpty(fileConfigCache)) {
  95 + initLocalCache();
  96 + return;
  97 + }
  98 +
  99 + // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存
  100 + LocalDateTime maxTime = CollectionUtils.getMaxValue(fileConfigCache, FileConfigDO::getUpdateTime);
  101 + if (fileConfigMapper.selectCountByUpdateTimeGt(maxTime) > 0) {
  102 + initLocalCache();
  103 + }
79 } 104 }
80 105
81 @Override 106 @Override
@@ -85,9 +110,9 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -85,9 +110,9 @@ public class FileConfigServiceImpl implements FileConfigService {
85 .setConfig(parseClientConfig(createReqVO.getStorage(), createReqVO.getConfig())) 110 .setConfig(parseClientConfig(createReqVO.getStorage(), createReqVO.getConfig()))
86 .setMaster(false); // 默认非 master 111 .setMaster(false); // 默认非 master
87 fileConfigMapper.insert(fileConfig); 112 fileConfigMapper.insert(fileConfig);
88 - // 发送刷新配置的消息  
89 - fileConfigProducer.sendFileConfigRefreshMessage();  
90 - // 返回 113 +
  114 + // 刷新缓存
  115 + initLocalCache();
91 return fileConfig.getId(); 116 return fileConfig.getId();
92 } 117 }
93 118
@@ -99,8 +124,9 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -99,8 +124,9 @@ public class FileConfigServiceImpl implements FileConfigService {
99 FileConfigDO updateObj = FileConfigConvert.INSTANCE.convert(updateReqVO) 124 FileConfigDO updateObj = FileConfigConvert.INSTANCE.convert(updateReqVO)
100 .setConfig(parseClientConfig(config.getStorage(), updateReqVO.getConfig())); 125 .setConfig(parseClientConfig(config.getStorage(), updateReqVO.getConfig()));
101 fileConfigMapper.updateById(updateObj); 126 fileConfigMapper.updateById(updateObj);
102 - // 发送刷新配置的消息  
103 - fileConfigProducer.sendFileConfigRefreshMessage(); 127 +
  128 + // 刷新缓存
  129 + initLocalCache();
104 } 130 }
105 131
106 @Override 132 @Override
@@ -112,15 +138,9 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -112,15 +138,9 @@ public class FileConfigServiceImpl implements FileConfigService {
112 fileConfigMapper.updateBatch(new FileConfigDO().setMaster(false)); 138 fileConfigMapper.updateBatch(new FileConfigDO().setMaster(false));
113 // 更新 139 // 更新
114 fileConfigMapper.updateById(new FileConfigDO().setId(id).setMaster(true)); 140 fileConfigMapper.updateById(new FileConfigDO().setId(id).setMaster(true));
115 - // 发送刷新配置的消息  
116 - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {  
117 -  
118 - @Override  
119 - public void afterCommit() {  
120 - fileConfigProducer.sendFileConfigRefreshMessage();  
121 - }  
122 141
123 - }); 142 + // 刷新缓存
  143 + initLocalCache();
124 } 144 }
125 145
126 private FileClientConfig parseClientConfig(Integer storage, Map<String, Object> config) { 146 private FileClientConfig parseClientConfig(Integer storage, Map<String, Object> config) {
@@ -143,8 +163,9 @@ public class FileConfigServiceImpl implements FileConfigService { @@ -143,8 +163,9 @@ public class FileConfigServiceImpl implements FileConfigService {
143 } 163 }
144 // 删除 164 // 删除
145 fileConfigMapper.deleteById(id); 165 fileConfigMapper.deleteById(id);
146 - // 发送刷新配置的消息  
147 - fileConfigProducer.sendFileConfigRefreshMessage(); 166 +
  167 + // 刷新缓存
  168 + initLocalCache();
148 } 169 }
149 170
150 private FileConfigDO validateFileConfigExists(Long id) { 171 private FileConfigDO validateFileConfigExists(Long id) {
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 @@ -16,7 +16,6 @@ import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigP
16 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigUpdateReqVO; 16 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigUpdateReqVO;
17 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; 17 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO;
18 import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper; 18 import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper;
19 -import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer;  
20 import lombok.Data; 19 import lombok.Data;
21 import org.junit.jupiter.api.Test; 20 import org.junit.jupiter.api.Test;
22 import org.springframework.boot.test.mock.mockito.MockBean; 21 import org.springframework.boot.test.mock.mockito.MockBean;
@@ -56,8 +55,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { @@ -56,8 +55,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
56 private FileConfigMapper fileConfigMapper; 55 private FileConfigMapper fileConfigMapper;
57 56
58 @MockBean 57 @MockBean
59 - private FileConfigProducer fileConfigProducer;  
60 - @MockBean  
61 private Validator validator; 58 private Validator validator;
62 @MockBean 59 @MockBean
63 private FileClientFactory fileClientFactory; 60 private FileClientFactory fileClientFactory;
@@ -81,6 +78,10 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { @@ -81,6 +78,10 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
81 verify(fileClientFactory).createOrUpdateFileClient(eq(2L), 78 verify(fileClientFactory).createOrUpdateFileClient(eq(2L),
82 eq(configDO2.getStorage()), eq(configDO2.getConfig())); 79 eq(configDO2.getStorage()), eq(configDO2.getConfig()));
83 assertSame(masterFileClient, fileConfigService.getMasterFileClient()); 80 assertSame(masterFileClient, fileConfigService.getMasterFileClient());
  81 + // 断言 fileConfigCache 缓存
  82 + assertEquals(2, fileConfigService.getFileConfigCache().size());
  83 + assertEquals(configDO1, fileConfigService.getFileConfigCache().get(0));
  84 + assertEquals(configDO2, fileConfigService.getFileConfigCache().get(1));
84 } 85 }
85 86
86 @Test 87 @Test
@@ -101,8 +102,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { @@ -101,8 +102,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
101 assertFalse(fileConfig.getMaster()); 102 assertFalse(fileConfig.getMaster());
102 assertEquals("/yunai", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath()); 103 assertEquals("/yunai", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath());
103 assertEquals("https://www.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain()); 104 assertEquals("https://www.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain());
104 - // verify 调用  
105 - verify(fileConfigProducer).sendFileConfigRefreshMessage();  
106 } 105 }
107 106
108 @Test 107 @Test
@@ -126,8 +125,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { @@ -126,8 +125,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
126 assertPojoEquals(reqVO, fileConfig, "config"); 125 assertPojoEquals(reqVO, fileConfig, "config");
127 assertEquals("/yunai2", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath()); 126 assertEquals("/yunai2", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath());
128 assertEquals("https://doc.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain()); 127 assertEquals("https://doc.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain());
129 - // verify 调用  
130 - verify(fileConfigProducer).sendFileConfigRefreshMessage();  
131 } 128 }
132 129
133 @Test 130 @Test
@@ -152,8 +149,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { @@ -152,8 +149,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
152 // 断言数据 149 // 断言数据
153 assertTrue(fileConfigMapper.selectById(dbFileConfig.getId()).getMaster()); 150 assertTrue(fileConfigMapper.selectById(dbFileConfig.getId()).getMaster());
154 assertFalse(fileConfigMapper.selectById(masterFileConfig.getId()).getMaster()); 151 assertFalse(fileConfigMapper.selectById(masterFileConfig.getId()).getMaster());
155 - // verify 调用  
156 - verify(fileConfigProducer).sendFileConfigRefreshMessage();  
157 } 152 }
158 153
159 @Test 154 @Test
@@ -174,8 +169,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { @@ -174,8 +169,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
174 fileConfigService.deleteFileConfig(id); 169 fileConfigService.deleteFileConfig(id);
175 // 校验数据不存在了 170 // 校验数据不存在了
176 assertNull(fileConfigMapper.selectById(id)); 171 assertNull(fileConfigMapper.selectById(id));
177 - // verify 调用  
178 - verify(fileConfigProducer).sendFileConfigRefreshMessage();  
179 } 172 }
180 173
181 @Test 174 @Test
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&lt;TradeCartDO&gt; { @@ -19,10 +19,10 @@ public interface TradeCartMapper extends BaseMapperX&lt;TradeCartDO&gt; {
19 19
20 default TradeCartDO selectByUserIdAndSkuId(Long userId, Long skuId, 20 default TradeCartDO selectByUserIdAndSkuId(Long userId, Long skuId,
21 Boolean addStatus, Boolean orderStatus) { 21 Boolean addStatus, Boolean orderStatus) {
22 - return selectOne(TradeCartDO::getUserId, userId,  
23 - TradeCartDO::getSkuId, skuId,  
24 - TradeCartDO::getAddStatus, addStatus,  
25 - TradeCartDO::getOrderStatus, orderStatus); 22 + return selectOne(new LambdaQueryWrapper<TradeCartDO>().eq(TradeCartDO::getUserId, userId)
  23 + .eq(TradeCartDO::getSkuId, skuId)
  24 + .eq(TradeCartDO::getAddStatus, addStatus)
  25 + .eq(TradeCartDO::getOrderStatus, orderStatus));
26 } 26 }
27 27
28 default Integer selectSumByUserId(Long userId) { 28 default Integer selectSumByUserId(Long userId) {
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; @@ -6,6 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO; 6 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO;
7 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; 7 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
  9 +import org.apache.ibatis.annotations.Select;
  10 +
  11 +import java.time.LocalDateTime;
9 12
10 @Mapper 13 @Mapper
11 public interface MpAccountMapper extends BaseMapperX<MpAccountDO> { 14 public interface MpAccountMapper extends BaseMapperX<MpAccountDO> {
@@ -22,4 +25,7 @@ public interface MpAccountMapper extends BaseMapperX&lt;MpAccountDO&gt; { @@ -22,4 +25,7 @@ public interface MpAccountMapper extends BaseMapperX&lt;MpAccountDO&gt; {
22 return selectOne(MpAccountDO::getAppId, appId); 25 return selectOne(MpAccountDO::getAppId, appId);
23 } 26 }
24 27
  28 + @Select("SELECT COUNT(*) FROM mp_account WHERE update_time > #{maxUpdateTime}")
  29 + Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
  30 +
25 } 31 }
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/consumer/MpAccountRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.mp.mq.consumer;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
4 -import cn.iocoder.yudao.module.mp.mq.message.MpAccountRefreshMessage;  
5 -import cn.iocoder.yudao.module.mp.service.account.MpAccountService;  
6 -import lombok.extern.slf4j.Slf4j;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 针对 {@link MpAccountRefreshMessage} 的消费者  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Component  
17 -@Slf4j  
18 -public class MpAccountRefreshConsumer extends AbstractChannelMessageListener<MpAccountRefreshMessage> {  
19 -  
20 - @Resource  
21 - private MpAccountService mpAccountService;  
22 -  
23 - @Override  
24 - public void onMessage(MpAccountRefreshMessage message) {  
25 - log.info("[onMessage][收到 Account 刷新消息]");  
26 - mpAccountService.initLocalCache();  
27 - }  
28 -  
29 -}  
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/MpAccountRefreshMessage.java deleted
1 -package cn.iocoder.yudao.module.mp.mq.message;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;  
4 -import lombok.Data;  
5 -import lombok.EqualsAndHashCode;  
6 -  
7 -/**  
8 - * 公众号账号刷新 Message  
9 - *  
10 - * @author 芋道源码  
11 - */  
12 -@Data  
13 -@EqualsAndHashCode(callSuper = true)  
14 -public class MpAccountRefreshMessage extends AbstractChannelMessage {  
15 -  
16 - @Override  
17 - public String getChannel() {  
18 - return "mp.account.refresh";  
19 - }  
20 -  
21 -}  
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/MpAccountProducer.java deleted
1 -package cn.iocoder.yudao.module.mp.mq.producer;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;  
4 -import cn.iocoder.yudao.module.mp.mq.message.MpAccountRefreshMessage;  
5 -import org.springframework.stereotype.Component;  
6 -  
7 -import javax.annotation.Resource;  
8 -  
9 -/**  
10 - * 公众号账号 Producer  
11 - *  
12 - * @author 芋道源码  
13 - */  
14 -@Component  
15 -public class MpAccountProducer {  
16 -  
17 - @Resource  
18 - private RedisMQTemplate redisMQTemplate;  
19 -  
20 - /**  
21 - * 发送 {@link MpAccountRefreshMessage} 消息  
22 - */  
23 - public void sendAccountRefreshMessage() {  
24 - MpAccountRefreshMessage message = new MpAccountRefreshMessage();  
25 - redisMQTemplate.send(message);  
26 - }  
27 -  
28 -}  
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java
1 package cn.iocoder.yudao.module.mp.service.account; 1 package cn.iocoder.yudao.module.mp.service.account;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.hutool.core.util.ObjUtil; 4 import cn.hutool.core.util.ObjUtil;
4 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; 5 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
7 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; 7 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
8 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO; 8 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO;
9 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO; 9 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; @@ -13,7 +13,6 @@ import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
13 import cn.iocoder.yudao.module.mp.dal.mysql.account.MpAccountMapper; 13 import cn.iocoder.yudao.module.mp.dal.mysql.account.MpAccountMapper;
14 import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants; 14 import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants;
15 import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; 15 import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
16 -import cn.iocoder.yudao.module.mp.mq.producer.MpAccountProducer;  
17 import com.google.common.annotations.VisibleForTesting; 16 import com.google.common.annotations.VisibleForTesting;
18 import lombok.Getter; 17 import lombok.Getter;
19 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
@@ -21,15 +20,20 @@ import me.chanjar.weixin.common.error.WxErrorException; @@ -21,15 +20,20 @@ import me.chanjar.weixin.common.error.WxErrorException;
21 import me.chanjar.weixin.mp.api.WxMpService; 20 import me.chanjar.weixin.mp.api.WxMpService;
22 import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; 21 import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
23 import org.springframework.context.annotation.Lazy; 22 import org.springframework.context.annotation.Lazy;
  23 +import org.springframework.scheduling.annotation.Scheduled;
24 import org.springframework.stereotype.Service; 24 import org.springframework.stereotype.Service;
25 import org.springframework.validation.annotation.Validated; 25 import org.springframework.validation.annotation.Validated;
26 26
27 import javax.annotation.PostConstruct; 27 import javax.annotation.PostConstruct;
28 import javax.annotation.Resource; 28 import javax.annotation.Resource;
  29 +import java.time.LocalDateTime;
29 import java.util.List; 30 import java.util.List;
30 import java.util.Map; 31 import java.util.Map;
  32 +import java.util.concurrent.TimeUnit;
31 33
32 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 34 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  35 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  36 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue;
33 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_USERNAME_EXISTS; 37 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_USERNAME_EXISTS;
34 38
35 /** 39 /**
@@ -58,9 +62,6 @@ public class MpAccountServiceImpl implements MpAccountService { @@ -58,9 +62,6 @@ public class MpAccountServiceImpl implements MpAccountService {
58 @Lazy // 延迟加载,解决循环依赖的问题 62 @Lazy // 延迟加载,解决循环依赖的问题
59 private MpServiceFactory mpServiceFactory; 63 private MpServiceFactory mpServiceFactory;
60 64
61 - @Resource  
62 - private MpAccountProducer mpAccountProducer;  
63 -  
64 @Override 65 @Override
65 @PostConstruct 66 @PostConstruct
66 public void initLocalCache() { 67 public void initLocalCache() {
@@ -72,7 +73,30 @@ public class MpAccountServiceImpl implements MpAccountService { @@ -72,7 +73,30 @@ public class MpAccountServiceImpl implements MpAccountService {
72 73
73 // 第二步:构建缓存。创建或更新支付 Client 74 // 第二步:构建缓存。创建或更新支付 Client
74 mpServiceFactory.init(accounts); 75 mpServiceFactory.init(accounts);
75 - accountCache = CollectionUtils.convertMap(accounts, MpAccountDO::getAppId); 76 + accountCache = convertMap(accounts, MpAccountDO::getAppId);
  77 + });
  78 + }
  79 +
  80 + /**
  81 + * 通过定时任务轮询,刷新缓存
  82 + *
  83 + * 目的:多节点部署时,通过轮询”通知“所有节点,进行刷新
  84 + */
  85 + @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS)
  86 + public void refreshLocalCache() {
  87 + // 注意:忽略自动多租户,因为要全局初始化缓存
  88 + TenantUtils.executeIgnore(() -> {
  89 + // 情况一:如果缓存里没有数据,则直接刷新缓存
  90 + if (CollUtil.isEmpty(accountCache)) {
  91 + initLocalCache();
  92 + return;
  93 + }
  94 +
  95 + // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存
  96 + LocalDateTime maxTime = getMaxValue(accountCache.values(), MpAccountDO::getUpdateTime);
  97 + if (mpAccountMapper.selectCountByUpdateTimeGt(maxTime) > 0) {
  98 + initLocalCache();
  99 + }
76 }); 100 });
77 } 101 }
78 102
@@ -85,8 +109,8 @@ public class MpAccountServiceImpl implements MpAccountService { @@ -85,8 +109,8 @@ public class MpAccountServiceImpl implements MpAccountService {
85 MpAccountDO account = MpAccountConvert.INSTANCE.convert(createReqVO); 109 MpAccountDO account = MpAccountConvert.INSTANCE.convert(createReqVO);
86 mpAccountMapper.insert(account); 110 mpAccountMapper.insert(account);
87 111
88 - // 发送刷新消息  
89 - mpAccountProducer.sendAccountRefreshMessage(); 112 + // 刷新缓存
  113 + initLocalCache();
90 return account.getId(); 114 return account.getId();
91 } 115 }
92 116
@@ -101,8 +125,8 @@ public class MpAccountServiceImpl implements MpAccountService { @@ -101,8 +125,8 @@ public class MpAccountServiceImpl implements MpAccountService {
101 MpAccountDO updateObj = MpAccountConvert.INSTANCE.convert(updateReqVO); 125 MpAccountDO updateObj = MpAccountConvert.INSTANCE.convert(updateReqVO);
102 mpAccountMapper.updateById(updateObj); 126 mpAccountMapper.updateById(updateObj);
103 127
104 - // 发送刷新消息  
105 - mpAccountProducer.sendAccountRefreshMessage(); 128 + // 刷新缓存
  129 + initLocalCache();
106 } 130 }
107 131
108 @Override 132 @Override
@@ -112,8 +136,8 @@ public class MpAccountServiceImpl implements MpAccountService { @@ -112,8 +136,8 @@ public class MpAccountServiceImpl implements MpAccountService {
112 // 删除 136 // 删除
113 mpAccountMapper.deleteById(id); 137 mpAccountMapper.deleteById(id);
114 138
115 - // 发送刷新消息  
116 - mpAccountProducer.sendAccountRefreshMessage(); 139 + // 刷新缓存
  140 + initLocalCache();
117 } 141 }
118 142
119 private MpAccountDO validateAccountExists(Long id) { 143 private MpAccountDO validateAccountExists(Long id) {
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; @@ -6,8 +6,6 @@ import lombok.Data;
6 /** 6 /**
7 * 支付单信息 Response DTO 7 * 支付单信息 Response DTO
8 * 8 *
9 - * TODO 芋艿:还没定好字段  
10 - *  
11 * @author 芋道源码 9 * @author 芋道源码
12 */ 10 */
13 @Data 11 @Data
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; @@ -8,8 +8,6 @@ import java.time.LocalDateTime;
8 /** 8 /**
9 * 退款单信息 Response DTO 9 * 退款单信息 Response DTO
10 * 10 *
11 - * TODO 芋艿:还没定好字段  
12 - *  
13 * @author 芋道源码 11 * @author 芋道源码
14 */ 12 */
15 @Data 13 @Data
yudao-module-pay/yudao-module-pay-biz/pom.xml
@@ -61,12 +61,6 @@ @@ -61,12 +61,6 @@
61 <artifactId>yudao-spring-boot-starter-job</artifactId> 61 <artifactId>yudao-spring-boot-starter-job</artifactId>
62 </dependency> 62 </dependency>
63 63
64 - <!-- 消息队列相关 -->  
65 - <dependency>  
66 - <groupId>cn.iocoder.boot</groupId>  
67 - <artifactId>yudao-spring-boot-starter-mq</artifactId>  
68 - </dependency>  
69 -  
70 <!-- Test 测试相关 --> 64 <!-- Test 测试相关 -->
71 <dependency> 65 <dependency>
72 <groupId>cn.iocoder.boot</groupId> 66 <groupId>cn.iocoder.boot</groupId>
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/RedisKeyConstants.java
1 package cn.iocoder.yudao.module.pay.dal.redis; 1 package cn.iocoder.yudao.module.pay.dal.redis;
2 2
3 -import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;  
4 -import org.redisson.api.RLock;  
5 -  
6 /** 3 /**
7 * 支付 Redis Key 枚举类 4 * 支付 Redis Key 枚举类
8 * 5 *
@@ -10,9 +7,14 @@ import org.redisson.api.RLock; @@ -10,9 +7,14 @@ import org.redisson.api.RLock;
10 */ 7 */
11 public interface RedisKeyConstants { 8 public interface RedisKeyConstants {
12 9
13 - RedisKeyDefine PAY_NOTIFY_LOCK = new RedisKeyDefine("通知任务的分布式锁",  
14 - "pay_notify:lock:%d", // 参数来自 DefaultLockKeyBuilder 类  
15 - RedisKeyDefine.KeyTypeEnum.HASH, RLock.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); // Redisson 的 Lock 锁,使用 Hash 数据结构 10 + /**
  11 + * 通知任务的分布式锁
  12 + *
  13 + * KEY 格式:pay_notify:lock:%d // 参数来自 DefaultLockKeyBuilder 类
  14 + * VALUE 数据格式:HASH // RLock.class:Redisson 的 Lock 锁,使用 Hash 数据结构
  15 + * 过期时间:不固定
  16 + */
  17 + String PAY_NOTIFY_LOCK = "pay_notify:lock:%d";
16 18
17 /** 19 /**
18 * 支付序号的缓存 20 * 支付序号的缓存
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 { @@ -33,7 +33,7 @@ public class PayNotifyLockRedisDAO {
33 } 33 }
34 34
35 private static String formatKey(Long id) { 35 private static String formatKey(Long id) {
36 - return String.format(PAY_NOTIFY_LOCK.getKeyTemplate(), id); 36 + return String.format(PAY_NOTIFY_LOCK, id);
37 } 37 }
38 38
39 } 39 }
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 @@ -15,7 +15,6 @@ import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelUpdateR
15 import cn.iocoder.yudao.module.pay.convert.channel.PayChannelConvert; 15 import cn.iocoder.yudao.module.pay.convert.channel.PayChannelConvert;
16 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; 16 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
17 import cn.iocoder.yudao.module.pay.dal.mysql.channel.PayChannelMapper; 17 import cn.iocoder.yudao.module.pay.dal.mysql.channel.PayChannelMapper;
18 -import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;  
19 import lombok.Getter; 18 import lombok.Getter;
20 import lombok.Setter; 19 import lombok.Setter;
21 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
@@ -112,7 +111,7 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -112,7 +111,7 @@ public class PayChannelServiceImpl implements PayChannelService {
112 channelMapper.insert(channel); 111 channelMapper.insert(channel);
113 112
114 // 刷新缓存 113 // 刷新缓存
115 - refreshLocalCache(); 114 + initLocalCache();
116 return channel.getId(); 115 return channel.getId();
117 } 116 }
118 117
@@ -127,7 +126,7 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -127,7 +126,7 @@ public class PayChannelServiceImpl implements PayChannelService {
127 channelMapper.updateById(channel); 126 channelMapper.updateById(channel);
128 127
129 // 刷新缓存 128 // 刷新缓存
130 - refreshLocalCache(); 129 + initLocalCache();
131 } 130 }
132 131
133 /** 132 /**
@@ -160,7 +159,7 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -160,7 +159,7 @@ public class PayChannelServiceImpl implements PayChannelService {
160 channelMapper.deleteById(id); 159 channelMapper.deleteById(id);
161 160
162 // 刷新缓存 161 // 刷新缓存
163 - refreshLocalCache(); 162 + initLocalCache();
164 } 163 }
165 164
166 private PayChannelDO validateChannelExists(Long id) { 165 private PayChannelDO validateChannelExists(Long id) {
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 { @@ -44,7 +44,7 @@ public interface AdminUserApi {
44 * @param postIds 岗位数组 44 * @param postIds 岗位数组
45 * @return 用户数组 45 * @return 用户数组
46 */ 46 */
47 - List<AdminUserRespDTO> getUsersByPostIds(Collection<Long> postIds); 47 + List<AdminUserRespDTO> getUserListByPostIds(Collection<Long> postIds);
48 48
49 /** 49 /**
50 * 获得用户 Map 50 * 获得用户 Map
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 { @@ -21,7 +21,7 @@ public class PermissionApiImpl implements PermissionApi {
21 21
22 @Override 22 @Override
23 public Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds) { 23 public Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds) {
24 - return permissionService.getUserRoleIdListByRoleIds(roleIds); 24 + return permissionService.getUserRoleIdListByRoleId(roleIds);
25 } 25 }
26 26
27 @Override 27 @Override
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 { @@ -40,7 +40,7 @@ public class AdminUserApiImpl implements AdminUserApi {
40 } 40 }
41 41
42 @Override 42 @Override
43 - public List<AdminUserRespDTO> getUsersByPostIds(Collection<Long> postIds) { 43 + public List<AdminUserRespDTO> getUserListByPostIds(Collection<Long> postIds) {
44 List<AdminUserDO> users = userService.getUserListByPostIds(postIds); 44 List<AdminUserDO> users = userService.getUserListByPostIds(postIds);
45 return UserConvert.INSTANCE.convertList4(users); 45 return UserConvert.INSTANCE.convertList4(users);
46 } 46 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.http
@@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
2 POST {{baseUrl}}/system/auth/login 2 POST {{baseUrl}}/system/auth/login
3 Content-Type: application/json 3 Content-Type: application/json
4 tenant-id: {{adminTenentId}} 4 tenant-id: {{adminTenentId}}
  5 +tag: Yunai.local
5 6
6 { 7 {
7 "username": "admin", 8 "username": "admin",
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; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.controller.admin.auth;
3 import cn.hutool.core.util.StrUtil; 3 import cn.hutool.core.util.StrUtil;
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 -import cn.iocoder.yudao.framework.common.util.collection.SetUtils;  
7 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; 6 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
8 import cn.iocoder.yudao.framework.security.config.SecurityProperties; 7 import cn.iocoder.yudao.framework.security.config.SecurityProperties;
9 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*; 8 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
@@ -12,8 +11,8 @@ import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; @@ -12,8 +11,8 @@ import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
12 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; 11 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
13 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; 12 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
14 import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; 13 import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
15 -import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;  
16 import cn.iocoder.yudao.module.system.service.auth.AdminAuthService; 14 import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
  15 +import cn.iocoder.yudao.module.system.service.permission.MenuService;
17 import cn.iocoder.yudao.module.system.service.permission.PermissionService; 16 import cn.iocoder.yudao.module.system.service.permission.PermissionService;
18 import cn.iocoder.yudao.module.system.service.permission.RoleService; 17 import cn.iocoder.yudao.module.system.service.permission.RoleService;
19 import cn.iocoder.yudao.module.system.service.social.SocialUserService; 18 import cn.iocoder.yudao.module.system.service.social.SocialUserService;
@@ -34,9 +33,9 @@ import java.util.List; @@ -34,9 +33,9 @@ import java.util.List;
34 import java.util.Set; 33 import java.util.Set;
35 34
36 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 35 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  36 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
37 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; 37 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
38 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.obtainAuthorization; 38 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.obtainAuthorization;
39 -import static java.util.Collections.singleton;  
40 39
41 @Tag(name = "管理后台 - 认证") 40 @Tag(name = "管理后台 - 认证")
42 @RestController 41 @RestController
@@ -52,6 +51,8 @@ public class AuthController { @@ -52,6 +51,8 @@ public class AuthController {
52 @Resource 51 @Resource
53 private RoleService roleService; 52 private RoleService roleService;
54 @Resource 53 @Resource
  54 + private MenuService menuService;
  55 + @Resource
55 private PermissionService permissionService; 56 private PermissionService permissionService;
56 @Resource 57 @Resource
57 private SocialUserService socialUserService; 58 private SocialUserService socialUserService;
@@ -91,33 +92,24 @@ public class AuthController { @@ -91,33 +92,24 @@ public class AuthController {
91 @GetMapping("/get-permission-info") 92 @GetMapping("/get-permission-info")
92 @Operation(summary = "获取登录用户的权限信息") 93 @Operation(summary = "获取登录用户的权限信息")
93 public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() { 94 public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
94 - // 获得用户信息 95 + // 1.1 获得用户信息
95 AdminUserDO user = userService.getUser(getLoginUserId()); 96 AdminUserDO user = userService.getUser(getLoginUserId());
96 if (user == null) { 97 if (user == null) {
97 return null; 98 return null;
98 } 99 }
99 - // 获得角色列表  
100 - Set<Long> roleIds = permissionService.getUserRoleIdsFromCache(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));  
101 - List<RoleDO> roleList = roleService.getRoleListFromCache(roleIds);  
102 - // 获得菜单列表  
103 - List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds,  
104 - SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType(), MenuTypeEnum.BUTTON.getType()),  
105 - singleton(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的  
106 - // 拼接结果返回  
107 - return success(AuthConvert.INSTANCE.convert(user, roleList, menuList));  
108 - }  
109 100
110 - @GetMapping("/list-menus")  
111 - @Operation(summary = "获得登录用户的菜单列表")  
112 - public CommonResult<List<AuthMenuRespVO>> getMenuList() {  
113 - // 获得角色列表  
114 - Set<Long> roleIds = permissionService.getUserRoleIdsFromCache(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));  
115 - // 获得用户拥有的菜单列表  
116 - List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds,  
117 - SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型  
118 - singleton(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的  
119 - // 转换成 Tree 结构返回  
120 - return success(AuthConvert.INSTANCE.buildMenuTree(menuList)); 101 + // 1.2 获得角色列表
  102 + Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
  103 + List<RoleDO> roles = roleService.getRoleList(roleIds);
  104 + roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
  105 +
  106 + // 1.3 获得菜单列表
  107 + Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
  108 + List<MenuDO> menuList = menuService.getMenuList(menuIds);
  109 + menuList.removeIf(menu -> !CommonStatusEnum.ENABLE.getStatus().equals(menu.getStatus())); // 移除禁用的菜单
  110 +
  111 + // 2. 拼接结果返回
  112 + return success(AuthConvert.INSTANCE.convert(user, roles, menuList));
121 } 113 }
122 114
123 // ========== 短信登录相关 ========== 115 // ========== 短信登录相关 ==========
@@ -149,7 +141,7 @@ public class AuthController { @@ -149,7 +141,7 @@ public class AuthController {
149 @Parameter(name = "redirectUri", description = "回调路径") 141 @Parameter(name = "redirectUri", description = "回调路径")
150 }) 142 })
151 public CommonResult<String> socialLogin(@RequestParam("type") Integer type, 143 public CommonResult<String> socialLogin(@RequestParam("type") Integer type,
152 - @RequestParam("redirectUri") String redirectUri) { 144 + @RequestParam("redirectUri") String redirectUri) {
153 return CommonResult.success(socialUserService.getAuthorizeUrl(type, redirectUri)); 145 return CommonResult.success(socialUserService.getAuthorizeUrl(type, redirectUri));
154 } 146 }
155 147
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; @@ -6,9 +6,10 @@ import lombok.Builder;
6 import lombok.Data; 6 import lombok.Data;
7 import lombok.NoArgsConstructor; 7 import lombok.NoArgsConstructor;
8 8
  9 +import java.util.List;
9 import java.util.Set; 10 import java.util.Set;
10 11
11 -@Schema(description = "管理后台 - 登录用户的权限信息 Response VO,额外包括用户信息和角色列表") 12 +@Schema(description = "管理后台 - 登录用户的权限信息 Response VO,额外包括用户信息和角色列表")
12 @Data 13 @Data
13 @NoArgsConstructor 14 @NoArgsConstructor
14 @AllArgsConstructor 15 @AllArgsConstructor
@@ -24,6 +25,9 @@ public class AuthPermissionInfoRespVO { @@ -24,6 +25,9 @@ public class AuthPermissionInfoRespVO {
24 @Schema(description = "操作权限数组", requiredMode = Schema.RequiredMode.REQUIRED) 25 @Schema(description = "操作权限数组", requiredMode = Schema.RequiredMode.REQUIRED)
25 private Set<String> permissions; 26 private Set<String> permissions;
26 27
  28 + @Schema(description = "菜单树", required = true)
  29 + private List<MenuVO> menus;
  30 +
27 @Schema(description = "用户信息 VO") 31 @Schema(description = "用户信息 VO")
28 @Data 32 @Data
29 @NoArgsConstructor 33 @NoArgsConstructor
@@ -37,9 +41,53 @@ public class AuthPermissionInfoRespVO { @@ -37,9 +41,53 @@ public class AuthPermissionInfoRespVO {
37 @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") 41 @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
38 private String nickname; 42 private String nickname;
39 43
40 - @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://www.iocoder.cn/xx.jpg") 44 + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.jpg")
41 private String avatar; 45 private String avatar;
42 46
43 } 47 }
44 48
  49 + @Schema(description = "管理后台 - 登录用户的菜单信息 Response VO")
  50 + @Data
  51 + @NoArgsConstructor
  52 + @AllArgsConstructor
  53 + @Builder
  54 + public static class MenuVO {
  55 +
  56 + @Schema(description = "菜单名称", required = true, example = "芋道")
  57 + private Long id;
  58 +
  59 + @Schema(description = "父菜单 ID", required = true, example = "1024")
  60 + private Long parentId;
  61 +
  62 + @Schema(description = "菜单名称", required = true, example = "芋道")
  63 + private String name;
  64 +
  65 + @Schema(description = "路由地址,仅菜单类型为菜单或者目录时,才需要传", example = "post")
  66 + private String path;
  67 +
  68 + @Schema(description = "组件路径,仅菜单类型为菜单时,才需要传", example = "system/post/index")
  69 + private String component;
  70 +
  71 + @Schema(description = "组件名", example = "SystemUser")
  72 + private String componentName;
  73 +
  74 + @Schema(description = "菜单图标,仅菜单类型为菜单或者目录时,才需要传", example = "/menu/list")
  75 + private String icon;
  76 +
  77 + @Schema(description = "是否可见", required = true, example = "false")
  78 + private Boolean visible;
  79 +
  80 + @Schema(description = "是否缓存", required = true, example = "false")
  81 + private Boolean keepAlive;
  82 +
  83 + @Schema(description = "是否总是显示", example = "false")
  84 + private Boolean alwaysShow;
  85 +
  86 + /**
  87 + * 子路由
  88 + */
  89 + private List<MenuVO> children;
  90 +
  91 + }
  92 +
45 } 93 }
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; @@ -11,9 +11,9 @@ import java.util.Map;
11 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; 11 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
12 12
13 /** 13 /**
14 -* 邮件日志 Base VO,提供给添加、修改、详细的子 VO 使用  
15 -* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成  
16 -*/ 14 + * 邮件日志 Base VO,提供给添加、修改、详细的子 VO 使用
  15 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  16 + */
17 @Data 17 @Data
18 public class MailLogBaseVO { 18 public class MailLogBaseVO {
19 19
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 { @@ -37,10 +37,10 @@ public class PermissionController {
37 37
38 @Operation(summary = "获得角色拥有的菜单编号") 38 @Operation(summary = "获得角色拥有的菜单编号")
39 @Parameter(name = "roleId", description = "角色编号", required = true) 39 @Parameter(name = "roleId", description = "角色编号", required = true)
40 - @GetMapping("/list-role-resources") 40 + @GetMapping("/list-role-menus")
41 @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')") 41 @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')")
42 - public CommonResult<Set<Long>> listRoleMenus(Long roleId) {  
43 - return success(permissionService.getRoleMenuIds(roleId)); 42 + public CommonResult<Set<Long>> getRoleMenuList(Long roleId) {
  43 + return success(permissionService.getRoleMenuListByRoleId(roleId));
44 } 44 }
45 45
46 @PostMapping("/assign-role-menu") 46 @PostMapping("/assign-role-menu")
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}} @@ -40,6 +40,3 @@ tenant-id: {{adminTenentId}}
40 GET {{baseUrl}}/system/role/page?pageNo=1&pageSize=10 40 GET {{baseUrl}}/system/role/page?pageNo=1&pageSize=10
41 Authorization: Bearer {{token}} 41 Authorization: Bearer {{token}}
42 tenant-id: {{adminTenentId}} 42 tenant-id: {{adminTenentId}}
43 -  
44 -###  
45 -  
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 { @@ -20,7 +20,7 @@ public class PermissionAssignRoleDataScopeReqVO {
20 // TODO 这里要多一个枚举校验 20 // TODO 这里要多一个枚举校验
21 private Integer dataScope; 21 private Integer dataScope;
22 22
23 - @Schema(description = "部门编号列表,只有范围类型为 DEPT_CUSTOM 时,该字段才需要", example = "1,3,5") 23 + @Schema(description = "部门编号列表,只有范围类型为 DEPT_CUSTOM 时,该字段才需要", example = "1,3,5")
24 private Set<Long> dataScopeDeptIds = Collections.emptySet(); // 兜底 24 private Set<Long> dataScopeDeptIds = Collections.emptySet(); // 兜底
25 25
26 } 26 }
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; @@ -7,9 +7,9 @@ import javax.validation.constraints.NotNull;
7 import java.util.List; 7 import java.util.List;
8 8
9 /** 9 /**
10 -* 敏感词 Base VO,提供给添加、修改、详细的子 VO 使用  
11 -* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成  
12 -*/ 10 + * 敏感词 Base VO,提供给添加、修改、详细的子 VO 使用
  11 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  12 + */
13 @Data 13 @Data
14 public class SensitiveWordBaseVO { 14 public class SensitiveWordBaseVO {
15 15
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.*; @@ -7,9 +7,9 @@ import javax.validation.constraints.*;
7 import java.time.LocalDateTime; 7 import java.time.LocalDateTime;
8 8
9 /** 9 /**
10 -* 租户 Base VO,提供给添加、修改、详细的子 VO 使用  
11 -* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成  
12 -*/ 10 + * 租户 Base VO,提供给添加、修改、详细的子 VO 使用
  11 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  12 + */
13 @Data 13 @Data
14 public class TenantBaseVO { 14 public class TenantBaseVO {
15 15
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 { @@ -25,7 +25,7 @@ public class UserProfileUpdateReqVO {
25 @Length(min = 11, max = 11, message = "手机号长度必须 11 位") 25 @Length(min = 11, max = 11, message = "手机号长度必须 11 位")
26 private String mobile; 26 private String mobile;
27 27
28 - @Schema(description = "用户性别-参见 SexEnum 枚举类", example = "1") 28 + @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1")
29 private Integer sex; 29 private Integer sex;
30 30
31 } 31 }
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 { @@ -29,7 +29,7 @@ public class UserExportReqVO {
29 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 29 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
30 private LocalDateTime[] createTime; 30 private LocalDateTime[] createTime;
31 31
32 - @Schema(description = "部门编号,同时筛选子部门", example = "1024") 32 + @Schema(description = "部门编号,同时筛选子部门", example = "1024")
33 private Long deptId; 33 private Long deptId;
34 34
35 } 35 }
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; @@ -6,7 +6,7 @@ import lombok.Data;
6 import lombok.EqualsAndHashCode; 6 import lombok.EqualsAndHashCode;
7 import lombok.NoArgsConstructor; 7 import lombok.NoArgsConstructor;
8 8
9 -@Schema(description = "管理后台 - 用户分页时的信息 Response VO,相比用户基本信息来说,会多部门信息") 9 +@Schema(description = "管理后台 - 用户分页时的信息 Response VO,相比用户基本信息来说,会多部门信息")
10 @Data 10 @Data
11 @NoArgsConstructor 11 @NoArgsConstructor
12 @AllArgsConstructor 12 @AllArgsConstructor
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserUpdateStatusReqVO.java
1 package cn.iocoder.yudao.module.system.controller.admin.user.vo.user; 1 package cn.iocoder.yudao.module.system.controller.admin.user.vo.user;
2 2
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
3 import io.swagger.v3.oas.annotations.media.Schema; 5 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 6 import lombok.Data;
5 7
@@ -13,9 +15,9 @@ public class UserUpdateStatusReqVO { @@ -13,9 +15,9 @@ public class UserUpdateStatusReqVO {
13 @NotNull(message = "角色编号不能为空") 15 @NotNull(message = "角色编号不能为空")
14 private Long id; 16 private Long id;
15 17
16 - @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 18 + @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
17 @NotNull(message = "状态不能为空") 19 @NotNull(message = "状态不能为空")
18 -// @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") 20 + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
19 private Integer status; 21 private Integer status;
20 22
21 } 23 }
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; @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
8 import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; 8 import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
9 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; 9 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
10 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; 10 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
  11 +import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
11 import org.mapstruct.Mapper; 12 import org.mapstruct.Mapper;
12 import org.mapstruct.factory.Mappers; 13 import org.mapstruct.factory.Mappers;
13 import org.slf4j.LoggerFactory; 14 import org.slf4j.LoggerFactory;
@@ -27,13 +28,16 @@ public interface AuthConvert { @@ -27,13 +28,16 @@ public interface AuthConvert {
27 28
28 default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) { 29 default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) {
29 return AuthPermissionInfoRespVO.builder() 30 return AuthPermissionInfoRespVO.builder()
30 - .user(AuthPermissionInfoRespVO.UserVO.builder().id(user.getId()).nickname(user.getNickname()).avatar(user.getAvatar()).build())  
31 - .roles(convertSet(roleList, RoleDO::getCode))  
32 - .permissions(convertSet(menuList, MenuDO::getPermission))  
33 - .build(); 31 + .user(AuthPermissionInfoRespVO.UserVO.builder().id(user.getId()).nickname(user.getNickname()).avatar(user.getAvatar()).build())
  32 + .roles(convertSet(roleList, RoleDO::getCode))
  33 + // 权限标识信息
  34 + .permissions(convertSet(menuList, MenuDO::getPermission))
  35 + // 菜单树
  36 + .menus(buildMenuTree(menuList))
  37 + .build();
34 } 38 }
35 39
36 - AuthMenuRespVO convertTreeNode(MenuDO menu); 40 + AuthPermissionInfoRespVO.MenuVO convertTreeNode(MenuDO menu);
37 41
38 /** 42 /**
39 * 将菜单列表,构建成菜单树 43 * 将菜单列表,构建成菜单树
@@ -41,20 +45,23 @@ public interface AuthConvert { @@ -41,20 +45,23 @@ public interface AuthConvert {
41 * @param menuList 菜单列表 45 * @param menuList 菜单列表
42 * @return 菜单树 46 * @return 菜单树
43 */ 47 */
44 - default List<AuthMenuRespVO> buildMenuTree(List<MenuDO> menuList) { 48 + default List<AuthPermissionInfoRespVO.MenuVO> buildMenuTree(List<MenuDO> menuList) {
  49 + // 移除按钮
  50 + menuList.removeIf(menu -> menu.getType().equals(MenuTypeEnum.BUTTON.getType()));
45 // 排序,保证菜单的有序性 51 // 排序,保证菜单的有序性
46 menuList.sort(Comparator.comparing(MenuDO::getSort)); 52 menuList.sort(Comparator.comparing(MenuDO::getSort));
  53 +
47 // 构建菜单树 54 // 构建菜单树
48 // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。 55 // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。
49 - Map<Long, AuthMenuRespVO> treeNodeMap = new LinkedHashMap<>(); 56 + Map<Long, AuthPermissionInfoRespVO.MenuVO> treeNodeMap = new LinkedHashMap<>();
50 menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AuthConvert.INSTANCE.convertTreeNode(menu))); 57 menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AuthConvert.INSTANCE.convertTreeNode(menu)));
51 // 处理父子关系 58 // 处理父子关系
52 treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(ID_ROOT)).forEach(childNode -> { 59 treeNodeMap.values().stream().filter(node -> !node.getParentId().equals(ID_ROOT)).forEach(childNode -> {
53 // 获得父节点 60 // 获得父节点
54 - AuthMenuRespVO parentNode = treeNodeMap.get(childNode.getParentId()); 61 + AuthPermissionInfoRespVO.MenuVO parentNode = treeNodeMap.get(childNode.getParentId());
55 if (parentNode == null) { 62 if (parentNode == null) {
56 LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]", 63 LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]",
57 - childNode.getId(), childNode.getParentId()); 64 + childNode.getId(), childNode.getParentId());
58 return; 65 return;
59 } 66 }
60 // 将自己添加到父节点中 67 // 将自己添加到父节点中
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 @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqV
6 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; 6 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
7 import org.apache.ibatis.annotations.Mapper; 7 import org.apache.ibatis.annotations.Mapper;
8 8
  9 +import java.util.Collection;
9 import java.util.List; 10 import java.util.List;
10 11
11 @Mapper 12 @Mapper
@@ -25,4 +26,8 @@ public interface DeptMapper extends BaseMapperX&lt;DeptDO&gt; { @@ -25,4 +26,8 @@ public interface DeptMapper extends BaseMapperX&lt;DeptDO&gt; {
25 return selectCount(DeptDO::getParentId, parentId); 26 return selectCount(DeptDO::getParentId, parentId);
26 } 27 }
27 28
  29 + default List<DeptDO> selectListByParentId(Collection<Long> parentIds) {
  30 + return selectList(DeptDO::getParentId, parentIds);
  31 + }
  32 +
28 } 33 }
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&lt;MenuDO&gt; { @@ -25,4 +25,7 @@ public interface MenuMapper extends BaseMapperX&lt;MenuDO&gt; {
25 .eqIfPresent(MenuDO::getStatus, reqVO.getStatus())); 25 .eqIfPresent(MenuDO::getStatus, reqVO.getStatus()));
26 } 26 }
27 27
  28 + default List<MenuDO> selectListByPermission(String permission) {
  29 + return selectList(MenuDO::getPermission, permission);
  30 + }
28 } 31 }
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; @@ -3,9 +3,7 @@ package cn.iocoder.yudao.module.system.dal.mysql.permission;
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO; 4 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO;
5 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 5 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
6 -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;  
7 import org.apache.ibatis.annotations.Mapper; 6 import org.apache.ibatis.annotations.Mapper;
8 -import org.springframework.stereotype.Repository;  
9 7
10 import java.util.Collection; 8 import java.util.Collection;
11 import java.util.List; 9 import java.util.List;
@@ -13,14 +11,18 @@ import java.util.List; @@ -13,14 +11,18 @@ import java.util.List;
13 @Mapper 11 @Mapper
14 public interface RoleMenuMapper extends BaseMapperX<RoleMenuDO> { 12 public interface RoleMenuMapper extends BaseMapperX<RoleMenuDO> {
15 13
16 - @Repository  
17 - class BatchInsertMapper extends ServiceImpl<RoleMenuMapper, RoleMenuDO> {  
18 - }  
19 -  
20 default List<RoleMenuDO> selectListByRoleId(Long roleId) { 14 default List<RoleMenuDO> selectListByRoleId(Long roleId) {
21 return selectList(RoleMenuDO::getRoleId, roleId); 15 return selectList(RoleMenuDO::getRoleId, roleId);
22 } 16 }
23 17
  18 + default List<RoleMenuDO> selectListByRoleId(Collection<Long> roleIds) {
  19 + return selectList(RoleMenuDO::getRoleId, roleIds);
  20 + }
  21 +
  22 + default List<RoleMenuDO> selectListByMenuId(Long menuId) {
  23 + return selectList(RoleMenuDO::getMenuId, menuId);
  24 + }
  25 +
24 default void deleteListByRoleIdAndMenuIds(Long roleId, Collection<Long> menuIds) { 26 default void deleteListByRoleIdAndMenuIds(Long roleId, Collection<Long> menuIds) {
25 delete(new LambdaQueryWrapper<RoleMenuDO>() 27 delete(new LambdaQueryWrapper<RoleMenuDO>()
26 .eq(RoleMenuDO::getRoleId, roleId) 28 .eq(RoleMenuDO::getRoleId, roleId)
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 @@ -7,7 +7,9 @@ import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.Sensitiv
7 import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO; 7 import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO;
8 import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO; 8 import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO;
9 import org.apache.ibatis.annotations.Mapper; 9 import org.apache.ibatis.annotations.Mapper;
  10 +import org.apache.ibatis.annotations.Select;
10 11
  12 +import java.time.LocalDateTime;
11 import java.util.List; 13 import java.util.List;
12 14
13 /** 15 /**
@@ -40,4 +42,7 @@ public interface SensitiveWordMapper extends BaseMapperX&lt;SensitiveWordDO&gt; { @@ -40,4 +42,7 @@ public interface SensitiveWordMapper extends BaseMapperX&lt;SensitiveWordDO&gt; {
40 return selectOne(SensitiveWordDO::getName, name); 42 return selectOne(SensitiveWordDO::getName, name);
41 } 43 }
42 44
  45 + @Select("SELECT COUNT(*) FROM system_sensitive_word WHERE update_time > #{maxUpdateTime}")
  46 + Long selectCountByUpdateTimeGt(LocalDateTime maxTime);
  47 +
43 } 48 }
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; @@ -6,6 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; 6 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO;
7 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; 7 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
  9 +import org.apache.ibatis.annotations.Select;
  10 +
  11 +import java.time.LocalDateTime;
9 12
10 @Mapper 13 @Mapper
11 public interface SmsChannelMapper extends BaseMapperX<SmsChannelDO> { 14 public interface SmsChannelMapper extends BaseMapperX<SmsChannelDO> {
@@ -18,4 +21,7 @@ public interface SmsChannelMapper extends BaseMapperX&lt;SmsChannelDO&gt; { @@ -18,4 +21,7 @@ public interface SmsChannelMapper extends BaseMapperX&lt;SmsChannelDO&gt; {
18 .orderByDesc(SmsChannelDO::getId)); 21 .orderByDesc(SmsChannelDO::getId));
19 } 22 }
20 23
  24 + @Select("SELECT COUNT(*) FROM system_sms_channel WHERE update_time > #{maxUpdateTime}")
  25 + Long selectCountByUpdateTimeGt(LocalDateTime maxTime);
  26 +
21 } 27 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java
1 package cn.iocoder.yudao.module.system.dal.redis; 1 package cn.iocoder.yudao.module.system.dal.redis;
2 2
3 -import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;  
4 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; 3 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
5 4
6 -import java.time.Duration;  
7 -  
8 -import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING;  
9 -  
10 /** 5 /**
11 * System Redis Key 枚举类 6 * System Redis Key 枚举类
12 * 7 *
@@ -14,16 +9,93 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.S @@ -14,16 +9,93 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.S
14 */ 9 */
15 public interface RedisKeyConstants { 10 public interface RedisKeyConstants {
16 11
17 - RedisKeyDefine CAPTCHA_CODE = new RedisKeyDefine("验证码的缓存",  
18 - "captcha_code:%s", // 参数为 uuid  
19 - STRING, String.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); 12 + /**
  13 + * 指定部门的所有子部门编号数组的缓存
  14 + * <p>
  15 + * KEY 格式:dept_children_ids:{id}
  16 + * VALUE 数据类型:String 子部门编号集合
  17 + */
  18 + String DEPT_CHILDREN_ID_LIST = "dept_children_ids";
  19 +
  20 + /**
  21 + * 角色的缓存
  22 + * <p>
  23 + * KEY 格式:role:{id}
  24 + * VALUE 数据类型:String 角色信息
  25 + */
  26 + String ROLE = "role";
  27 +
  28 + /**
  29 + * 用户拥有的角色编号的缓存
  30 + * <p>
  31 + * KEY 格式:user_role_ids:{userId}
  32 + * VALUE 数据类型:String 角色编号集合
  33 + */
  34 + String USER_ROLE_ID_LIST = "user_role_ids";
  35 +
  36 + /**
  37 + * 拥有指定菜单的角色编号的缓存
  38 + * <p>
  39 + * KEY 格式:user_role_ids:{menuId}
  40 + * VALUE 数据类型:String 角色编号集合
  41 + */
  42 + String MENU_ROLE_ID_LIST = "menu_role_ids";
  43 +
  44 + /**
  45 + * 拥有权限对应的菜单编号数组的缓存
  46 + * <p>
  47 + * KEY 格式:permission_menu_ids:{permission}
  48 + * VALUE 数据类型:String 菜单编号数组
  49 + */
  50 + String PERMISSION_MENU_ID_LIST = "permission_menu_ids";
  51 +
  52 + /**
  53 + * OAuth2 客户端的缓存
  54 + * <p>
  55 + * KEY 格式:user:{id}
  56 + * VALUE 数据类型:String 客户端信息
  57 + */
  58 + String OAUTH_CLIENT = "oauth_client";
  59 +
  60 + /**
  61 + * 访问令牌的缓存
  62 + * <p>
  63 + * KEY 格式:oauth2_access_token:{token}
  64 + * VALUE 数据类型:String 访问令牌信息 {@link OAuth2AccessTokenDO}
  65 + * <p>
  66 + * 由于动态过期时间,使用 RedisTemplate 操作
  67 + */
  68 + String OAUTH2_ACCESS_TOKEN = "oauth2_access_token:%s";
  69 +
  70 + /**
  71 + * 站内信模版的缓存
  72 + * <p>
  73 + * KEY 格式:notify_template:{code}
  74 + * VALUE 数据格式:String 模版信息
  75 + */
  76 + String NOTIFY_TEMPLATE = "notify_template";
20 77
21 - RedisKeyDefine OAUTH2_ACCESS_TOKEN = new RedisKeyDefine("访问令牌的缓存",  
22 - "oauth2_access_token:%s", // 参数为访问令牌 token  
23 - STRING, OAuth2AccessTokenDO.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); 78 + /**
  79 + * 邮件账号的缓存
  80 + * <p>
  81 + * KEY 格式:sms_template:{id}
  82 + * VALUE 数据格式:String 账号信息
  83 + */
  84 + String MAIL_ACCOUNT = "mail_account";
24 85
25 - RedisKeyDefine SOCIAL_AUTH_STATE = new RedisKeyDefine("社交登陆的 state", // 注意,它是被 JustAuth 的 justauth.type.prefix 使用到  
26 - "social_auth_state:%s", // 参数为 state  
27 - STRING, String.class, Duration.ofHours(24)); // 值为 state 86 + /**
  87 + * 邮件模版的缓存
  88 + * <p>
  89 + * KEY 格式:mail_template:{code}
  90 + * VALUE 数据格式:String 模版信息
  91 + */
  92 + String MAIL_TEMPLATE = "mail_template";
28 93
  94 + /**
  95 + * 短信模版的缓存
  96 + * <p>
  97 + * KEY 格式:sms_template:{id}
  98 + * VALUE 数据格式:String 模版信息
  99 + */
  100 + String SMS_TEMPLATE = "sms_template";
29 } 101 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/common/CaptchaRedisDAO.java deleted
1 -package cn.iocoder.yudao.module.system.dal.redis.common;  
2 -  
3 -import org.springframework.data.redis.core.StringRedisTemplate;  
4 -import org.springframework.stereotype.Repository;  
5 -  
6 -import javax.annotation.Resource;  
7 -import java.time.Duration;  
8 -  
9 -import static cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants.CAPTCHA_CODE;  
10 -  
11 -/**  
12 - * 验证码的 Redis DAO  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Repository  
17 -public class CaptchaRedisDAO {  
18 -  
19 - @Resource  
20 - private StringRedisTemplate stringRedisTemplate;  
21 -  
22 - public String get(String uuid) {  
23 - String redisKey = formatKey(uuid);  
24 - return stringRedisTemplate.opsForValue().get(redisKey);  
25 - }  
26 -  
27 - public void set(String uuid, String code, Duration timeout) {  
28 - String redisKey = formatKey(uuid);  
29 - stringRedisTemplate.opsForValue().set(redisKey, code, timeout);  
30 - }  
31 -  
32 - public void delete(String uuid) {  
33 - String redisKey = formatKey(uuid);  
34 - stringRedisTemplate.delete(redisKey);  
35 - }  
36 -  
37 - private static String formatKey(String uuid) {  
38 - return String.format(CAPTCHA_CODE.getKeyTemplate(), uuid);  
39 - }  
40 -  
41 -}  
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 { @@ -53,7 +53,7 @@ public class OAuth2AccessTokenRedisDAO {
53 } 53 }
54 54
55 private static String formatKey(String accessToken) { 55 private static String formatKey(String accessToken) {
56 - return String.format(OAUTH2_ACCESS_TOKEN.getKeyTemplate(), accessToken); 56 + return String.format(OAUTH2_ACCESS_TOKEN, accessToken);
57 } 57 }
58 58
59 } 59 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/auth/OAuth2ClientRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.system.mq.consumer.auth;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
4 -import cn.iocoder.yudao.module.system.mq.message.auth.OAuth2ClientRefreshMessage;  
5 -import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService;  
6 -import lombok.extern.slf4j.Slf4j;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 针对 {@link OAuth2ClientRefreshMessage} 的消费者  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Component  
17 -@Slf4j  
18 -public class OAuth2ClientRefreshConsumer extends AbstractChannelMessageListener<OAuth2ClientRefreshMessage> {  
19 -  
20 - @Resource  
21 - private OAuth2ClientService oauth2ClientService;  
22 -  
23 - @Override  
24 - public void onMessage(OAuth2ClientRefreshMessage message) {  
25 - log.info("[onMessage][收到 OAuth2Client 刷新消息]");  
26 - oauth2ClientService.initLocalCache();  
27 - }  
28 -  
29 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/dept/DeptRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.system.mq.consumer.dept;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
4 -import cn.iocoder.yudao.module.system.mq.message.dept.DeptRefreshMessage;  
5 -import cn.iocoder.yudao.module.system.service.dept.DeptService;  
6 -import lombok.extern.slf4j.Slf4j;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 针对 {@link DeptRefreshMessage} 的消费者  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Component  
17 -@Slf4j  
18 -public class DeptRefreshConsumer extends AbstractChannelMessageListener<DeptRefreshMessage> {  
19 -  
20 - @Resource  
21 - private DeptService deptService;  
22 -  
23 - @Override  
24 - public void onMessage(DeptRefreshMessage message) {  
25 - log.info("[onMessage][收到 Dept 刷新消息]");  
26 - deptService.initLocalCache();  
27 - }  
28 -  
29 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailAccountRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.system.mq.consumer.mail;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
4 -import cn.iocoder.yudao.module.system.mq.message.mail.MailAccountRefreshMessage;  
5 -import cn.iocoder.yudao.module.system.mq.message.mail.MailTemplateRefreshMessage;  
6 -import cn.iocoder.yudao.module.system.service.mail.MailAccountService;  
7 -import cn.iocoder.yudao.module.system.service.mail.MailTemplateService;  
8 -import lombok.extern.slf4j.Slf4j;  
9 -import org.springframework.stereotype.Component;  
10 -  
11 -import javax.annotation.Resource;  
12 -  
13 -/**  
14 - * 针对 {@link MailAccountRefreshMessage} 的消费者  
15 - *  
16 - * @author wangjingyi  
17 - */  
18 -@Component  
19 -@Slf4j  
20 -public class MailAccountRefreshConsumer extends AbstractChannelMessageListener<MailAccountRefreshMessage> {  
21 -  
22 - @Resource  
23 - private MailAccountService mailAccountService;  
24 -  
25 - @Override  
26 - public void onMessage(MailAccountRefreshMessage message) {  
27 - log.info("[onMessage][收到 Mail Account 刷新信息]");  
28 - mailAccountService.initLocalCache();  
29 - }  
30 -  
31 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailTemplateRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.system.mq.consumer.mail;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
4 -import cn.iocoder.yudao.module.system.mq.message.mail.MailTemplateRefreshMessage;  
5 -import cn.iocoder.yudao.module.system.service.mail.MailTemplateService;  
6 -import lombok.extern.slf4j.Slf4j;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 针对 {@link MailTemplateRefreshMessage} 的消费者  
13 - *  
14 - * @author wangjingyi  
15 - */  
16 -@Component  
17 -@Slf4j  
18 -public class MailTemplateRefreshConsumer extends AbstractChannelMessageListener<MailTemplateRefreshMessage> {  
19 -  
20 - @Resource  
21 - private MailTemplateService mailTemplateService;  
22 -  
23 - @Override  
24 - public void onMessage(MailTemplateRefreshMessage message) {  
25 - log.info("[onMessage][收到 Mail Template 刷新信息]");  
26 - mailTemplateService.initLocalCache();  
27 - }  
28 -  
29 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/notify/NotifyTemplateRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.system.mq.consumer.notify;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
4 -import cn.iocoder.yudao.module.system.mq.message.notify.NotifyTemplateRefreshMessage;  
5 -import cn.iocoder.yudao.module.system.service.notify.NotifyTemplateService;  
6 -import lombok.extern.slf4j.Slf4j;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 针对 {@link NotifyTemplateRefreshMessage} 的消费者  
13 - *  
14 - * @author xrcoder  
15 - */  
16 -@Component  
17 -@Slf4j  
18 -public class NotifyTemplateRefreshConsumer extends AbstractChannelMessageListener<NotifyTemplateRefreshMessage> {  
19 -  
20 - @Resource  
21 - private NotifyTemplateService notifyTemplateService;  
22 -  
23 - @Override  
24 - public void onMessage(NotifyTemplateRefreshMessage message) {  
25 - log.info("[onMessage][收到 NotifyTemplate 刷新消息]");  
26 - notifyTemplateService.initLocalCache();  
27 - }  
28 -  
29 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/permission/MenuRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.system.mq.consumer.permission;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
4 -import cn.iocoder.yudao.module.system.mq.message.permission.MenuRefreshMessage;  
5 -import cn.iocoder.yudao.module.system.service.permission.MenuService;  
6 -import lombok.extern.slf4j.Slf4j;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 针对 {@link MenuRefreshMessage} 的消费者  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Component  
17 -@Slf4j  
18 -public class MenuRefreshConsumer extends AbstractChannelMessageListener<MenuRefreshMessage> {  
19 -  
20 - @Resource  
21 - private MenuService menuService;  
22 -  
23 - @Override  
24 - public void onMessage(MenuRefreshMessage message) {  
25 - log.info("[onMessage][收到 Menu 刷新消息]");  
26 - menuService.initLocalCache();  
27 - }  
28 -  
29 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/permission/RoleMenuRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.system.mq.consumer.permission;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
4 -import cn.iocoder.yudao.module.system.mq.message.permission.RoleMenuRefreshMessage;  
5 -import cn.iocoder.yudao.module.system.service.permission.PermissionService;  
6 -import lombok.extern.slf4j.Slf4j;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 针对 {@link RoleMenuRefreshMessage} 的消费者  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Component  
17 -@Slf4j  
18 -public class RoleMenuRefreshConsumer extends AbstractChannelMessageListener<RoleMenuRefreshMessage> {  
19 -  
20 - @Resource  
21 - private PermissionService permissionService;  
22 -  
23 - @Override  
24 - public void onMessage(RoleMenuRefreshMessage message) {  
25 - log.info("[onMessage][收到 Role 与 Menu 的关联刷新消息]");  
26 - permissionService.initLocalCache();  
27 - }  
28 -  
29 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/permission/RoleRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.system.mq.consumer.permission;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
4 -import cn.iocoder.yudao.module.system.mq.message.permission.RoleRefreshMessage;  
5 -import cn.iocoder.yudao.module.system.service.permission.RoleService;  
6 -import lombok.extern.slf4j.Slf4j;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 针对 {@link RoleRefreshMessage} 的消费者  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Component  
17 -@Slf4j  
18 -public class RoleRefreshConsumer extends AbstractChannelMessageListener<RoleRefreshMessage> {  
19 -  
20 - @Resource  
21 - private RoleService roleService;  
22 -  
23 - @Override  
24 - public void onMessage(RoleRefreshMessage message) {  
25 - log.info("[onMessage][收到 Role 刷新消息]");  
26 - roleService.initLocalCache();  
27 - }  
28 -  
29 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/permission/UserRoleRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.system.mq.consumer.permission;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
4 -import cn.iocoder.yudao.module.system.mq.message.permission.UserRoleRefreshMessage;  
5 -import cn.iocoder.yudao.module.system.service.permission.PermissionService;  
6 -import lombok.extern.slf4j.Slf4j;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 针对 {@link UserRoleRefreshMessage} 的消费者  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Component  
17 -@Slf4j  
18 -public class UserRoleRefreshConsumer extends AbstractChannelMessageListener<UserRoleRefreshMessage> {  
19 -  
20 - @Resource  
21 - private PermissionService permissionService;  
22 -  
23 - @Override  
24 - public void onMessage(UserRoleRefreshMessage message) {  
25 - log.info("[onMessage][收到 User 与 Role 的关联刷新消息]");  
26 - permissionService.initLocalCache();  
27 - }  
28 -  
29 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sensitiveword/SensitiveWordRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.system.mq.consumer.sensitiveword;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
4 -import cn.iocoder.yudao.module.system.mq.message.sensitiveword.SensitiveWordRefreshMessage;  
5 -import cn.iocoder.yudao.module.system.service.sensitiveword.SensitiveWordService;  
6 -import lombok.extern.slf4j.Slf4j;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 针对 {@link SensitiveWordRefreshMessage} 的消费者  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Component  
17 -@Slf4j  
18 -public class SensitiveWordRefreshConsumer extends AbstractChannelMessageListener<SensitiveWordRefreshMessage> {  
19 -  
20 - @Resource  
21 - private SensitiveWordService sensitiveWordService;  
22 -  
23 - @Override  
24 - public void onMessage(SensitiveWordRefreshMessage message) {  
25 - log.info("[onMessage][收到 SensitiveWord 刷新消息]");  
26 - sensitiveWordService.initLocalCache();  
27 - }  
28 -  
29 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsChannelRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.system.mq.consumer.sms;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
4 -import cn.iocoder.yudao.module.system.mq.message.sms.SmsChannelRefreshMessage;  
5 -import cn.iocoder.yudao.module.system.service.sms.SmsChannelService;  
6 -import lombok.extern.slf4j.Slf4j;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 针对 {@link SmsChannelRefreshMessage} 的消费者  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Component  
17 -@Slf4j  
18 -public class SmsChannelRefreshConsumer extends AbstractChannelMessageListener<SmsChannelRefreshMessage> {  
19 -  
20 - @Resource  
21 - private SmsChannelService smsChannelService;  
22 -  
23 - @Override  
24 - public void onMessage(SmsChannelRefreshMessage message) {  
25 - log.info("[onMessage][收到 SmsChannel 刷新消息]");  
26 - smsChannelService.initLocalCache();  
27 - }  
28 -  
29 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsTemplateRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.system.mq.consumer.sms;  
2 -  
3 -import cn.iocoder.yudao.module.system.mq.message.sms.SmsTemplateRefreshMessage;  
4 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
5 -import cn.iocoder.yudao.module.system.service.sms.SmsTemplateService;  
6 -import lombok.extern.slf4j.Slf4j;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 针对 {@link SmsTemplateRefreshMessage} 的消费者  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Component  
17 -@Slf4j  
18 -public class SmsTemplateRefreshConsumer extends AbstractChannelMessageListener<SmsTemplateRefreshMessage> {  
19 -  
20 - @Resource  
21 - private SmsTemplateService smsTemplateService;  
22 -  
23 - @Override  
24 - public void onMessage(SmsTemplateRefreshMessage message) {  
25 - log.info("[onMessage][收到 SmsTemplate 刷新消息]");  
26 - smsTemplateService.initLocalCache();  
27 - }  
28 -  
29 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/auth/OAuth2ClientRefreshMessage.java deleted
1 -package cn.iocoder.yudao.module.system.mq.message.auth;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;  
4 -import lombok.Data;  
5 -import lombok.EqualsAndHashCode;  
6 -  
7 -/**  
8 - * OAuth 2.0 客户端的数据刷新 Message  
9 - *  
10 - * @author 芋道源码  
11 - */  
12 -@Data  
13 -@EqualsAndHashCode(callSuper = true)  
14 -public class OAuth2ClientRefreshMessage extends AbstractChannelMessage {  
15 -  
16 - @Override  
17 - public String getChannel() {  
18 - return "system.oauth2-client.refresh";  
19 - }  
20 -  
21 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/dept/DeptRefreshMessage.java deleted
1 -package cn.iocoder.yudao.module.system.mq.message.dept;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;  
4 -import lombok.Data;  
5 -import lombok.EqualsAndHashCode;  
6 -  
7 -/**  
8 - * 部门数据刷新 Message  
9 - *  
10 - * @author 芋道源码  
11 - */  
12 -@Data  
13 -@EqualsAndHashCode(callSuper = true)  
14 -public class DeptRefreshMessage extends AbstractChannelMessage {  
15 -  
16 - @Override  
17 - public String getChannel() {  
18 - return "system.dept.refresh";  
19 - }  
20 -  
21 -}