Commit bf3e848c171c6e63c94f09cbb2df2fee01c2b9b3
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 | - | 105 | + |
| 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 |
pom.xml
| @@ -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<T> extends MPJBaseMapper<T> { | @@ -46,18 +44,6 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> { | ||
| 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<T> extends MPJBaseMapper<T> { | @@ -117,11 +103,6 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> { | ||
| 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<T> extends MPJBaseMapper<T> { | @@ -130,13 +111,8 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> { | ||
| 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<FileConfigDO> { | @@ -18,4 +21,7 @@ public interface FileConfigMapper extends BaseMapperX<FileConfigDO> { | ||
| 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
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
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
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<TradeCartDO> { | @@ -19,10 +19,10 @@ public interface TradeCartMapper extends BaseMapperX<TradeCartDO> { | ||
| 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<MpAccountDO> { | @@ -22,4 +25,7 @@ public interface MpAccountMapper extends BaseMapperX<MpAccountDO> { | ||
| 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
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java
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<DeptDO> { | @@ -25,4 +26,8 @@ public interface DeptMapper extends BaseMapperX<DeptDO> { | ||
| 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<MenuDO> { | @@ -25,4 +25,7 @@ public interface MenuMapper extends BaseMapperX<MenuDO> { | ||
| 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<SensitiveWordDO> { | @@ -40,4 +42,7 @@ public interface SensitiveWordMapper extends BaseMapperX<SensitiveWordDO> { | ||
| 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<SmsChannelDO> { | @@ -18,4 +21,7 @@ public interface SmsChannelMapper extends BaseMapperX<SmsChannelDO> { | ||
| 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 | -} |