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
Docker-HOWTO.md
| 1 | 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 | 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 | 13 | ├── yudao-server |
| 13 | -│ ├── Dockerfile | |
| 14 | -│ └── nginx.conf | |
| 14 | +│ └── Dockerfile | |
| 15 | 15 | └── yudao-ui-admin |
| 16 | 16 | ├── .dockerignore |
| 17 | - └── Dockerfile | |
| 17 | + ├── Dockerfile | |
| 18 | + └── nginx.conf <-- 提供基础配置,gzip压缩、api转发 | |
| 18 | 19 | ``` |
| 19 | 20 | |
| 20 | -## Maven build (Optional) | |
| 21 | +## 构建 jar 包 | |
| 21 | 22 | |
| 22 | 23 | ```shell |
| 23 | 24 | # 创建maven缓存volume |
| ... | ... | @@ -30,29 +31,19 @@ docker run -it --rm --name yudao-maven \ |
| 30 | 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 | 36 | ```shell |
| 42 | 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 | 49 | - redis: port: 6379 | ... | ... |
README.md
docker-compose.yml
| 1 | -version: "3.8" | |
| 1 | +version: "3.4" | |
| 2 | 2 | |
| 3 | 3 | name: yudao-system |
| 4 | 4 | |
| ... | ... | @@ -9,25 +9,22 @@ services: |
| 9 | 9 | restart: unless-stopped |
| 10 | 10 | tty: true |
| 11 | 11 | ports: |
| 12 | - - 13306:3306 | |
| 12 | + - "3306:3306" | |
| 13 | 13 | environment: |
| 14 | 14 | MYSQL_DATABASE: ${MYSQL_DATABASE:-ruoyi-vue-pro} |
| 15 | 15 | MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-123456} |
| 16 | 16 | volumes: |
| 17 | 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 | 20 | redis: |
| 22 | 21 | container_name: yudao-redis |
| 23 | 22 | image: redis:6-alpine |
| 24 | 23 | restart: unless-stopped |
| 25 | 24 | ports: |
| 26 | - - 16379:6379 | |
| 25 | + - "6379:6379" | |
| 27 | 26 | volumes: |
| 28 | 27 | - redis:/data |
| 29 | - networks: | |
| 30 | - - yudao-network | |
| 31 | 28 | |
| 32 | 29 | server: |
| 33 | 30 | container_name: yudao-server |
| ... | ... | @@ -36,7 +33,7 @@ services: |
| 36 | 33 | image: yudao-server |
| 37 | 34 | restart: unless-stopped |
| 38 | 35 | ports: |
| 39 | - - 48080:48080 | |
| 36 | + - "48080:48080" | |
| 40 | 37 | environment: |
| 41 | 38 | # https://github.com/polovyivan/docker-pass-configs-to-container |
| 42 | 39 | SPRING_PROFILES_ACTIVE: local |
| ... | ... | @@ -54,8 +51,6 @@ services: |
| 54 | 51 | --spring.datasource.dynamic.datasource.slave.username=${SLAVE_DATASOURCE_USERNAME:-root} |
| 55 | 52 | --spring.datasource.dynamic.datasource.slave.password=${SLAVE_DATASOURCE_PASSWORD:-123456} |
| 56 | 53 | --spring.redis.host=${REDIS_HOST:-yudao-redis} |
| 57 | - networks: | |
| 58 | - - yudao-network | |
| 59 | 54 | depends_on: |
| 60 | 55 | - mysql |
| 61 | 56 | - redis |
| ... | ... | @@ -78,16 +73,10 @@ services: |
| 78 | 73 | image: yudao-admin |
| 79 | 74 | restart: unless-stopped |
| 80 | 75 | ports: |
| 81 | - - 8080:80 | |
| 82 | - networks: | |
| 83 | - - yudao-network | |
| 76 | + - "8080:80" | |
| 84 | 77 | depends_on: |
| 85 | 78 | - server |
| 86 | 79 | |
| 87 | -networks: | |
| 88 | - yudao-network: | |
| 89 | - driver: bridge | |
| 90 | - | |
| 91 | 80 | volumes: |
| 92 | 81 | mysql: |
| 93 | 82 | driver: local | ... | ... |
pom.xml
| ... | ... | @@ -30,7 +30,7 @@ |
| 30 | 30 | <url>https://github.com/YunaiV/ruoyi-vue-pro</url> |
| 31 | 31 | |
| 32 | 32 | <properties> |
| 33 | - <revision>1.7.3-snapshot</revision> | |
| 33 | + <revision>1.8.0-snapshot</revision> | |
| 34 | 34 | <!-- Maven 相关 --> |
| 35 | 35 | <java.version>1.8</java.version> |
| 36 | 36 | <maven.compiler.source>${java.version}</maven.compiler.source> | ... | ... |
yudao-dependencies/pom.xml
| ... | ... | @@ -14,7 +14,7 @@ |
| 14 | 14 | <url>https://github.com/YunaiV/ruoyi-vue-pro</url> |
| 15 | 15 | |
| 16 | 16 | <properties> |
| 17 | - <revision>1.7.3-snapshot</revision> | |
| 17 | + <revision>1.8.0-snapshot</revision> | |
| 18 | 18 | <!-- 统一依赖管理 --> |
| 19 | 19 | <spring.boot.version>2.7.13</spring.boot.version> |
| 20 | 20 | <!-- Web 相关 --> |
| ... | ... | @@ -71,7 +71,7 @@ |
| 71 | 71 | <justauth.version>1.0.1</justauth.version> |
| 72 | 72 | <jimureport.version>1.5.8</jimureport.version> |
| 73 | 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 | 75 | </properties> |
| 76 | 76 | |
| 77 | 77 | <dependencyManagement> |
| ... | ... | @@ -216,10 +216,9 @@ |
| 216 | 216 | <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <!-- 多数据源 --> |
| 217 | 217 | <version>${dynamic-datasource.version}</version> |
| 218 | 218 | </dependency> |
| 219 | - | |
| 220 | 219 | <dependency> |
| 221 | 220 | <groupId>com.github.yulichang</groupId> |
| 222 | - <artifactId>mybatis-plus-join-boot-starter</artifactId> | |
| 221 | + <artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 --> | |
| 223 | 222 | <version>${mybatis-plus-join-boot-starter.version}</version> |
| 224 | 223 | </dependency> |
| 225 | 224 | |
| ... | ... | @@ -601,8 +600,23 @@ |
| 601 | 600 | |
| 602 | 601 | <dependency> |
| 603 | 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 | 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 | 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 | 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 | 168 | if (CollUtil.isEmpty(from)) { |
| 169 | 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 | 4 | import cn.hutool.core.util.ReflectUtil; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 6 | 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 | 7 | import cn.iocoder.yudao.framework.security.core.LoginUser; |
| 10 | 8 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| 11 | 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 | 12 | import net.sf.jsqlparser.expression.Alias; |
| 13 | 13 | import net.sf.jsqlparser.expression.Expression; |
| 14 | 14 | import org.junit.jupiter.api.BeforeEach; |
| ... | ... | @@ -23,6 +23,7 @@ import static cn.iocoder.yudao.framework.datapermission.core.rule.dept.DeptDataP |
| 23 | 23 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
| 24 | 24 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; |
| 25 | 25 | import static org.junit.jupiter.api.Assertions.*; |
| 26 | +import static org.mockito.ArgumentMatchers.eq; | |
| 26 | 27 | import static org.mockito.ArgumentMatchers.same; |
| 27 | 28 | import static org.mockito.Mockito.mockStatic; |
| 28 | 29 | import static org.mockito.Mockito.when; |
| ... | ... | @@ -73,6 +74,8 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { |
| 73 | 74 | LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) |
| 74 | 75 | .setUserType(UserTypeEnum.ADMIN.getValue())); |
| 75 | 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 | 81 | NullPointerException exception = assertThrows(NullPointerException.class, | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml
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 | 34 | <!-- 三方云服务相关 --> |
| 35 | 35 | <dependency> |
| 36 | 36 | <groupId>com.github.binarywang</groupId> |
| 37 | -<!-- <artifactId>weixin-java-mp</artifactId>--> | |
| 38 | 37 | <artifactId>wx-java-mp-spring-boot-starter</artifactId> |
| 39 | - <version>4.5.0</version> | |
| 40 | 38 | </dependency> |
| 41 | 39 | <dependency> |
| 42 | 40 | <groupId>com.github.binarywang</groupId> |
| 43 | 41 | <artifactId>wx-java-miniapp-spring-boot-starter</artifactId> |
| 44 | - <version>4.5.0</version> | |
| 45 | 42 | </dependency> |
| 46 | - <!-- TODO 芋艿:清理 --> | |
| 47 | 43 | </dependencies> |
| 48 | 44 | |
| 49 | 45 | </project> | ... | ... |
yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/config/YudaoCaptchaConfiguration.java
| 1 | 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 | 3 | import cn.iocoder.yudao.framework.captcha.core.service.RedisCaptchaServiceImpl; |
| 6 | 4 | import com.xingyuv.captcha.properties.AjCaptchaProperties; |
| 7 | 5 | import com.xingyuv.captcha.service.CaptchaCacheService; |
| ... | ... | @@ -15,12 +13,6 @@ import javax.annotation.Resource; |
| 15 | 13 | @AutoConfiguration |
| 16 | 14 | public class YudaoCaptchaConfiguration { |
| 17 | 15 | |
| 18 | - static { | |
| 19 | - // 手动加载 Lock4jRedisKeyConstants 类,因为它不会被使用到 | |
| 20 | - // 如果不加载,会导致 Redis 监控,看到它的 Redis Key 枚举 | |
| 21 | - ClassUtil.loadClass(CaptchaRedisKeyConstants.class.getName()); | |
| 22 | - } | |
| 23 | - | |
| 24 | 16 | @Resource |
| 25 | 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 | 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 | 4 | * 验证码 Redis Key 枚举类 |
| 12 | 5 | * |
| ... | ... | @@ -14,12 +7,22 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.S |
| 14 | 7 | */ |
| 15 | 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 | 64 | |
| 65 | 65 | <dependency> |
| 66 | 66 | <groupId>com.github.yulichang</groupId> |
| 67 | - <artifactId>mybatis-plus-join-boot-starter</artifactId> | |
| 67 | + <artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 --> | |
| 68 | 68 | </dependency> |
| 69 | - | |
| 70 | 69 | </dependencies> |
| 71 | 70 | |
| 72 | 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 | 6 | import com.baomidou.mybatisplus.core.conditions.Wrapper; |
| 7 | 7 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| 8 | 8 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| 9 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |
| 9 | 10 | import com.baomidou.mybatisplus.core.metadata.IPage; |
| 10 | 11 | import com.baomidou.mybatisplus.core.toolkit.support.SFunction; |
| 11 | 12 | import com.baomidou.mybatisplus.extension.toolkit.Db; |
| 12 | -import com.github.yulichang.base.MPJBaseMapper; | |
| 13 | 13 | import org.apache.ibatis.annotations.Param; |
| 14 | 14 | |
| 15 | 15 | import java.util.Collection; |
| ... | ... | @@ -17,10 +17,8 @@ import java.util.List; |
| 17 | 17 | |
| 18 | 18 | /** |
| 19 | 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 | 23 | default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) { |
| 26 | 24 | // MyBatis Plus 查询 |
| ... | ... | @@ -46,18 +44,6 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> { |
| 46 | 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 | 47 | default Long selectCount() { |
| 62 | 48 | return selectCount(new QueryWrapper<T>()); |
| 63 | 49 | } |
| ... | ... | @@ -117,11 +103,6 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> { |
| 117 | 103 | update(update, new QueryWrapper<>()); |
| 118 | 104 | } |
| 119 | 105 | |
| 120 | - /** | |
| 121 | - * 根据ID 批量更新,适合大量数据更新 | |
| 122 | - * | |
| 123 | - * @param entities 实体们 | |
| 124 | - */ | |
| 125 | 106 | default void updateBatch(Collection<T> entities) { |
| 126 | 107 | Db.updateBatchById(entities); |
| 127 | 108 | } |
| ... | ... | @@ -130,13 +111,8 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> { |
| 130 | 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 | 1 | package cn.iocoder.yudao.framework.idempotent.core.redis; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine; | |
| 4 | 3 | import lombok.AllArgsConstructor; |
| 5 | 4 | import org.springframework.data.redis.core.StringRedisTemplate; |
| 6 | 5 | |
| 7 | 6 | import java.util.concurrent.TimeUnit; |
| 8 | 7 | |
| 9 | -import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING; | |
| 10 | - | |
| 11 | 8 | /** |
| 12 | 9 | * 幂等 Redis DAO |
| 13 | 10 | * |
| ... | ... | @@ -16,9 +13,14 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.S |
| 16 | 13 | @AllArgsConstructor |
| 17 | 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 | 25 | private final StringRedisTemplate redisTemplate; |
| 24 | 26 | |
| ... | ... | @@ -28,7 +30,7 @@ public class IdempotentRedisDAO { |
| 28 | 30 | } |
| 29 | 31 | |
| 30 | 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 | 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 | 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 | 5 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| 8 | 6 | import org.springframework.context.annotation.Bean; |
| 9 | 7 | |
| 10 | 8 | @AutoConfiguration(before = LockAutoConfiguration.class) |
| 11 | 9 | public class YudaoLock4jConfiguration { |
| 12 | 10 | |
| 13 | - static { | |
| 14 | - // 手动加载 Lock4jRedisKeyConstants 类,因为它不会被使用到 | |
| 15 | - // 如果不加载,会导致 Redis 监控,看到它的 Redis Key 枚举 | |
| 16 | - ClassUtil.loadClass(Lock4jRedisKeyConstants.class.getName()); | |
| 17 | - } | |
| 18 | - | |
| 19 | 11 | @Bean |
| 20 | 12 | public DefaultLockFailureStrategy lockFailureStrategy() { |
| 21 | 13 | return new DefaultLockFailureStrategy(); | ... | ... |
yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/core/Lock4jRedisKeyConstants.java
| 1 | 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 | 4 | * Lock4j Redis Key 枚举类 |
| 10 | 5 | * |
| ... | ... | @@ -12,8 +7,13 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.H |
| 12 | 7 | */ |
| 13 | 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
yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java
| 1 | 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 | 5 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| 4 | 6 | import org.springframework.boot.autoconfigure.cache.CacheProperties; |
| 5 | 7 | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| ... | ... | @@ -7,8 +9,15 @@ import org.springframework.cache.annotation.EnableCaching; |
| 7 | 9 | import org.springframework.context.annotation.Bean; |
| 8 | 10 | import org.springframework.context.annotation.Primary; |
| 9 | 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 | 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 | 23 | * Cache 配置类,基于 Redis 实现 |
| ... | ... | @@ -20,15 +29,19 @@ public class YudaoCacheAutoConfiguration { |
| 20 | 29 | |
| 21 | 30 | /** |
| 22 | 31 | * RedisCacheConfiguration Bean |
| 23 | - * | |
| 32 | + * <p> | |
| 24 | 33 | * 参考 org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration 的 createConfiguration 方法 |
| 25 | 34 | */ |
| 26 | 35 | @Bean |
| 27 | 36 | @Primary |
| 28 | 37 | public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) { |
| 29 | - // 设置使用 JSON 序列化方式 | |
| 30 | 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 | 46 | // 设置 CacheProperties.Redis 的属性 |
| 34 | 47 | CacheProperties.Redis redisProperties = cacheProperties.getRedis(); |
| ... | ... | @@ -47,4 +60,14 @@ public class YudaoCacheAutoConfiguration { |
| 47 | 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 | 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 | 6 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| 4 | 7 | import org.springframework.context.annotation.Bean; |
| 5 | 8 | import org.springframework.data.redis.connection.RedisConnectionFactory; |
| ... | ... | @@ -25,9 +28,17 @@ public class YudaoRedisAutoConfiguration { |
| 25 | 28 | template.setKeySerializer(RedisSerializer.string()); |
| 26 | 29 | template.setHashKeySerializer(RedisSerializer.string()); |
| 27 | 30 | // 使用 JSON 序列化方式(库是 Jackson ),序列化 VALUE 。 |
| 28 | - template.setValueSerializer(RedisSerializer.json()); | |
| 29 | - template.setHashValueSerializer(RedisSerializer.json()); | |
| 31 | + template.setValueSerializer(buildRedisSerializer()); | |
| 32 | + template.setHashValueSerializer(buildRedisSerializer()); | |
| 30 | 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 | 60 | /** |
| 61 | 61 | * 自定义的权限映射 Bean 们 |
| 62 | 62 | * |
| 63 | - * @see #configure(HttpSecurity) | |
| 63 | + * @see #filterChain(HttpSecurity) | |
| 64 | 64 | */ |
| 65 | 65 | @Resource |
| 66 | 66 | private List<AuthorizeRequestsCustomizer> authorizeRequestsCustomizers; |
| ... | ... | @@ -79,7 +79,7 @@ public class YudaoWebSecurityConfigurerAdapter { |
| 79 | 79 | |
| 80 | 80 | /** |
| 81 | 81 | * 配置 URL 的安全配置 |
| 82 | - * <p> | |
| 82 | + * | |
| 83 | 83 | * anyRequest | 匹配所有请求路径 |
| 84 | 84 | * access | SpringEl表达式结果为true时可以访问 |
| 85 | 85 | * anonymous | 匿名可以访问 |
| ... | ... | @@ -141,7 +141,6 @@ public class YudaoWebSecurityConfigurerAdapter { |
| 141 | 141 | |
| 142 | 142 | // 添加 Token Filter |
| 143 | 143 | httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); |
| 144 | - | |
| 145 | 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 | 40 | |
| 41 | 41 | // Redis 配置类 |
| 42 | 42 | RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer |
| 43 | +// RedisAutoConfiguration.class, // Spring Redis 自动配置类 | |
| 43 | 44 | YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类 |
| 44 | 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 | 52 | // 接口信息 |
| 53 | 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 | 57 | securitySchemas.keySet().forEach(key -> openAPI.addSecurityItem(new SecurityRequirement().addList(key))); |
| 57 | 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 | 47 | @Parameter(name = "processInstanceId", description = "流程实例的编号", required = true) |
| 48 | 48 | @PreAuthorize("@ss.hasPermission('bpm:task:query')") |
| 49 | 49 | public CommonResult<List<BpmTaskRespVO>> getTaskListByProcessInstanceId( |
| 50 | - @RequestParam("processInstanceId") String processInstanceId) { | |
| 50 | + @RequestParam("processInstanceId") String processInstanceId) { | |
| 51 | 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 | 73 | |
| 74 | 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 | 83 | BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, AdminUserRespDTO startUser); |
| 82 | 84 | |
| 83 | 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 | 15 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; |
| 16 | 16 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; |
| 17 | 17 | import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; |
| 18 | -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; | |
| 19 | 18 | import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants; |
| 19 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; | |
| 20 | 20 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; |
| 21 | 21 | import cn.iocoder.yudao.module.system.api.dept.DeptApi; |
| 22 | 22 | import cn.iocoder.yudao.module.system.api.dept.PostApi; |
| ... | ... | @@ -89,7 +89,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { |
| 89 | 89 | |
| 90 | 90 | @Override |
| 91 | 91 | public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId, |
| 92 | - String taskDefinitionKey) { | |
| 92 | + String taskDefinitionKey) { | |
| 93 | 93 | return taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, taskDefinitionKey); |
| 94 | 94 | } |
| 95 | 95 | |
| ... | ... | @@ -128,14 +128,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { |
| 128 | 128 | validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions()); |
| 129 | 129 | // 校验是否已经配置 |
| 130 | 130 | BpmTaskAssignRuleDO existRule = |
| 131 | - taskRuleMapper.selectListByModelIdAndTaskDefinitionKey(reqVO.getModelId(), reqVO.getTaskDefinitionKey()); | |
| 131 | + taskRuleMapper.selectListByModelIdAndTaskDefinitionKey(reqVO.getModelId(), reqVO.getTaskDefinitionKey()); | |
| 132 | 132 | if (existRule != null) { |
| 133 | 133 | throw exception(TASK_ASSIGN_RULE_EXISTS, reqVO.getModelId(), reqVO.getTaskDefinitionKey()); |
| 134 | 134 | } |
| 135 | 135 | |
| 136 | 136 | // 存储 |
| 137 | 137 | BpmTaskAssignRuleDO rule = BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO) |
| 138 | - .setProcessDefinitionId(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL); // 只有流程模型,才允许新建 | |
| 138 | + .setProcessDefinitionId(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL); // 只有流程模型,才允许新建 | |
| 139 | 139 | taskRuleMapper.insert(rule); |
| 140 | 140 | return rule.getId(); |
| 141 | 141 | } |
| ... | ... | @@ -169,14 +169,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { |
| 169 | 169 | |
| 170 | 170 | // 遍历,匹配对应的规则 |
| 171 | 171 | Map<String, BpmTaskAssignRuleRespVO> processInstanceRuleMap = |
| 172 | - CollectionUtils.convertMap(processInstanceRules, BpmTaskAssignRuleRespVO::getTaskDefinitionKey); | |
| 172 | + CollectionUtils.convertMap(processInstanceRules, BpmTaskAssignRuleRespVO::getTaskDefinitionKey); | |
| 173 | 173 | for (BpmTaskAssignRuleRespVO modelRule : modelRules) { |
| 174 | 174 | BpmTaskAssignRuleRespVO processInstanceRule = processInstanceRuleMap.get(modelRule.getTaskDefinitionKey()); |
| 175 | 175 | if (processInstanceRule == null) { |
| 176 | 176 | return false; |
| 177 | 177 | } |
| 178 | 178 | if (!ObjectUtil.equals(modelRule.getType(), processInstanceRule.getType()) || !ObjectUtil.equal( |
| 179 | - modelRule.getOptions(), processInstanceRule.getOptions())) { | |
| 179 | + modelRule.getOptions(), processInstanceRule.getOptions())) { | |
| 180 | 180 | return false; |
| 181 | 181 | } |
| 182 | 182 | } |
| ... | ... | @@ -192,7 +192,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { |
| 192 | 192 | // 开始复制 |
| 193 | 193 | List<BpmTaskAssignRuleDO> newRules = BpmTaskAssignRuleConvert.INSTANCE.convertList2(rules); |
| 194 | 194 | newRules.forEach(rule -> rule.setProcessDefinitionId(toProcessDefinitionId).setId(null).setCreateTime(null) |
| 195 | - .setUpdateTime(null)); | |
| 195 | + .setUpdateTime(null)); | |
| 196 | 196 | taskRuleMapper.insertBatch(newRules); |
| 197 | 197 | } |
| 198 | 198 | |
| ... | ... | @@ -215,7 +215,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { |
| 215 | 215 | if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.ROLE.getType())) { |
| 216 | 216 | roleApi.validRoleList(options); |
| 217 | 217 | } else if (ObjectUtils.equalsAny(type, BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), |
| 218 | - BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) { | |
| 218 | + BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) { | |
| 219 | 219 | deptApi.validateDeptList(options); |
| 220 | 220 | } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.POST.getType())) { |
| 221 | 221 | postApi.validPostList(options); |
| ... | ... | @@ -225,7 +225,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { |
| 225 | 225 | userGroupService.validUserGroups(options); |
| 226 | 226 | } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.SCRIPT.getType())) { |
| 227 | 227 | dictDataApi.validateDictDataList(DictTypeConstants.TASK_ASSIGN_SCRIPT, |
| 228 | - CollectionUtils.convertSet(options, String::valueOf)); | |
| 228 | + CollectionUtils.convertSet(options, String::valueOf)); | |
| 229 | 229 | } else { |
| 230 | 230 | throw new IllegalArgumentException(format("未知的规则类型({})", type)); |
| 231 | 231 | } |
| ... | ... | @@ -298,7 +298,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { |
| 298 | 298 | } |
| 299 | 299 | |
| 300 | 300 | private Set<Long> calculateTaskCandidateUsersByPost(BpmTaskAssignRuleDO rule) { |
| 301 | - List<AdminUserRespDTO> users = adminUserApi.getUsersByPostIds(rule.getOptions()); | |
| 301 | + List<AdminUserRespDTO> users = adminUserApi.getUserListByPostIds(rule.getOptions()); | |
| 302 | 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 | 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 | 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 | 40 | // mock 方法(startUser) |
| 41 | 41 | AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L)); |
| 42 | 42 | when(adminUserApi.getUser(eq(1L))).thenReturn(startUser); |
| 43 | + // mock 方法(getStartUserDept)没有部门 | |
| 44 | + when(deptApi.getDept(eq(10L))).thenReturn(null); | |
| 43 | 45 | |
| 44 | 46 | // 调用 |
| 45 | 47 | Set<Long> result = script.calculateTaskCandidateUsers(execution); |
| ... | ... | @@ -56,7 +58,9 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest { |
| 56 | 58 | when(adminUserApi.getUser(eq(1L))).thenReturn(startUser); |
| 57 | 59 | DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L) |
| 58 | 60 | .setLeaderUserId(20L)); |
| 61 | + // mock 方法(getDept) | |
| 59 | 62 | when(deptApi.getDept(eq(10L))).thenReturn(startUserDept); |
| 63 | + when(deptApi.getDept(eq(100L))).thenReturn(null); | |
| 60 | 64 | |
| 61 | 65 | // 调用 |
| 62 | 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 | 120 | // mock 方法 |
| 121 | 121 | List<AdminUserRespDTO> users = CollectionUtils.convertList(asSet(11L, 22L), |
| 122 | 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 | 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 | 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 | 30 | @Import(BpmUserGroupServiceImpl.class) |
| 31 | 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 | 2 | GET {{baseUrl}}/infra/redis/get-monitor-info |
| 3 | 3 | Authorization: Bearer {{token}} |
| 4 | 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 | 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 | 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 | 4 | import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO; |
| 11 | 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 | 6 | import io.swagger.v3.oas.annotations.Operation; |
| 7 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 15 | 8 | import org.springframework.data.redis.connection.RedisServerCommands; |
| 16 | -import org.springframework.data.redis.core.Cursor; | |
| 17 | 9 | import org.springframework.data.redis.core.RedisCallback; |
| 18 | -import org.springframework.data.redis.core.ScanOptions; | |
| 19 | 10 | import org.springframework.data.redis.core.StringRedisTemplate; |
| 20 | 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 | 16 | import javax.annotation.Resource; |
| 24 | -import java.util.*; | |
| 17 | +import java.util.Properties; | |
| 25 | 18 | |
| 26 | 19 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 27 | 20 | |
| ... | ... | @@ -47,66 +40,4 @@ public class RedisController { |
| 47 | 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 | 1 | package cn.iocoder.yudao.module.infra.convert.redis; |
| 2 | 2 | |
| 3 | 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 | 4 | import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO; |
| 7 | 5 | import org.mapstruct.Mapper; |
| 8 | 6 | import org.mapstruct.factory.Mappers; |
| 9 | 7 | |
| 10 | 8 | import java.util.ArrayList; |
| 11 | -import java.util.List; | |
| 12 | 9 | import java.util.Properties; |
| 13 | 10 | |
| 14 | 11 | @Mapper |
| ... | ... | @@ -29,6 +26,4 @@ public interface RedisConvert { |
| 29 | 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 | import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; |
| 7 | 7 | import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; |
| 8 | 8 | import org.apache.ibatis.annotations.Mapper; |
| 9 | +import org.apache.ibatis.annotations.Select; | |
| 10 | + | |
| 11 | +import java.time.LocalDateTime; | |
| 9 | 12 | |
| 10 | 13 | @Mapper |
| 11 | 14 | public interface FileConfigMapper extends BaseMapperX<FileConfigDO> { |
| ... | ... | @@ -18,4 +21,7 @@ public interface FileConfigMapper extends BaseMapperX<FileConfigDO> { |
| 18 | 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
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.infra.service.file; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 3 | 4 | import cn.hutool.core.io.resource.ResourceUtil; |
| 4 | 5 | import cn.hutool.core.util.IdUtil; |
| 5 | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 6 | 8 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 7 | 9 | import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; |
| 8 | 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 | 17 | import cn.iocoder.yudao.module.infra.convert.file.FileConfigConvert; |
| 16 | 18 | import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; |
| 17 | 19 | import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper; |
| 18 | -import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer; | |
| 19 | 20 | import lombok.Getter; |
| 20 | 21 | import lombok.extern.slf4j.Slf4j; |
| 22 | +import org.springframework.scheduling.annotation.Scheduled; | |
| 21 | 23 | import org.springframework.stereotype.Service; |
| 22 | 24 | import org.springframework.transaction.annotation.Transactional; |
| 23 | -import org.springframework.transaction.support.TransactionSynchronization; | |
| 24 | -import org.springframework.transaction.support.TransactionSynchronizationManager; | |
| 25 | 25 | import org.springframework.validation.annotation.Validated; |
| 26 | 26 | |
| 27 | 27 | import javax.annotation.PostConstruct; |
| 28 | 28 | import javax.annotation.Resource; |
| 29 | 29 | import javax.validation.Validator; |
| 30 | +import java.time.LocalDateTime; | |
| 30 | 31 | import java.util.List; |
| 31 | 32 | import java.util.Map; |
| 33 | +import java.util.concurrent.TimeUnit; | |
| 32 | 34 | |
| 33 | 35 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 34 | 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 | 48 | |
| 47 | 49 | @Resource |
| 48 | 50 | private FileClientFactory fileClientFactory; |
| 51 | + | |
| 52 | + /** | |
| 53 | + * 文件配置的缓存 | |
| 54 | + */ | |
| 55 | + @Getter | |
| 56 | + private List<FileConfigDO> fileConfigCache; | |
| 49 | 57 | /** |
| 50 | 58 | * Master FileClient 对象,有且仅有一个,即 {@link FileConfigDO#getMaster()} 对应的 |
| 51 | 59 | */ |
| ... | ... | @@ -56,12 +64,8 @@ public class FileConfigServiceImpl implements FileConfigService { |
| 56 | 64 | private FileConfigMapper fileConfigMapper; |
| 57 | 65 | |
| 58 | 66 | @Resource |
| 59 | - private FileConfigProducer fileConfigProducer; | |
| 60 | - | |
| 61 | - @Resource | |
| 62 | 67 | private Validator validator; |
| 63 | 68 | |
| 64 | - @Override | |
| 65 | 69 | @PostConstruct |
| 66 | 70 | public void initLocalCache() { |
| 67 | 71 | // 第一步:查询数据 |
| ... | ... | @@ -76,6 +80,27 @@ public class FileConfigServiceImpl implements FileConfigService { |
| 76 | 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 | 106 | @Override |
| ... | ... | @@ -85,9 +110,9 @@ public class FileConfigServiceImpl implements FileConfigService { |
| 85 | 110 | .setConfig(parseClientConfig(createReqVO.getStorage(), createReqVO.getConfig())) |
| 86 | 111 | .setMaster(false); // 默认非 master |
| 87 | 112 | fileConfigMapper.insert(fileConfig); |
| 88 | - // 发送刷新配置的消息 | |
| 89 | - fileConfigProducer.sendFileConfigRefreshMessage(); | |
| 90 | - // 返回 | |
| 113 | + | |
| 114 | + // 刷新缓存 | |
| 115 | + initLocalCache(); | |
| 91 | 116 | return fileConfig.getId(); |
| 92 | 117 | } |
| 93 | 118 | |
| ... | ... | @@ -99,8 +124,9 @@ public class FileConfigServiceImpl implements FileConfigService { |
| 99 | 124 | FileConfigDO updateObj = FileConfigConvert.INSTANCE.convert(updateReqVO) |
| 100 | 125 | .setConfig(parseClientConfig(config.getStorage(), updateReqVO.getConfig())); |
| 101 | 126 | fileConfigMapper.updateById(updateObj); |
| 102 | - // 发送刷新配置的消息 | |
| 103 | - fileConfigProducer.sendFileConfigRefreshMessage(); | |
| 127 | + | |
| 128 | + // 刷新缓存 | |
| 129 | + initLocalCache(); | |
| 104 | 130 | } |
| 105 | 131 | |
| 106 | 132 | @Override |
| ... | ... | @@ -112,15 +138,9 @@ public class FileConfigServiceImpl implements FileConfigService { |
| 112 | 138 | fileConfigMapper.updateBatch(new FileConfigDO().setMaster(false)); |
| 113 | 139 | // 更新 |
| 114 | 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 | 146 | private FileClientConfig parseClientConfig(Integer storage, Map<String, Object> config) { |
| ... | ... | @@ -143,8 +163,9 @@ public class FileConfigServiceImpl implements FileConfigService { |
| 143 | 163 | } |
| 144 | 164 | // 删除 |
| 145 | 165 | fileConfigMapper.deleteById(id); |
| 146 | - // 发送刷新配置的消息 | |
| 147 | - fileConfigProducer.sendFileConfigRefreshMessage(); | |
| 166 | + | |
| 167 | + // 刷新缓存 | |
| 168 | + initLocalCache(); | |
| 148 | 169 | } |
| 149 | 170 | |
| 150 | 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 | 16 | import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigUpdateReqVO; |
| 17 | 17 | import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; |
| 18 | 18 | import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper; |
| 19 | -import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer; | |
| 20 | 19 | import lombok.Data; |
| 21 | 20 | import org.junit.jupiter.api.Test; |
| 22 | 21 | import org.springframework.boot.test.mock.mockito.MockBean; |
| ... | ... | @@ -56,8 +55,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { |
| 56 | 55 | private FileConfigMapper fileConfigMapper; |
| 57 | 56 | |
| 58 | 57 | @MockBean |
| 59 | - private FileConfigProducer fileConfigProducer; | |
| 60 | - @MockBean | |
| 61 | 58 | private Validator validator; |
| 62 | 59 | @MockBean |
| 63 | 60 | private FileClientFactory fileClientFactory; |
| ... | ... | @@ -81,6 +78,10 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { |
| 81 | 78 | verify(fileClientFactory).createOrUpdateFileClient(eq(2L), |
| 82 | 79 | eq(configDO2.getStorage()), eq(configDO2.getConfig())); |
| 83 | 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 | 87 | @Test |
| ... | ... | @@ -101,8 +102,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { |
| 101 | 102 | assertFalse(fileConfig.getMaster()); |
| 102 | 103 | assertEquals("/yunai", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath()); |
| 103 | 104 | assertEquals("https://www.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain()); |
| 104 | - // verify 调用 | |
| 105 | - verify(fileConfigProducer).sendFileConfigRefreshMessage(); | |
| 106 | 105 | } |
| 107 | 106 | |
| 108 | 107 | @Test |
| ... | ... | @@ -126,8 +125,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { |
| 126 | 125 | assertPojoEquals(reqVO, fileConfig, "config"); |
| 127 | 126 | assertEquals("/yunai2", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath()); |
| 128 | 127 | assertEquals("https://doc.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain()); |
| 129 | - // verify 调用 | |
| 130 | - verify(fileConfigProducer).sendFileConfigRefreshMessage(); | |
| 131 | 128 | } |
| 132 | 129 | |
| 133 | 130 | @Test |
| ... | ... | @@ -152,8 +149,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { |
| 152 | 149 | // 断言数据 |
| 153 | 150 | assertTrue(fileConfigMapper.selectById(dbFileConfig.getId()).getMaster()); |
| 154 | 151 | assertFalse(fileConfigMapper.selectById(masterFileConfig.getId()).getMaster()); |
| 155 | - // verify 调用 | |
| 156 | - verify(fileConfigProducer).sendFileConfigRefreshMessage(); | |
| 157 | 152 | } |
| 158 | 153 | |
| 159 | 154 | @Test |
| ... | ... | @@ -174,8 +169,6 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { |
| 174 | 169 | fileConfigService.deleteFileConfig(id); |
| 175 | 170 | // 校验数据不存在了 |
| 176 | 171 | assertNull(fileConfigMapper.selectById(id)); |
| 177 | - // verify 调用 | |
| 178 | - verify(fileConfigProducer).sendFileConfigRefreshMessage(); | |
| 179 | 172 | } |
| 180 | 173 | |
| 181 | 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 | 19 | |
| 20 | 20 | default TradeCartDO selectByUserIdAndSkuId(Long userId, Long skuId, |
| 21 | 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 | 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 | import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO; |
| 7 | 7 | import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; |
| 8 | 8 | import org.apache.ibatis.annotations.Mapper; |
| 9 | +import org.apache.ibatis.annotations.Select; | |
| 10 | + | |
| 11 | +import java.time.LocalDateTime; | |
| 9 | 12 | |
| 10 | 13 | @Mapper |
| 11 | 14 | public interface MpAccountMapper extends BaseMapperX<MpAccountDO> { |
| ... | ... | @@ -22,4 +25,7 @@ public interface MpAccountMapper extends BaseMapperX<MpAccountDO> { |
| 22 | 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 | 1 | package cn.iocoder.yudao.module.mp.service.account; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 3 | 4 | import cn.hutool.core.util.ObjUtil; |
| 4 | 5 | import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; |
| 5 | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 7 | 7 | import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; |
| 8 | 8 | import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO; |
| 9 | 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 | 13 | import cn.iocoder.yudao.module.mp.dal.mysql.account.MpAccountMapper; |
| 14 | 14 | import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants; |
| 15 | 15 | import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; |
| 16 | -import cn.iocoder.yudao.module.mp.mq.producer.MpAccountProducer; | |
| 17 | 16 | import com.google.common.annotations.VisibleForTesting; |
| 18 | 17 | import lombok.Getter; |
| 19 | 18 | import lombok.extern.slf4j.Slf4j; |
| ... | ... | @@ -21,15 +20,20 @@ import me.chanjar.weixin.common.error.WxErrorException; |
| 21 | 20 | import me.chanjar.weixin.mp.api.WxMpService; |
| 22 | 21 | import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; |
| 23 | 22 | import org.springframework.context.annotation.Lazy; |
| 23 | +import org.springframework.scheduling.annotation.Scheduled; | |
| 24 | 24 | import org.springframework.stereotype.Service; |
| 25 | 25 | import org.springframework.validation.annotation.Validated; |
| 26 | 26 | |
| 27 | 27 | import javax.annotation.PostConstruct; |
| 28 | 28 | import javax.annotation.Resource; |
| 29 | +import java.time.LocalDateTime; | |
| 29 | 30 | import java.util.List; |
| 30 | 31 | import java.util.Map; |
| 32 | +import java.util.concurrent.TimeUnit; | |
| 31 | 33 | |
| 32 | 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 | 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 | 62 | @Lazy // 延迟加载,解决循环依赖的问题 |
| 59 | 63 | private MpServiceFactory mpServiceFactory; |
| 60 | 64 | |
| 61 | - @Resource | |
| 62 | - private MpAccountProducer mpAccountProducer; | |
| 63 | - | |
| 64 | 65 | @Override |
| 65 | 66 | @PostConstruct |
| 66 | 67 | public void initLocalCache() { |
| ... | ... | @@ -72,7 +73,30 @@ public class MpAccountServiceImpl implements MpAccountService { |
| 72 | 73 | |
| 73 | 74 | // 第二步:构建缓存。创建或更新支付 Client |
| 74 | 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 | 109 | MpAccountDO account = MpAccountConvert.INSTANCE.convert(createReqVO); |
| 86 | 110 | mpAccountMapper.insert(account); |
| 87 | 111 | |
| 88 | - // 发送刷新消息 | |
| 89 | - mpAccountProducer.sendAccountRefreshMessage(); | |
| 112 | + // 刷新缓存 | |
| 113 | + initLocalCache(); | |
| 90 | 114 | return account.getId(); |
| 91 | 115 | } |
| 92 | 116 | |
| ... | ... | @@ -101,8 +125,8 @@ public class MpAccountServiceImpl implements MpAccountService { |
| 101 | 125 | MpAccountDO updateObj = MpAccountConvert.INSTANCE.convert(updateReqVO); |
| 102 | 126 | mpAccountMapper.updateById(updateObj); |
| 103 | 127 | |
| 104 | - // 发送刷新消息 | |
| 105 | - mpAccountProducer.sendAccountRefreshMessage(); | |
| 128 | + // 刷新缓存 | |
| 129 | + initLocalCache(); | |
| 106 | 130 | } |
| 107 | 131 | |
| 108 | 132 | @Override |
| ... | ... | @@ -112,8 +136,8 @@ public class MpAccountServiceImpl implements MpAccountService { |
| 112 | 136 | // 删除 |
| 113 | 137 | mpAccountMapper.deleteById(id); |
| 114 | 138 | |
| 115 | - // 发送刷新消息 | |
| 116 | - mpAccountProducer.sendAccountRefreshMessage(); | |
| 139 | + // 刷新缓存 | |
| 140 | + initLocalCache(); | |
| 117 | 141 | } |
| 118 | 142 | |
| 119 | 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 | 61 | <artifactId>yudao-spring-boot-starter-job</artifactId> |
| 62 | 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 | 64 | <!-- Test 测试相关 --> |
| 71 | 65 | <dependency> |
| 72 | 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 | 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 | 4 | * 支付 Redis Key 枚举类 |
| 8 | 5 | * |
| ... | ... | @@ -10,9 +7,14 @@ import org.redisson.api.RLock; |
| 10 | 7 | */ |
| 11 | 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
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 | 15 | import cn.iocoder.yudao.module.pay.convert.channel.PayChannelConvert; |
| 16 | 16 | import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; |
| 17 | 17 | import cn.iocoder.yudao.module.pay.dal.mysql.channel.PayChannelMapper; |
| 18 | -import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants; | |
| 19 | 18 | import lombok.Getter; |
| 20 | 19 | import lombok.Setter; |
| 21 | 20 | import lombok.extern.slf4j.Slf4j; |
| ... | ... | @@ -112,7 +111,7 @@ public class PayChannelServiceImpl implements PayChannelService { |
| 112 | 111 | channelMapper.insert(channel); |
| 113 | 112 | |
| 114 | 113 | // 刷新缓存 |
| 115 | - refreshLocalCache(); | |
| 114 | + initLocalCache(); | |
| 116 | 115 | return channel.getId(); |
| 117 | 116 | } |
| 118 | 117 | |
| ... | ... | @@ -127,7 +126,7 @@ public class PayChannelServiceImpl implements PayChannelService { |
| 127 | 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 | 159 | channelMapper.deleteById(id); |
| 161 | 160 | |
| 162 | 161 | // 刷新缓存 |
| 163 | - refreshLocalCache(); | |
| 162 | + initLocalCache(); | |
| 164 | 163 | } |
| 165 | 164 | |
| 166 | 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 | 44 | * @param postIds 岗位数组 |
| 45 | 45 | * @return 用户数组 |
| 46 | 46 | */ |
| 47 | - List<AdminUserRespDTO> getUsersByPostIds(Collection<Long> postIds); | |
| 47 | + List<AdminUserRespDTO> getUserListByPostIds(Collection<Long> postIds); | |
| 48 | 48 | |
| 49 | 49 | /** |
| 50 | 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 | 21 | |
| 22 | 22 | @Override |
| 23 | 23 | public Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds) { |
| 24 | - return permissionService.getUserRoleIdListByRoleIds(roleIds); | |
| 24 | + return permissionService.getUserRoleIdListByRoleId(roleIds); | |
| 25 | 25 | } |
| 26 | 26 | |
| 27 | 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 | 40 | } |
| 41 | 41 | |
| 42 | 42 | @Override |
| 43 | - public List<AdminUserRespDTO> getUsersByPostIds(Collection<Long> postIds) { | |
| 43 | + public List<AdminUserRespDTO> getUserListByPostIds(Collection<Long> postIds) { | |
| 44 | 44 | List<AdminUserDO> users = userService.getUserListByPostIds(postIds); |
| 45 | 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
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 | 3 | import cn.hutool.core.util.StrUtil; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 6 | -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; | |
| 7 | 6 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 8 | 7 | import cn.iocoder.yudao.framework.security.config.SecurityProperties; |
| 9 | 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 | 11 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; |
| 13 | 12 | import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; |
| 14 | 13 | import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; |
| 15 | -import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum; | |
| 16 | 14 | import cn.iocoder.yudao.module.system.service.auth.AdminAuthService; |
| 15 | +import cn.iocoder.yudao.module.system.service.permission.MenuService; | |
| 17 | 16 | import cn.iocoder.yudao.module.system.service.permission.PermissionService; |
| 18 | 17 | import cn.iocoder.yudao.module.system.service.permission.RoleService; |
| 19 | 18 | import cn.iocoder.yudao.module.system.service.social.SocialUserService; |
| ... | ... | @@ -34,9 +33,9 @@ import java.util.List; |
| 34 | 33 | import java.util.Set; |
| 35 | 34 | |
| 36 | 35 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 36 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 37 | 37 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 38 | 38 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.obtainAuthorization; |
| 39 | -import static java.util.Collections.singleton; | |
| 40 | 39 | |
| 41 | 40 | @Tag(name = "管理后台 - 认证") |
| 42 | 41 | @RestController |
| ... | ... | @@ -52,6 +51,8 @@ public class AuthController { |
| 52 | 51 | @Resource |
| 53 | 52 | private RoleService roleService; |
| 54 | 53 | @Resource |
| 54 | + private MenuService menuService; | |
| 55 | + @Resource | |
| 55 | 56 | private PermissionService permissionService; |
| 56 | 57 | @Resource |
| 57 | 58 | private SocialUserService socialUserService; |
| ... | ... | @@ -91,33 +92,24 @@ public class AuthController { |
| 91 | 92 | @GetMapping("/get-permission-info") |
| 92 | 93 | @Operation(summary = "获取登录用户的权限信息") |
| 93 | 94 | public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() { |
| 94 | - // 获得用户信息 | |
| 95 | + // 1.1 获得用户信息 | |
| 95 | 96 | AdminUserDO user = userService.getUser(getLoginUserId()); |
| 96 | 97 | if (user == null) { |
| 97 | 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 | 141 | @Parameter(name = "redirectUri", description = "回调路径") |
| 150 | 142 | }) |
| 151 | 143 | public CommonResult<String> socialLogin(@RequestParam("type") Integer type, |
| 152 | - @RequestParam("redirectUri") String redirectUri) { | |
| 144 | + @RequestParam("redirectUri") String redirectUri) { | |
| 153 | 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 | 6 | import lombok.Data; |
| 7 | 7 | import lombok.NoArgsConstructor; |
| 8 | 8 | |
| 9 | +import java.util.List; | |
| 9 | 10 | import java.util.Set; |
| 10 | 11 | |
| 11 | -@Schema(description = "管理后台 - 登录用户的权限信息 Response VO,额外包括用户信息和角色列表") | |
| 12 | +@Schema(description = "管理后台 - 登录用户的权限信息 Response VO,额外包括用户信息和角色列表") | |
| 12 | 13 | @Data |
| 13 | 14 | @NoArgsConstructor |
| 14 | 15 | @AllArgsConstructor |
| ... | ... | @@ -24,6 +25,9 @@ public class AuthPermissionInfoRespVO { |
| 24 | 25 | @Schema(description = "操作权限数组", requiredMode = Schema.RequiredMode.REQUIRED) |
| 25 | 26 | private Set<String> permissions; |
| 26 | 27 | |
| 28 | + @Schema(description = "菜单树", required = true) | |
| 29 | + private List<MenuVO> menus; | |
| 30 | + | |
| 27 | 31 | @Schema(description = "用户信息 VO") |
| 28 | 32 | @Data |
| 29 | 33 | @NoArgsConstructor |
| ... | ... | @@ -37,9 +41,53 @@ public class AuthPermissionInfoRespVO { |
| 37 | 41 | @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码") |
| 38 | 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 | 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 | 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 | 17 | @Data |
| 18 | 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 | 37 | |
| 38 | 38 | @Operation(summary = "获得角色拥有的菜单编号") |
| 39 | 39 | @Parameter(name = "roleId", description = "角色编号", required = true) |
| 40 | - @GetMapping("/list-role-resources") | |
| 40 | + @GetMapping("/list-role-menus") | |
| 41 | 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 | 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
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 | 20 | // TODO 这里要多一个枚举校验 |
| 21 | 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 | 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 | 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 | 13 | @Data |
| 14 | 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 | 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 | 13 | @Data |
| 14 | 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 | 25 | @Length(min = 11, max = 11, message = "手机号长度必须 11 位") |
| 26 | 26 | private String mobile; |
| 27 | 27 | |
| 28 | - @Schema(description = "用户性别-参见 SexEnum 枚举类", example = "1") | |
| 28 | + @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1") | |
| 29 | 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 | 29 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 30 | 30 | private LocalDateTime[] createTime; |
| 31 | 31 | |
| 32 | - @Schema(description = "部门编号,同时筛选子部门", example = "1024") | |
| 32 | + @Schema(description = "部门编号,同时筛选子部门", example = "1024") | |
| 33 | 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 | 6 | import lombok.EqualsAndHashCode; |
| 7 | 7 | import lombok.NoArgsConstructor; |
| 8 | 8 | |
| 9 | -@Schema(description = "管理后台 - 用户分页时的信息 Response VO,相比用户基本信息来说,会多部门信息") | |
| 9 | +@Schema(description = "管理后台 - 用户分页时的信息 Response VO,相比用户基本信息来说,会多部门信息") | |
| 10 | 10 | @Data |
| 11 | 11 | @NoArgsConstructor |
| 12 | 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 | 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 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | 6 | import lombok.Data; |
| 5 | 7 | |
| ... | ... | @@ -13,9 +15,9 @@ public class UserUpdateStatusReqVO { |
| 13 | 15 | @NotNull(message = "角色编号不能为空") |
| 14 | 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 | 19 | @NotNull(message = "状态不能为空") |
| 18 | -// @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") | |
| 20 | + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") | |
| 19 | 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 | 8 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; |
| 9 | 9 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; |
| 10 | 10 | import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; |
| 11 | +import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum; | |
| 11 | 12 | import org.mapstruct.Mapper; |
| 12 | 13 | import org.mapstruct.factory.Mappers; |
| 13 | 14 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -27,13 +28,16 @@ public interface AuthConvert { |
| 27 | 28 | |
| 28 | 29 | default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) { |
| 29 | 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 | 45 | * @param menuList 菜单列表 |
| 42 | 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 | 52 | menuList.sort(Comparator.comparing(MenuDO::getSort)); |
| 53 | + | |
| 47 | 54 | // 构建菜单树 |
| 48 | 55 | // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。 |
| 49 | - Map<Long, AuthMenuRespVO> treeNodeMap = new LinkedHashMap<>(); | |
| 56 | + Map<Long, AuthPermissionInfoRespVO.MenuVO> treeNodeMap = new LinkedHashMap<>(); | |
| 50 | 57 | menuList.forEach(menu -> treeNodeMap.put(menu.getId(), AuthConvert.INSTANCE.convertTreeNode(menu))); |
| 51 | 58 | // 处理父子关系 |
| 52 | 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 | 62 | if (parentNode == null) { |
| 56 | 63 | LoggerFactory.getLogger(getClass()).error("[buildRouterTree][resource({}) 找不到父资源({})]", |
| 57 | - childNode.getId(), childNode.getParentId()); | |
| 64 | + childNode.getId(), childNode.getParentId()); | |
| 58 | 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 | import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; |
| 7 | 7 | import org.apache.ibatis.annotations.Mapper; |
| 8 | 8 | |
| 9 | +import java.util.Collection; | |
| 9 | 10 | import java.util.List; |
| 10 | 11 | |
| 11 | 12 | @Mapper |
| ... | ... | @@ -25,4 +26,8 @@ public interface DeptMapper extends BaseMapperX<DeptDO> { |
| 25 | 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 | 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 | 3 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 4 | 4 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO; |
| 5 | 5 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| 6 | -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |
| 7 | 6 | import org.apache.ibatis.annotations.Mapper; |
| 8 | -import org.springframework.stereotype.Repository; | |
| 9 | 7 | |
| 10 | 8 | import java.util.Collection; |
| 11 | 9 | import java.util.List; |
| ... | ... | @@ -13,14 +11,18 @@ import java.util.List; |
| 13 | 11 | @Mapper |
| 14 | 12 | public interface RoleMenuMapper extends BaseMapperX<RoleMenuDO> { |
| 15 | 13 | |
| 16 | - @Repository | |
| 17 | - class BatchInsertMapper extends ServiceImpl<RoleMenuMapper, RoleMenuDO> { | |
| 18 | - } | |
| 19 | - | |
| 20 | 14 | default List<RoleMenuDO> selectListByRoleId(Long roleId) { |
| 21 | 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 | 26 | default void deleteListByRoleIdAndMenuIds(Long roleId, Collection<Long> menuIds) { |
| 25 | 27 | delete(new LambdaQueryWrapper<RoleMenuDO>() |
| 26 | 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 | import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO; |
| 8 | 8 | import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO; |
| 9 | 9 | import org.apache.ibatis.annotations.Mapper; |
| 10 | +import org.apache.ibatis.annotations.Select; | |
| 10 | 11 | |
| 12 | +import java.time.LocalDateTime; | |
| 11 | 13 | import java.util.List; |
| 12 | 14 | |
| 13 | 15 | /** |
| ... | ... | @@ -40,4 +42,7 @@ public interface SensitiveWordMapper extends BaseMapperX<SensitiveWordDO> { |
| 40 | 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 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; |
| 7 | 7 | import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; |
| 8 | 8 | import org.apache.ibatis.annotations.Mapper; |
| 9 | +import org.apache.ibatis.annotations.Select; | |
| 10 | + | |
| 11 | +import java.time.LocalDateTime; | |
| 9 | 12 | |
| 10 | 13 | @Mapper |
| 11 | 14 | public interface SmsChannelMapper extends BaseMapperX<SmsChannelDO> { |
| ... | ... | @@ -18,4 +21,7 @@ public interface SmsChannelMapper extends BaseMapperX<SmsChannelDO> { |
| 18 | 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 | 1 | package cn.iocoder.yudao.module.system.dal.redis; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine; | |
| 4 | 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 | 6 | * System Redis Key 枚举类 |
| 12 | 7 | * |
| ... | ... | @@ -14,16 +9,93 @@ import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.S |
| 14 | 9 | */ |
| 15 | 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 | 53 | } |
| 54 | 54 | |
| 55 | 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 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailAccountRefreshMessage.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.message.mail; | |
| 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 wangjingyi | |
| 11 | - */ | |
| 12 | -@Data | |
| 13 | -@EqualsAndHashCode(callSuper = true) | |
| 14 | -public class MailAccountRefreshMessage extends AbstractChannelMessage { | |
| 15 | - | |
| 16 | - @Override | |
| 17 | - public String getChannel() { | |
| 18 | - return "system.mail-account.refresh"; | |
| 19 | - } | |
| 20 | - | |
| 21 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailTemplateRefreshMessage.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.message.mail; | |
| 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 wangjingyi | |
| 11 | - */ | |
| 12 | -@Data | |
| 13 | -@EqualsAndHashCode(callSuper = true) | |
| 14 | -public class MailTemplateRefreshMessage extends AbstractChannelMessage { | |
| 15 | - | |
| 16 | - @Override | |
| 17 | - public String getChannel() { | |
| 18 | - return "system.mail-template.refresh"; | |
| 19 | - } | |
| 20 | - | |
| 21 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/notify/NotifyTemplateRefreshMessage.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.message.notify; | |
| 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 xrcoder | |
| 11 | - */ | |
| 12 | -@Data | |
| 13 | -@EqualsAndHashCode(callSuper = true) | |
| 14 | -public class NotifyTemplateRefreshMessage extends AbstractChannelMessage { | |
| 15 | - | |
| 16 | - @Override | |
| 17 | - public String getChannel() { | |
| 18 | - return "system.notify-template.refresh"; | |
| 19 | - } | |
| 20 | - | |
| 21 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/permission/MenuRefreshMessage.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.message.permission; | |
| 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 MenuRefreshMessage extends AbstractChannelMessage { | |
| 15 | - | |
| 16 | - @Override | |
| 17 | - public String getChannel() { | |
| 18 | - return "system.menu.refresh"; | |
| 19 | - } | |
| 20 | - | |
| 21 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/permission/RoleMenuRefreshMessage.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.message.permission; | |
| 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 RoleMenuRefreshMessage extends AbstractChannelMessage { | |
| 15 | - | |
| 16 | - @Override | |
| 17 | - public String getChannel() { | |
| 18 | - return "system.role-menu.refresh"; | |
| 19 | - } | |
| 20 | - | |
| 21 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/permission/RoleRefreshMessage.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.message.permission; | |
| 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 RoleRefreshMessage extends AbstractChannelMessage { | |
| 15 | - | |
| 16 | - @Override | |
| 17 | - public String getChannel() { | |
| 18 | - return "system.role.refresh"; | |
| 19 | - } | |
| 20 | - | |
| 21 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/permission/UserRoleRefreshMessage.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.message.permission; | |
| 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 UserRoleRefreshMessage extends AbstractChannelMessage { | |
| 15 | - | |
| 16 | - @Override | |
| 17 | - public String getChannel() { | |
| 18 | - return "system.user-role.refresh"; | |
| 19 | - } | |
| 20 | - | |
| 21 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/sensitiveword/SensitiveWordRefreshMessage.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.message.sensitiveword; | |
| 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 | -@Data | |
| 11 | -@EqualsAndHashCode(callSuper = true) | |
| 12 | -public class SensitiveWordRefreshMessage extends AbstractChannelMessage { | |
| 13 | - | |
| 14 | - @Override | |
| 15 | - public String getChannel() { | |
| 16 | - return "system.sensitive-word.refresh"; | |
| 17 | - } | |
| 18 | - | |
| 19 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/sms/SmsChannelRefreshMessage.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.message.sms; | |
| 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 SmsChannelRefreshMessage extends AbstractChannelMessage { | |
| 15 | - | |
| 16 | - @Override | |
| 17 | - public String getChannel() { | |
| 18 | - return "system.sms-channel.refresh"; | |
| 19 | - } | |
| 20 | - | |
| 21 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/sms/SmsTemplateRefreshMessage.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.message.sms; | |
| 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 SmsTemplateRefreshMessage extends AbstractChannelMessage { | |
| 15 | - | |
| 16 | - @Override | |
| 17 | - public String getChannel() { | |
| 18 | - return "system.sms-template.refresh"; | |
| 19 | - } | |
| 20 | - | |
| 21 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/auth/OAuth2ClientProducer.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.producer.auth; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; | |
| 4 | -import cn.iocoder.yudao.module.system.mq.message.auth.OAuth2ClientRefreshMessage; | |
| 5 | -import org.springframework.stereotype.Component; | |
| 6 | - | |
| 7 | -import javax.annotation.Resource; | |
| 8 | - | |
| 9 | -/** | |
| 10 | - * OAuth 2.0 客户端相关消息的 Producer | |
| 11 | - */ | |
| 12 | -@Component | |
| 13 | -public class OAuth2ClientProducer { | |
| 14 | - | |
| 15 | - @Resource | |
| 16 | - private RedisMQTemplate redisMQTemplate; | |
| 17 | - | |
| 18 | - /** | |
| 19 | - * 发送 {@link OAuth2ClientRefreshMessage} 消息 | |
| 20 | - */ | |
| 21 | - public void sendOAuth2ClientRefreshMessage() { | |
| 22 | - OAuth2ClientRefreshMessage message = new OAuth2ClientRefreshMessage(); | |
| 23 | - redisMQTemplate.send(message); | |
| 24 | - } | |
| 25 | - | |
| 26 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/dept/DeptProducer.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.producer.dept; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.module.system.mq.message.dept.DeptRefreshMessage; | |
| 4 | -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; | |
| 5 | -import org.springframework.stereotype.Component; | |
| 6 | - | |
| 7 | -import javax.annotation.Resource; | |
| 8 | - | |
| 9 | -/** | |
| 10 | - * Dept 部门相关消息的 Producer | |
| 11 | - */ | |
| 12 | -@Component | |
| 13 | -public class DeptProducer { | |
| 14 | - | |
| 15 | - @Resource | |
| 16 | - private RedisMQTemplate redisMQTemplate; | |
| 17 | - | |
| 18 | - /** | |
| 19 | - * 发送 {@link DeptRefreshMessage} 消息 | |
| 20 | - */ | |
| 21 | - public void sendDeptRefreshMessage() { | |
| 22 | - DeptRefreshMessage message = new DeptRefreshMessage(); | |
| 23 | - redisMQTemplate.send(message); | |
| 24 | - } | |
| 25 | - | |
| 26 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java
| 1 | 1 | package cn.iocoder.yudao.module.system.mq.producer.mail; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; |
| 4 | -import cn.iocoder.yudao.module.system.mq.message.mail.MailAccountRefreshMessage; | |
| 5 | 4 | import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage; |
| 6 | -import cn.iocoder.yudao.module.system.mq.message.mail.MailTemplateRefreshMessage; | |
| 7 | 5 | import lombok.extern.slf4j.Slf4j; |
| 8 | 6 | import org.springframework.stereotype.Component; |
| 9 | 7 | |
| ... | ... | @@ -23,22 +21,6 @@ public class MailProducer { |
| 23 | 21 | private RedisMQTemplate redisMQTemplate; |
| 24 | 22 | |
| 25 | 23 | /** |
| 26 | - * 发送 {@link MailTemplateRefreshMessage} 消息 | |
| 27 | - */ | |
| 28 | - public void sendMailTemplateRefreshMessage() { | |
| 29 | - MailTemplateRefreshMessage message = new MailTemplateRefreshMessage(); | |
| 30 | - redisMQTemplate.send(message); | |
| 31 | - } | |
| 32 | - | |
| 33 | - /** | |
| 34 | - * 发送 {@link MailAccountRefreshMessage} 消息 | |
| 35 | - */ | |
| 36 | - public void sendMailAccountRefreshMessage() { | |
| 37 | - MailAccountRefreshMessage message = new MailAccountRefreshMessage(); | |
| 38 | - redisMQTemplate.send(message); | |
| 39 | - } | |
| 40 | - | |
| 41 | - /** | |
| 42 | 24 | * 发送 {@link MailSendMessage} 消息 |
| 43 | 25 | * |
| 44 | 26 | * @param sendLogId 发送日志编码 | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/notify/NotifyProducer.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.producer.notify; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; | |
| 4 | -import cn.iocoder.yudao.module.system.mq.message.notify.NotifyTemplateRefreshMessage; | |
| 5 | -import lombok.extern.slf4j.Slf4j; | |
| 6 | -import org.springframework.stereotype.Component; | |
| 7 | - | |
| 8 | -import javax.annotation.Resource; | |
| 9 | - | |
| 10 | -/** | |
| 11 | - * Notify 站内信相关消息的 Producer | |
| 12 | - * | |
| 13 | - * @author xrcoder | |
| 14 | - * @since 2022-08-06 | |
| 15 | - */ | |
| 16 | -@Slf4j | |
| 17 | -@Component | |
| 18 | -public class NotifyProducer { | |
| 19 | - | |
| 20 | - @Resource | |
| 21 | - private RedisMQTemplate redisMQTemplate; | |
| 22 | - | |
| 23 | - | |
| 24 | - /** | |
| 25 | - * 发送 {@link NotifyTemplateRefreshMessage} 消息 | |
| 26 | - */ | |
| 27 | - public void sendNotifyTemplateRefreshMessage() { | |
| 28 | - NotifyTemplateRefreshMessage message = new NotifyTemplateRefreshMessage(); | |
| 29 | - redisMQTemplate.send(message); | |
| 30 | - } | |
| 31 | - | |
| 32 | - | |
| 33 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/package-info.java deleted
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/permission/MenuProducer.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.producer.permission; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.module.system.mq.message.permission.MenuRefreshMessage; | |
| 4 | -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; | |
| 5 | -import org.springframework.stereotype.Component; | |
| 6 | - | |
| 7 | -import javax.annotation.Resource; | |
| 8 | - | |
| 9 | -/** | |
| 10 | - * Menu 菜单相关消息的 Producer | |
| 11 | - */ | |
| 12 | -@Component | |
| 13 | -public class MenuProducer { | |
| 14 | - | |
| 15 | - @Resource | |
| 16 | - private RedisMQTemplate redisMQTemplate; | |
| 17 | - | |
| 18 | - /** | |
| 19 | - * 发送 {@link MenuRefreshMessage} 消息 | |
| 20 | - */ | |
| 21 | - public void sendMenuRefreshMessage() { | |
| 22 | - MenuRefreshMessage message = new MenuRefreshMessage(); | |
| 23 | - redisMQTemplate.send(message); | |
| 24 | - } | |
| 25 | - | |
| 26 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/permission/PermissionProducer.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.producer.permission; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.module.system.mq.message.permission.RoleMenuRefreshMessage; | |
| 4 | -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; | |
| 5 | -import cn.iocoder.yudao.module.system.mq.message.permission.UserRoleRefreshMessage; | |
| 6 | -import org.springframework.stereotype.Component; | |
| 7 | - | |
| 8 | -import javax.annotation.Resource; | |
| 9 | - | |
| 10 | -/** | |
| 11 | - * Permission 权限相关消息的 Producer | |
| 12 | - */ | |
| 13 | -@Component | |
| 14 | -public class PermissionProducer { | |
| 15 | - | |
| 16 | - @Resource | |
| 17 | - private RedisMQTemplate redisMQTemplate; | |
| 18 | - | |
| 19 | - /** | |
| 20 | - * 发送 {@link RoleMenuRefreshMessage} 消息 | |
| 21 | - */ | |
| 22 | - public void sendRoleMenuRefreshMessage() { | |
| 23 | - RoleMenuRefreshMessage message = new RoleMenuRefreshMessage(); | |
| 24 | - redisMQTemplate.send(message); | |
| 25 | - } | |
| 26 | - | |
| 27 | - /** | |
| 28 | - * 发送 {@link UserRoleRefreshMessage} 消息 | |
| 29 | - */ | |
| 30 | - public void sendUserRoleRefreshMessage() { | |
| 31 | - UserRoleRefreshMessage message = new UserRoleRefreshMessage(); | |
| 32 | - redisMQTemplate.send(message); | |
| 33 | - } | |
| 34 | - | |
| 35 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/permission/RoleProducer.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.producer.permission; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.module.system.mq.message.permission.RoleRefreshMessage; | |
| 4 | -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; | |
| 5 | -import org.springframework.stereotype.Component; | |
| 6 | - | |
| 7 | -import javax.annotation.Resource; | |
| 8 | - | |
| 9 | -/** | |
| 10 | - * Role 角色相关消息的 Producer | |
| 11 | - * | |
| 12 | - * @author 芋道源码 | |
| 13 | - */ | |
| 14 | -@Component | |
| 15 | -public class RoleProducer { | |
| 16 | - | |
| 17 | - @Resource | |
| 18 | - private RedisMQTemplate redisMQTemplate; | |
| 19 | - | |
| 20 | - /** | |
| 21 | - * 发送 {@link RoleRefreshMessage} 消息 | |
| 22 | - */ | |
| 23 | - public void sendRoleRefreshMessage() { | |
| 24 | - RoleRefreshMessage message = new RoleRefreshMessage(); | |
| 25 | - redisMQTemplate.send(message); | |
| 26 | - } | |
| 27 | - | |
| 28 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/sensitiveword/SensitiveWordProducer.java deleted
| 1 | -package cn.iocoder.yudao.module.system.mq.producer.sensitiveword; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; | |
| 4 | -import cn.iocoder.yudao.module.system.mq.message.sensitiveword.SensitiveWordRefreshMessage; | |
| 5 | -import org.springframework.stereotype.Component; | |
| 6 | - | |
| 7 | -import javax.annotation.Resource; | |
| 8 | - | |
| 9 | -/** | |
| 10 | - * 敏感词相关的 Producer | |
| 11 | - */ | |
| 12 | -@Component | |
| 13 | -public class SensitiveWordProducer { | |
| 14 | - | |
| 15 | - @Resource | |
| 16 | - private RedisMQTemplate redisMQTemplate; | |
| 17 | - | |
| 18 | - /** | |
| 19 | - * 发送 {@link SensitiveWordRefreshMessage} 消息 | |
| 20 | - */ | |
| 21 | - public void sendSensitiveWordRefreshMessage() { | |
| 22 | - SensitiveWordRefreshMessage message = new SensitiveWordRefreshMessage(); | |
| 23 | - redisMQTemplate.send(message); | |
| 24 | - } | |
| 25 | - | |
| 26 | -} |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/sms/SmsProducer.java
| 1 | 1 | package cn.iocoder.yudao.module.system.mq.producer.sms; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.core.KeyValue; |
| 4 | -import cn.iocoder.yudao.module.system.mq.message.sms.SmsChannelRefreshMessage; | |
| 5 | -import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage; | |
| 6 | -import cn.iocoder.yudao.module.system.mq.message.sms.SmsTemplateRefreshMessage; | |
| 7 | 4 | import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; |
| 5 | +import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage; | |
| 8 | 6 | import lombok.extern.slf4j.Slf4j; |
| 9 | 7 | import org.springframework.stereotype.Component; |
| 10 | 8 | |
| ... | ... | @@ -15,7 +13,7 @@ import java.util.List; |
| 15 | 13 | * Sms 短信相关消息的 Producer |
| 16 | 14 | * |
| 17 | 15 | * @author zzf |
| 18 | - * @date 2021/3/9 16:35 | |
| 16 | + * @since 2021/3/9 16:35 | |
| 19 | 17 | */ |
| 20 | 18 | @Slf4j |
| 21 | 19 | @Component |
| ... | ... | @@ -25,22 +23,6 @@ public class SmsProducer { |
| 25 | 23 | private RedisMQTemplate redisMQTemplate; |
| 26 | 24 | |
| 27 | 25 | /** |
| 28 | - * 发送 {@link SmsChannelRefreshMessage} 消息 | |
| 29 | - */ | |
| 30 | - public void sendSmsChannelRefreshMessage() { | |
| 31 | - SmsChannelRefreshMessage message = new SmsChannelRefreshMessage(); | |
| 32 | - redisMQTemplate.send(message); | |
| 33 | - } | |
| 34 | - | |
| 35 | - /** | |
| 36 | - * 发送 {@link SmsTemplateRefreshMessage} 消息 | |
| 37 | - */ | |
| 38 | - public void sendSmsTemplateRefreshMessage() { | |
| 39 | - SmsTemplateRefreshMessage message = new SmsTemplateRefreshMessage(); | |
| 40 | - redisMQTemplate.send(message); | |
| 41 | - } | |
| 42 | - | |
| 43 | - /** | |
| 44 | 26 | * 发送 {@link SmsSendMessage} 消息 |
| 45 | 27 | * |
| 46 | 28 | * @param logId 短信日志编号 | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptService.java
| ... | ... | @@ -7,10 +7,7 @@ import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqV |
| 7 | 7 | import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO; |
| 8 | 8 | import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; |
| 9 | 9 | |
| 10 | -import java.util.Collection; | |
| 11 | -import java.util.Collections; | |
| 12 | -import java.util.List; | |
| 13 | -import java.util.Map; | |
| 10 | +import java.util.*; | |
| 14 | 11 | |
| 15 | 12 | /** |
| 16 | 13 | * 部门 Service 接口 |
| ... | ... | @@ -20,11 +17,6 @@ import java.util.Map; |
| 20 | 17 | public interface DeptService { |
| 21 | 18 | |
| 22 | 19 | /** |
| 23 | - * 初始化部门的本地缓存 | |
| 24 | - */ | |
| 25 | - void initLocalCache(); | |
| 26 | - | |
| 27 | - /** | |
| 28 | 20 | * 创建部门 |
| 29 | 21 | * |
| 30 | 22 | * @param reqVO 部门信息 |
| ... | ... | @@ -47,21 +39,12 @@ public interface DeptService { |
| 47 | 39 | void deleteDept(Long id); |
| 48 | 40 | |
| 49 | 41 | /** |
| 50 | - * 筛选部门列表 | |
| 51 | - * | |
| 52 | - * @param reqVO 筛选条件请求 VO | |
| 53 | - * @return 部门列表 | |
| 54 | - */ | |
| 55 | - List<DeptDO> getDeptList(DeptListReqVO reqVO); | |
| 56 | - | |
| 57 | - /** | |
| 58 | - * 获得所有子部门,从缓存中 | |
| 42 | + * 获得部门信息 | |
| 59 | 43 | * |
| 60 | - * @param parentId 部门编号 | |
| 61 | - * @param recursive 是否递归获取所有 | |
| 62 | - * @return 子部门列表 | |
| 44 | + * @param id 部门编号 | |
| 45 | + * @return 部门信息 | |
| 63 | 46 | */ |
| 64 | - List<DeptDO> getDeptListByParentIdFromCache(Long parentId, boolean recursive); | |
| 47 | + DeptDO getDept(Long id); | |
| 65 | 48 | |
| 66 | 49 | /** |
| 67 | 50 | * 获得部门信息数组 |
| ... | ... | @@ -72,6 +55,14 @@ public interface DeptService { |
| 72 | 55 | List<DeptDO> getDeptList(Collection<Long> ids); |
| 73 | 56 | |
| 74 | 57 | /** |
| 58 | + * 筛选部门列表 | |
| 59 | + * | |
| 60 | + * @param reqVO 筛选条件请求 VO | |
| 61 | + * @return 部门列表 | |
| 62 | + */ | |
| 63 | + List<DeptDO> getDeptList(DeptListReqVO reqVO); | |
| 64 | + | |
| 65 | + /** | |
| 75 | 66 | * 获得指定编号的部门 Map |
| 76 | 67 | * |
| 77 | 68 | * @param ids 部门编号数组 |
| ... | ... | @@ -86,12 +77,20 @@ public interface DeptService { |
| 86 | 77 | } |
| 87 | 78 | |
| 88 | 79 | /** |
| 89 | - * 获得部门信息 | |
| 80 | + * 获得指定部门的所有子部门 | |
| 90 | 81 | * |
| 91 | 82 | * @param id 部门编号 |
| 92 | - * @return 部门信息 | |
| 83 | + * @return 子部门列表 | |
| 93 | 84 | */ |
| 94 | - DeptDO getDept(Long id); | |
| 85 | + List<DeptDO> getChildDeptList(Long id); | |
| 86 | + | |
| 87 | + /** | |
| 88 | + * 获得所有子部门,从缓存中 | |
| 89 | + * | |
| 90 | + * @param id 父部门编号 | |
| 91 | + * @return 子部门列表 | |
| 92 | + */ | |
| 93 | + Set<Long> getChildDeptIdListFromCache(Long id); | |
| 95 | 94 | |
| 96 | 95 | /** |
| 97 | 96 | * 校验部门们是否有效。如下情况,视为无效: | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.system.service.dept; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.util.ObjectUtil; | |
| 4 | 5 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 5 | -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | |
| 6 | -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | |
| 6 | +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; | |
| 7 | 7 | import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptCreateReqVO; |
| 8 | 8 | import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO; |
| 9 | 9 | import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO; |
| 10 | 10 | import cn.iocoder.yudao.module.system.convert.dept.DeptConvert; |
| 11 | 11 | import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; |
| 12 | 12 | import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper; |
| 13 | +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; | |
| 13 | 14 | import cn.iocoder.yudao.module.system.enums.dept.DeptIdEnum; |
| 14 | -import cn.iocoder.yudao.module.system.mq.producer.dept.DeptProducer; | |
| 15 | -import com.google.common.collect.ImmutableMap; | |
| 16 | -import com.google.common.collect.ImmutableMultimap; | |
| 17 | -import com.google.common.collect.Multimap; | |
| 18 | -import lombok.Getter; | |
| 15 | +import com.google.common.annotations.VisibleForTesting; | |
| 19 | 16 | import lombok.extern.slf4j.Slf4j; |
| 17 | +import org.springframework.cache.annotation.CacheEvict; | |
| 18 | +import org.springframework.cache.annotation.Cacheable; | |
| 20 | 19 | import org.springframework.stereotype.Service; |
| 21 | 20 | import org.springframework.validation.annotation.Validated; |
| 22 | 21 | |
| 23 | -import javax.annotation.PostConstruct; | |
| 24 | 22 | import javax.annotation.Resource; |
| 25 | 23 | import java.util.*; |
| 26 | 24 | |
| 27 | 25 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 26 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 28 | 27 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; |
| 29 | 28 | |
| 30 | 29 | /** |
| ... | ... | @@ -37,55 +36,12 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; |
| 37 | 36 | @Slf4j |
| 38 | 37 | public class DeptServiceImpl implements DeptService { |
| 39 | 38 | |
| 40 | - /** | |
| 41 | - * 部门缓存 | |
| 42 | - * key:部门编号 {@link DeptDO#getId()} | |
| 43 | - * | |
| 44 | - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | |
| 45 | - */ | |
| 46 | - @Getter | |
| 47 | - private volatile Map<Long, DeptDO> deptCache; | |
| 48 | - /** | |
| 49 | - * 父部门缓存 | |
| 50 | - * key:部门编号 {@link DeptDO#getParentId()} | |
| 51 | - * value: 直接子部门列表 | |
| 52 | - * | |
| 53 | - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | |
| 54 | - */ | |
| 55 | - @Getter | |
| 56 | - private volatile Multimap<Long, DeptDO> parentDeptCache; | |
| 57 | - | |
| 58 | 39 | @Resource |
| 59 | 40 | private DeptMapper deptMapper; |
| 60 | 41 | |
| 61 | - @Resource | |
| 62 | - private DeptProducer deptProducer; | |
| 63 | - | |
| 64 | - /** | |
| 65 | - * 初始化 {@link #parentDeptCache} 和 {@link #deptCache} 缓存 | |
| 66 | - */ | |
| 67 | - @Override | |
| 68 | - @PostConstruct | |
| 69 | - public synchronized void initLocalCache() { | |
| 70 | - // 注意:忽略自动多租户,因为要全局初始化缓存 | |
| 71 | - TenantUtils.executeIgnore(() -> { | |
| 72 | - // 第一步:查询数据 | |
| 73 | - List<DeptDO> depts = deptMapper.selectList(); | |
| 74 | - log.info("[initLocalCache][缓存部门,数量为:{}]", depts.size()); | |
| 75 | - | |
| 76 | - // 第二步:构建缓存 | |
| 77 | - ImmutableMap.Builder<Long, DeptDO> builder = ImmutableMap.builder(); | |
| 78 | - ImmutableMultimap.Builder<Long, DeptDO> parentBuilder = ImmutableMultimap.builder(); | |
| 79 | - depts.forEach(deptDO -> { | |
| 80 | - builder.put(deptDO.getId(), deptDO); | |
| 81 | - parentBuilder.put(deptDO.getParentId(), deptDO); | |
| 82 | - }); | |
| 83 | - deptCache = builder.build(); | |
| 84 | - parentDeptCache = parentBuilder.build(); | |
| 85 | - }); | |
| 86 | - } | |
| 87 | - | |
| 88 | 42 | @Override |
| 43 | + @CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, | |
| 44 | + allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存 | |
| 89 | 45 | public Long createDept(DeptCreateReqVO reqVO) { |
| 90 | 46 | // 校验正确性 |
| 91 | 47 | if (reqVO.getParentId() == null) { |
| ... | ... | @@ -95,12 +51,12 @@ public class DeptServiceImpl implements DeptService { |
| 95 | 51 | // 插入部门 |
| 96 | 52 | DeptDO dept = DeptConvert.INSTANCE.convert(reqVO); |
| 97 | 53 | deptMapper.insert(dept); |
| 98 | - // 发送刷新消息 | |
| 99 | - deptProducer.sendDeptRefreshMessage(); | |
| 100 | 54 | return dept.getId(); |
| 101 | 55 | } |
| 102 | 56 | |
| 103 | 57 | @Override |
| 58 | + @CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, | |
| 59 | + allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存 | |
| 104 | 60 | public void updateDept(DeptUpdateReqVO reqVO) { |
| 105 | 61 | // 校验正确性 |
| 106 | 62 | if (reqVO.getParentId() == null) { |
| ... | ... | @@ -110,11 +66,11 @@ public class DeptServiceImpl implements DeptService { |
| 110 | 66 | // 更新部门 |
| 111 | 67 | DeptDO updateObj = DeptConvert.INSTANCE.convert(reqVO); |
| 112 | 68 | deptMapper.updateById(updateObj); |
| 113 | - // 发送刷新消息 | |
| 114 | - deptProducer.sendDeptRefreshMessage(); | |
| 115 | 69 | } |
| 116 | 70 | |
| 117 | 71 | @Override |
| 72 | + @CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, | |
| 73 | + allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存 | |
| 118 | 74 | public void deleteDept(Long id) { |
| 119 | 75 | // 校验是否存在 |
| 120 | 76 | validateDeptExists(id); |
| ... | ... | @@ -124,70 +80,30 @@ public class DeptServiceImpl implements DeptService { |
| 124 | 80 | } |
| 125 | 81 | // 删除部门 |
| 126 | 82 | deptMapper.deleteById(id); |
| 127 | - // 发送刷新消息 | |
| 128 | - deptProducer.sendDeptRefreshMessage(); | |
| 129 | - } | |
| 130 | - | |
| 131 | - @Override | |
| 132 | - public List<DeptDO> getDeptList(DeptListReqVO reqVO) { | |
| 133 | - return deptMapper.selectList(reqVO); | |
| 134 | - } | |
| 135 | - | |
| 136 | - @Override | |
| 137 | - public List<DeptDO> getDeptListByParentIdFromCache(Long parentId, boolean recursive) { | |
| 138 | - if (parentId == null) { | |
| 139 | - return Collections.emptyList(); | |
| 140 | - } | |
| 141 | - List<DeptDO> result = new ArrayList<>(); | |
| 142 | - // 递归,简单粗暴 | |
| 143 | - getDeptsByParentIdFromCache(result, parentId, | |
| 144 | - recursive ? Integer.MAX_VALUE : 1, // 如果递归获取,则无限;否则,只递归 1 次 | |
| 145 | - parentDeptCache); | |
| 146 | - return result; | |
| 147 | - } | |
| 148 | - | |
| 149 | - /** | |
| 150 | - * 递归获取所有的子部门,添加到 result 结果 | |
| 151 | - * | |
| 152 | - * @param result 结果 | |
| 153 | - * @param parentId 父编号 | |
| 154 | - * @param recursiveCount 递归次数 | |
| 155 | - * @param parentDeptMap 父部门 Map,使用缓存,避免变化 | |
| 156 | - */ | |
| 157 | - private void getDeptsByParentIdFromCache(List<DeptDO> result, Long parentId, int recursiveCount, | |
| 158 | - Multimap<Long, DeptDO> parentDeptMap) { | |
| 159 | - // 递归次数为 0,结束! | |
| 160 | - if (recursiveCount == 0) { | |
| 161 | - return; | |
| 162 | - } | |
| 163 | - | |
| 164 | - // 获得子部门 | |
| 165 | - Collection<DeptDO> depts = parentDeptMap.get(parentId); | |
| 166 | - if (CollUtil.isEmpty(depts)) { | |
| 167 | - return; | |
| 168 | - } | |
| 169 | - // 针对多租户,过滤掉非当前租户的部门 | |
| 170 | - Long tenantId = TenantContextHolder.getTenantId(); | |
| 171 | - if (tenantId != null) { | |
| 172 | - depts = CollUtil.filterNew(depts, dept -> tenantId.equals(dept.getTenantId())); | |
| 173 | - } | |
| 174 | - result.addAll(depts); | |
| 175 | - | |
| 176 | - // 继续递归 | |
| 177 | - depts.forEach(dept -> getDeptsByParentIdFromCache(result, dept.getId(), | |
| 178 | - recursiveCount - 1, parentDeptMap)); | |
| 179 | 83 | } |
| 180 | 84 | |
| 181 | 85 | private void validateForCreateOrUpdate(Long id, Long parentId, String name) { |
| 182 | 86 | // 校验自己存在 |
| 183 | 87 | validateDeptExists(id); |
| 184 | 88 | // 校验父部门的有效性 |
| 185 | - validateParentDeptEnable(id, parentId); | |
| 89 | + validateParentDept(id, parentId); | |
| 186 | 90 | // 校验部门名的唯一性 |
| 187 | 91 | validateDeptNameUnique(id, parentId, name); |
| 188 | 92 | } |
| 189 | 93 | |
| 190 | - private void validateParentDeptEnable(Long id, Long parentId) { | |
| 94 | + @VisibleForTesting | |
| 95 | + void validateDeptExists(Long id) { | |
| 96 | + if (id == null) { | |
| 97 | + return; | |
| 98 | + } | |
| 99 | + DeptDO dept = deptMapper.selectById(id); | |
| 100 | + if (dept == null) { | |
| 101 | + throw exception(DEPT_NOT_FOUND); | |
| 102 | + } | |
| 103 | + } | |
| 104 | + | |
| 105 | + @VisibleForTesting | |
| 106 | + void validateParentDept(Long id, Long parentId) { | |
| 191 | 107 | if (parentId == null || DeptIdEnum.ROOT.getId().equals(parentId)) { |
| 192 | 108 | return; |
| 193 | 109 | } |
| ... | ... | @@ -200,49 +116,71 @@ public class DeptServiceImpl implements DeptService { |
| 200 | 116 | if (dept == null) { |
| 201 | 117 | throw exception(DEPT_PARENT_NOT_EXITS); |
| 202 | 118 | } |
| 203 | - // 父部门被禁用 | |
| 204 | - if (!CommonStatusEnum.ENABLE.getStatus().equals(dept.getStatus())) { | |
| 205 | - throw exception(DEPT_NOT_ENABLE); | |
| 206 | - } | |
| 207 | 119 | // 父部门不能是原来的子部门 |
| 208 | - List<DeptDO> children = getDeptListByParentIdFromCache(id, true); | |
| 120 | + List<DeptDO> children = getChildDeptList(id); | |
| 209 | 121 | if (children.stream().anyMatch(dept1 -> dept1.getId().equals(parentId))) { |
| 210 | 122 | throw exception(DEPT_PARENT_IS_CHILD); |
| 211 | 123 | } |
| 212 | 124 | } |
| 213 | 125 | |
| 214 | - private void validateDeptExists(Long id) { | |
| 215 | - if (id == null) { | |
| 216 | - return; | |
| 217 | - } | |
| 218 | - DeptDO dept = deptMapper.selectById(id); | |
| 126 | + @VisibleForTesting | |
| 127 | + void validateDeptNameUnique(Long id, Long parentId, String name) { | |
| 128 | + DeptDO dept = deptMapper.selectByParentIdAndName(parentId, name); | |
| 219 | 129 | if (dept == null) { |
| 220 | - throw exception(DEPT_NOT_FOUND); | |
| 221 | - } | |
| 222 | - } | |
| 223 | - | |
| 224 | - private void validateDeptNameUnique(Long id, Long parentId, String name) { | |
| 225 | - DeptDO menu = deptMapper.selectByParentIdAndName(parentId, name); | |
| 226 | - if (menu == null) { | |
| 227 | 130 | return; |
| 228 | 131 | } |
| 229 | 132 | // 如果 id 为空,说明不用比较是否为相同 id 的岗位 |
| 230 | 133 | if (id == null) { |
| 231 | 134 | throw exception(DEPT_NAME_DUPLICATE); |
| 232 | 135 | } |
| 233 | - if (!menu.getId().equals(id)) { | |
| 136 | + if (ObjectUtil.notEqual(dept.getId(), id)) { | |
| 234 | 137 | throw exception(DEPT_NAME_DUPLICATE); |
| 235 | 138 | } |
| 236 | 139 | } |
| 237 | 140 | |
| 238 | 141 | @Override |
| 142 | + public DeptDO getDept(Long id) { | |
| 143 | + return deptMapper.selectById(id); | |
| 144 | + } | |
| 145 | + | |
| 146 | + @Override | |
| 239 | 147 | public List<DeptDO> getDeptList(Collection<Long> ids) { |
| 148 | + if (CollUtil.isEmpty(ids)) { | |
| 149 | + return Collections.emptyList(); | |
| 150 | + } | |
| 240 | 151 | return deptMapper.selectBatchIds(ids); |
| 241 | 152 | } |
| 242 | 153 | |
| 243 | 154 | @Override |
| 244 | - public DeptDO getDept(Long id) { | |
| 245 | - return deptMapper.selectById(id); | |
| 155 | + public List<DeptDO> getDeptList(DeptListReqVO reqVO) { | |
| 156 | + return deptMapper.selectList(reqVO); | |
| 157 | + } | |
| 158 | + | |
| 159 | + @Override | |
| 160 | + public List<DeptDO> getChildDeptList(Long id) { | |
| 161 | + List<DeptDO> children = new LinkedList<>(); | |
| 162 | + // 遍历每一层 | |
| 163 | + Collection<Long> parentIds = Collections.singleton(id); | |
| 164 | + for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环 | |
| 165 | + // 查询当前层,所有的子部门 | |
| 166 | + List<DeptDO> depts = deptMapper.selectListByParentId(parentIds); | |
| 167 | + // 1. 如果没有子部门,则结束遍历 | |
| 168 | + if (CollUtil.isEmpty(depts)) { | |
| 169 | + break; | |
| 170 | + } | |
| 171 | + // 2. 如果有子部门,继续遍历 | |
| 172 | + children.addAll(depts); | |
| 173 | + parentIds = convertSet(depts, DeptDO::getId); | |
| 174 | + } | |
| 175 | + return children; | |
| 176 | + } | |
| 177 | + | |
| 178 | + @Override | |
| 179 | + @DataPermission(enable = false) // 禁用数据权限,避免简历不正确的缓存 | |
| 180 | + @Cacheable(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, key = "#id") | |
| 181 | + public Set<Long> getChildDeptIdListFromCache(Long id) { | |
| 182 | + List<DeptDO> children = getChildDeptList(id); | |
| 183 | + return convertSet(children, DeptDO::getId); | |
| 246 | 184 | } |
| 247 | 185 | |
| 248 | 186 | @Override | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountService.java
| ... | ... | @@ -18,19 +18,6 @@ import java.util.List; |
| 18 | 18 | public interface MailAccountService { |
| 19 | 19 | |
| 20 | 20 | /** |
| 21 | - * 初始化邮箱账号的本地缓存 | |
| 22 | - */ | |
| 23 | - void initLocalCache(); | |
| 24 | - | |
| 25 | - /** | |
| 26 | - * 从缓存中获取邮箱账号 | |
| 27 | - * | |
| 28 | - * @param id 编号 | |
| 29 | - * @return 邮箱账号 | |
| 30 | - */ | |
| 31 | - MailAccountDO getMailAccountFromCache(Long id); | |
| 32 | - | |
| 33 | - /** | |
| 34 | 21 | * 创建邮箱账号 |
| 35 | 22 | * |
| 36 | 23 | * @param createReqVO 邮箱账号信息 |
| ... | ... | @@ -61,6 +48,14 @@ public interface MailAccountService { |
| 61 | 48 | MailAccountDO getMailAccount(Long id); |
| 62 | 49 | |
| 63 | 50 | /** |
| 51 | + * 从缓存中获取邮箱账号 | |
| 52 | + * | |
| 53 | + * @param id 编号 | |
| 54 | + * @return 邮箱账号 | |
| 55 | + */ | |
| 56 | + MailAccountDO getMailAccountFromCache(Long id); | |
| 57 | + | |
| 58 | + /** | |
| 64 | 59 | * 获取邮箱账号分页信息 |
| 65 | 60 | * |
| 66 | 61 | * @param pageReqVO 邮箱账号分页参数 | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImpl.java
| ... | ... | @@ -7,20 +7,18 @@ import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccou |
| 7 | 7 | import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert; |
| 8 | 8 | import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; |
| 9 | 9 | import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper; |
| 10 | -import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; | |
| 11 | -import lombok.Getter; | |
| 10 | +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; | |
| 12 | 11 | import lombok.extern.slf4j.Slf4j; |
| 12 | +import org.springframework.cache.annotation.Cacheable; | |
| 13 | 13 | import org.springframework.stereotype.Service; |
| 14 | 14 | import org.springframework.validation.annotation.Validated; |
| 15 | 15 | |
| 16 | -import javax.annotation.PostConstruct; | |
| 17 | 16 | import javax.annotation.Resource; |
| 18 | 17 | import java.util.List; |
| 19 | -import java.util.Map; | |
| 20 | 18 | |
| 21 | 19 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 22 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 23 | -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; | |
| 20 | +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS; | |
| 21 | +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS; | |
| 24 | 22 | |
| 25 | 23 | /** |
| 26 | 24 | * 邮箱账号 Service 实现类 |
| ... | ... | @@ -39,46 +37,16 @@ public class MailAccountServiceImpl implements MailAccountService { |
| 39 | 37 | @Resource |
| 40 | 38 | private MailTemplateService mailTemplateService; |
| 41 | 39 | |
| 42 | - @Resource | |
| 43 | - private MailProducer mailProducer; | |
| 44 | - | |
| 45 | - /** | |
| 46 | - * 邮箱账号缓存 | |
| 47 | - * key:邮箱账号编码 {@link MailAccountDO#getId()} | |
| 48 | - * | |
| 49 | - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | |
| 50 | - */ | |
| 51 | - @Getter | |
| 52 | - private volatile Map<Long, MailAccountDO> mailAccountCache; | |
| 53 | - | |
| 54 | - @Override | |
| 55 | - @PostConstruct | |
| 56 | - public void initLocalCache() { | |
| 57 | - // 第一步:查询数据 | |
| 58 | - List<MailAccountDO> accounts = mailAccountMapper.selectList(); | |
| 59 | - log.info("[initLocalCache][缓存邮箱账号,数量:{}]", accounts.size()); | |
| 60 | - | |
| 61 | - // 第二步:构建缓存 | |
| 62 | - mailAccountCache = convertMap(accounts, MailAccountDO::getId); | |
| 63 | - } | |
| 64 | - | |
| 65 | - @Override | |
| 66 | - public MailAccountDO getMailAccountFromCache(Long id) { | |
| 67 | - return mailAccountCache.get(id); | |
| 68 | - } | |
| 69 | - | |
| 70 | 40 | @Override |
| 71 | 41 | public Long createMailAccount(MailAccountCreateReqVO createReqVO) { |
| 72 | 42 | // 插入 |
| 73 | 43 | MailAccountDO account = MailAccountConvert.INSTANCE.convert(createReqVO); |
| 74 | 44 | mailAccountMapper.insert(account); |
| 75 | - | |
| 76 | - // 发送刷新消息 | |
| 77 | - mailProducer.sendMailAccountRefreshMessage(); | |
| 78 | 45 | return account.getId(); |
| 79 | 46 | } |
| 80 | 47 | |
| 81 | 48 | @Override |
| 49 | + @Cacheable(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#updateReqVO.id") | |
| 82 | 50 | public void updateMailAccount(MailAccountUpdateReqVO updateReqVO) { |
| 83 | 51 | // 校验是否存在 |
| 84 | 52 | validateMailAccountExists(updateReqVO.getId()); |
| ... | ... | @@ -86,11 +54,10 @@ public class MailAccountServiceImpl implements MailAccountService { |
| 86 | 54 | // 更新 |
| 87 | 55 | MailAccountDO updateObj = MailAccountConvert.INSTANCE.convert(updateReqVO); |
| 88 | 56 | mailAccountMapper.updateById(updateObj); |
| 89 | - // 发送刷新消息 | |
| 90 | - mailProducer.sendMailAccountRefreshMessage(); | |
| 91 | 57 | } |
| 92 | 58 | |
| 93 | 59 | @Override |
| 60 | + @Cacheable(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#id") | |
| 94 | 61 | public void deleteMailAccount(Long id) { |
| 95 | 62 | // 校验是否存在账号 |
| 96 | 63 | validateMailAccountExists(id); |
| ... | ... | @@ -101,8 +68,6 @@ public class MailAccountServiceImpl implements MailAccountService { |
| 101 | 68 | |
| 102 | 69 | // 删除 |
| 103 | 70 | mailAccountMapper.deleteById(id); |
| 104 | - // 发送刷新消息 | |
| 105 | - mailProducer.sendMailAccountRefreshMessage(); | |
| 106 | 71 | } |
| 107 | 72 | |
| 108 | 73 | private void validateMailAccountExists(Long id) { |
| ... | ... | @@ -117,6 +82,12 @@ public class MailAccountServiceImpl implements MailAccountService { |
| 117 | 82 | } |
| 118 | 83 | |
| 119 | 84 | @Override |
| 85 | + @Cacheable(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#id", unless = "#result == null") | |
| 86 | + public MailAccountDO getMailAccountFromCache(Long id) { | |
| 87 | + return getMailAccount(id); | |
| 88 | + } | |
| 89 | + | |
| 90 | + @Override | |
| 120 | 91 | public PageResult<MailAccountDO> getMailAccountPage(MailAccountPageReqVO pageReqVO) { |
| 121 | 92 | return mailAccountMapper.selectPage(pageReqVO); |
| 122 | 93 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java
| ... | ... | @@ -10,14 +10,14 @@ import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemp |
| 10 | 10 | import cn.iocoder.yudao.module.system.convert.mail.MailTemplateConvert; |
| 11 | 11 | import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; |
| 12 | 12 | import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper; |
| 13 | -import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; | |
| 13 | +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; | |
| 14 | 14 | import com.google.common.annotations.VisibleForTesting; |
| 15 | -import lombok.Getter; | |
| 16 | 15 | import lombok.extern.slf4j.Slf4j; |
| 16 | +import org.springframework.cache.annotation.CacheEvict; | |
| 17 | +import org.springframework.cache.annotation.Cacheable; | |
| 17 | 18 | import org.springframework.stereotype.Service; |
| 18 | 19 | import org.springframework.validation.annotation.Validated; |
| 19 | 20 | |
| 20 | -import javax.annotation.PostConstruct; | |
| 21 | 21 | import javax.annotation.Resource; |
| 22 | 22 | import javax.validation.Valid; |
| 23 | 23 | import java.util.List; |
| ... | ... | @@ -25,8 +25,8 @@ import java.util.Map; |
| 25 | 25 | import java.util.regex.Pattern; |
| 26 | 26 | |
| 27 | 27 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 28 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 29 | -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; | |
| 28 | +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_CODE_EXISTS; | |
| 29 | +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_NOT_EXISTS; | |
| 30 | 30 | |
| 31 | 31 | /** |
| 32 | 32 | * 邮箱模版 Service 实现类 |
| ... | ... | @@ -47,29 +47,6 @@ public class MailTemplateServiceImpl implements MailTemplateService { |
| 47 | 47 | @Resource |
| 48 | 48 | private MailTemplateMapper mailTemplateMapper; |
| 49 | 49 | |
| 50 | - @Resource | |
| 51 | - private MailProducer mailProducer; | |
| 52 | - | |
| 53 | - /** | |
| 54 | - * 邮件模板缓存 | |
| 55 | - * key:邮件模版标识 {@link MailTemplateDO#getCode()} | |
| 56 | - * | |
| 57 | - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | |
| 58 | - */ | |
| 59 | - @Getter | |
| 60 | - private volatile Map<String, MailTemplateDO> mailTemplateCache; | |
| 61 | - | |
| 62 | - @Override | |
| 63 | - @PostConstruct | |
| 64 | - public void initLocalCache() { | |
| 65 | - // 第一步:查询数据 | |
| 66 | - List<MailTemplateDO> templates = mailTemplateMapper.selectList(); | |
| 67 | - log.info("[initLocalCache][缓存邮件模版,数量:{}]", templates.size()); | |
| 68 | - | |
| 69 | - // 第二步:构建缓存 | |
| 70 | - mailTemplateCache = convertMap(templates, MailTemplateDO::getCode); | |
| 71 | - } | |
| 72 | - | |
| 73 | 50 | @Override |
| 74 | 51 | public Long createMailTemplate(MailTemplateCreateReqVO createReqVO) { |
| 75 | 52 | // 校验 code 是否唯一 |
| ... | ... | @@ -79,12 +56,12 @@ public class MailTemplateServiceImpl implements MailTemplateService { |
| 79 | 56 | MailTemplateDO template = MailTemplateConvert.INSTANCE.convert(createReqVO) |
| 80 | 57 | .setParams(parseTemplateContentParams(createReqVO.getContent())); |
| 81 | 58 | mailTemplateMapper.insert(template); |
| 82 | - // 发送刷新消息 | |
| 83 | - mailProducer.sendMailTemplateRefreshMessage(); | |
| 84 | 59 | return template.getId(); |
| 85 | 60 | } |
| 86 | 61 | |
| 87 | 62 | @Override |
| 63 | + @CacheEvict(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE, | |
| 64 | + allEntries = true) // allEntries 清空所有缓存,因为可能修改到 code 字段,不好清理 | |
| 88 | 65 | public void updateMailTemplate(@Valid MailTemplateUpdateReqVO updateReqVO) { |
| 89 | 66 | // 校验是否存在 |
| 90 | 67 | validateMailTemplateExists(updateReqVO.getId()); |
| ... | ... | @@ -95,12 +72,10 @@ public class MailTemplateServiceImpl implements MailTemplateService { |
| 95 | 72 | MailTemplateDO updateObj = MailTemplateConvert.INSTANCE.convert(updateReqVO) |
| 96 | 73 | .setParams(parseTemplateContentParams(updateReqVO.getContent())); |
| 97 | 74 | mailTemplateMapper.updateById(updateObj); |
| 98 | - // 发送刷新消息 | |
| 99 | - mailProducer.sendMailTemplateRefreshMessage(); | |
| 100 | 75 | } |
| 101 | 76 | |
| 102 | 77 | @VisibleForTesting |
| 103 | - public void validateCodeUnique(Long id, String code) { | |
| 78 | + void validateCodeUnique(Long id, String code) { | |
| 104 | 79 | MailTemplateDO template = mailTemplateMapper.selectByCode(code); |
| 105 | 80 | if (template == null) { |
| 106 | 81 | return; |
| ... | ... | @@ -113,14 +88,14 @@ public class MailTemplateServiceImpl implements MailTemplateService { |
| 113 | 88 | } |
| 114 | 89 | |
| 115 | 90 | @Override |
| 91 | + @CacheEvict(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE, | |
| 92 | + allEntries = true) // allEntries 清空所有缓存,因为 id 不是直接的缓存 code,不好清理 | |
| 116 | 93 | public void deleteMailTemplate(Long id) { |
| 117 | 94 | // 校验是否存在 |
| 118 | 95 | validateMailTemplateExists(id); |
| 119 | 96 | |
| 120 | 97 | // 删除 |
| 121 | 98 | mailTemplateMapper.deleteById(id); |
| 122 | - // 发送刷新消息 | |
| 123 | - mailProducer.sendMailTemplateRefreshMessage(); | |
| 124 | 99 | } |
| 125 | 100 | |
| 126 | 101 | private void validateMailTemplateExists(Long id) { |
| ... | ... | @@ -133,6 +108,12 @@ public class MailTemplateServiceImpl implements MailTemplateService { |
| 133 | 108 | public MailTemplateDO getMailTemplate(Long id) {return mailTemplateMapper.selectById(id);} |
| 134 | 109 | |
| 135 | 110 | @Override |
| 111 | + @Cacheable(value = RedisKeyConstants.MAIL_TEMPLATE, key = "#code", unless = "#result == null") | |
| 112 | + public MailTemplateDO getMailTemplateByCodeFromCache(String code) { | |
| 113 | + return mailTemplateMapper.selectByCode(code); | |
| 114 | + } | |
| 115 | + | |
| 116 | + @Override | |
| 136 | 117 | public PageResult<MailTemplateDO> getMailTemplatePage(MailTemplatePageReqVO pageReqVO) { |
| 137 | 118 | return mailTemplateMapper.selectPage(pageReqVO); |
| 138 | 119 | } |
| ... | ... | @@ -141,11 +122,6 @@ public class MailTemplateServiceImpl implements MailTemplateService { |
| 141 | 122 | public List<MailTemplateDO> getMailTemplateList() {return mailTemplateMapper.selectList();} |
| 142 | 123 | |
| 143 | 124 | @Override |
| 144 | - public MailTemplateDO getMailTemplateByCodeFromCache(String code) { | |
| 145 | - return mailTemplateCache.get(code); | |
| 146 | - } | |
| 147 | - | |
| 148 | - @Override | |
| 149 | 125 | public String formatMailTemplateContent(String content, Map<String, Object> params) { |
| 150 | 126 | return StrUtil.format(content, params); |
| 151 | 127 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateService.java
| ... | ... | @@ -17,19 +17,6 @@ import java.util.Map; |
| 17 | 17 | public interface NotifyTemplateService { |
| 18 | 18 | |
| 19 | 19 | /** |
| 20 | - * 初始化站内信模板的本地缓存 | |
| 21 | - */ | |
| 22 | - void initLocalCache(); | |
| 23 | - | |
| 24 | - /** | |
| 25 | - * 获得站内信模板,从缓存中 | |
| 26 | - * | |
| 27 | - * @param code 模板编码 | |
| 28 | - * @return 站内信模板 | |
| 29 | - */ | |
| 30 | - NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code); | |
| 31 | - | |
| 32 | - /** | |
| 33 | 20 | * 创建站内信模版 |
| 34 | 21 | * |
| 35 | 22 | * @param createReqVO 创建信息 |
| ... | ... | @@ -60,6 +47,14 @@ public interface NotifyTemplateService { |
| 60 | 47 | NotifyTemplateDO getNotifyTemplate(Long id); |
| 61 | 48 | |
| 62 | 49 | /** |
| 50 | + * 获得站内信模板,从缓存中 | |
| 51 | + * | |
| 52 | + * @param code 模板编码 | |
| 53 | + * @return 站内信模板 | |
| 54 | + */ | |
| 55 | + NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code); | |
| 56 | + | |
| 57 | + /** | |
| 63 | 58 | * 获得站内信模版分页 |
| 64 | 59 | * |
| 65 | 60 | * @param pageReqVO 分页查询 | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImpl.java
| ... | ... | @@ -3,27 +3,28 @@ package cn.iocoder.yudao.module.system.service.notify; |
| 3 | 3 | import cn.hutool.core.util.ReUtil; |
| 4 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 7 | 6 | import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateCreateReqVO; |
| 8 | 7 | import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplatePageReqVO; |
| 9 | 8 | import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO; |
| 10 | 9 | import cn.iocoder.yudao.module.system.convert.notify.NotifyTemplateConvert; |
| 11 | 10 | import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; |
| 12 | 11 | import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyTemplateMapper; |
| 13 | -import cn.iocoder.yudao.module.system.mq.producer.notify.NotifyProducer; | |
| 12 | +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; | |
| 14 | 13 | import com.google.common.annotations.VisibleForTesting; |
| 15 | 14 | import lombok.extern.slf4j.Slf4j; |
| 15 | +import org.springframework.cache.annotation.CacheEvict; | |
| 16 | +import org.springframework.cache.annotation.Cacheable; | |
| 16 | 17 | import org.springframework.stereotype.Service; |
| 17 | 18 | import org.springframework.validation.annotation.Validated; |
| 18 | 19 | |
| 19 | -import javax.annotation.PostConstruct; | |
| 20 | 20 | import javax.annotation.Resource; |
| 21 | 21 | import java.util.List; |
| 22 | 22 | import java.util.Map; |
| 23 | 23 | import java.util.regex.Pattern; |
| 24 | 24 | |
| 25 | 25 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 26 | -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; | |
| 26 | +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_CODE_DUPLICATE; | |
| 27 | +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_NOT_EXISTS; | |
| 27 | 28 | |
| 28 | 29 | /** |
| 29 | 30 | * 站内信模版 Service 实现类 |
| ... | ... | @@ -43,36 +44,6 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService { |
| 43 | 44 | @Resource |
| 44 | 45 | private NotifyTemplateMapper notifyTemplateMapper; |
| 45 | 46 | |
| 46 | - @Resource | |
| 47 | - private NotifyProducer notifyProducer; | |
| 48 | - | |
| 49 | - /** | |
| 50 | - * 站内信模板缓存 | |
| 51 | - * key:站内信模板编码 {@link NotifyTemplateDO#getCode()} | |
| 52 | - * <p> | |
| 53 | - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | |
| 54 | - */ | |
| 55 | - private volatile Map<String, NotifyTemplateDO> notifyTemplateCache; | |
| 56 | - | |
| 57 | - /** | |
| 58 | - * 初始化站内信模板的本地缓存 | |
| 59 | - */ | |
| 60 | - @Override | |
| 61 | - @PostConstruct | |
| 62 | - public void initLocalCache() { | |
| 63 | - // 第一步:查询数据 | |
| 64 | - List<NotifyTemplateDO> templates = notifyTemplateMapper.selectList(); | |
| 65 | - log.info("[initLocalCache][缓存站内信模版,数量为:{}]", templates.size()); | |
| 66 | - | |
| 67 | - // 第二步:构建缓存 | |
| 68 | - notifyTemplateCache = CollectionUtils.convertMap(templates, NotifyTemplateDO::getCode); | |
| 69 | - } | |
| 70 | - | |
| 71 | - @Override | |
| 72 | - public NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code) { | |
| 73 | - return notifyTemplateCache.get(code); | |
| 74 | - } | |
| 75 | - | |
| 76 | 47 | @Override |
| 77 | 48 | public Long createNotifyTemplate(NotifyTemplateCreateReqVO createReqVO) { |
| 78 | 49 | // 校验站内信编码是否重复 |
| ... | ... | @@ -82,13 +53,12 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService { |
| 82 | 53 | NotifyTemplateDO notifyTemplate = NotifyTemplateConvert.INSTANCE.convert(createReqVO); |
| 83 | 54 | notifyTemplate.setParams(parseTemplateContentParams(notifyTemplate.getContent())); |
| 84 | 55 | notifyTemplateMapper.insert(notifyTemplate); |
| 85 | - | |
| 86 | - // 发送刷新消息 | |
| 87 | - notifyProducer.sendNotifyTemplateRefreshMessage(); | |
| 88 | 56 | return notifyTemplate.getId(); |
| 89 | 57 | } |
| 90 | 58 | |
| 91 | 59 | @Override |
| 60 | + @CacheEvict(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE, | |
| 61 | + allEntries = true) // allEntries 清空所有缓存,因为可能修改到 code 字段,不好清理 | |
| 92 | 62 | public void updateNotifyTemplate(NotifyTemplateUpdateReqVO updateReqVO) { |
| 93 | 63 | // 校验存在 |
| 94 | 64 | validateNotifyTemplateExists(updateReqVO.getId()); |
| ... | ... | @@ -99,9 +69,6 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService { |
| 99 | 69 | NotifyTemplateDO updateObj = NotifyTemplateConvert.INSTANCE.convert(updateReqVO); |
| 100 | 70 | updateObj.setParams(parseTemplateContentParams(updateObj.getContent())); |
| 101 | 71 | notifyTemplateMapper.updateById(updateObj); |
| 102 | - | |
| 103 | - // 发送刷新消息 | |
| 104 | - notifyProducer.sendNotifyTemplateRefreshMessage(); | |
| 105 | 72 | } |
| 106 | 73 | |
| 107 | 74 | @VisibleForTesting |
| ... | ... | @@ -110,13 +77,13 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService { |
| 110 | 77 | } |
| 111 | 78 | |
| 112 | 79 | @Override |
| 80 | + @CacheEvict(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE, | |
| 81 | + allEntries = true) // allEntries 清空所有缓存,因为 id 不是直接的缓存 code,不好清理 | |
| 113 | 82 | public void deleteNotifyTemplate(Long id) { |
| 114 | 83 | // 校验存在 |
| 115 | 84 | validateNotifyTemplateExists(id); |
| 116 | 85 | // 删除 |
| 117 | 86 | notifyTemplateMapper.deleteById(id); |
| 118 | - // 发送刷新消息 | |
| 119 | - notifyProducer.sendNotifyTemplateRefreshMessage(); | |
| 120 | 87 | } |
| 121 | 88 | |
| 122 | 89 | private void validateNotifyTemplateExists(Long id) { |
| ... | ... | @@ -131,12 +98,19 @@ public class NotifyTemplateServiceImpl implements NotifyTemplateService { |
| 131 | 98 | } |
| 132 | 99 | |
| 133 | 100 | @Override |
| 101 | + @Cacheable(cacheNames = RedisKeyConstants.NOTIFY_TEMPLATE, key = "#code", | |
| 102 | + unless = "#result == null") | |
| 103 | + public NotifyTemplateDO getNotifyTemplateByCodeFromCache(String code) { | |
| 104 | + return notifyTemplateMapper.selectByCode(code); | |
| 105 | + } | |
| 106 | + | |
| 107 | + @Override | |
| 134 | 108 | public PageResult<NotifyTemplateDO> getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO) { |
| 135 | 109 | return notifyTemplateMapper.selectPage(pageReqVO); |
| 136 | 110 | } |
| 137 | 111 | |
| 138 | 112 | @VisibleForTesting |
| 139 | - public void validateNotifyTemplateCodeDuplicate(Long id, String code) { | |
| 113 | + void validateNotifyTemplateCodeDuplicate(Long id, String code) { | |
| 140 | 114 | NotifyTemplateDO template = notifyTemplateMapper.selectByCode(code); |
| 141 | 115 | if (template == null) { |
| 142 | 116 | return; | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientService.java
| ... | ... | @@ -19,11 +19,6 @@ import java.util.Collection; |
| 19 | 19 | public interface OAuth2ClientService { |
| 20 | 20 | |
| 21 | 21 | /** |
| 22 | - * 初始化 OAuth2Client 的本地缓存 | |
| 23 | - */ | |
| 24 | - void initLocalCache(); | |
| 25 | - | |
| 26 | - /** | |
| 27 | 22 | * 创建 OAuth2 客户端 |
| 28 | 23 | * |
| 29 | 24 | * @param createReqVO 创建信息 |
| ... | ... | @@ -54,6 +49,14 @@ public interface OAuth2ClientService { |
| 54 | 49 | OAuth2ClientDO getOAuth2Client(Long id); |
| 55 | 50 | |
| 56 | 51 | /** |
| 52 | + * 获得 OAuth2 客户端,从缓存中 | |
| 53 | + * | |
| 54 | + * @param clientId 客户端编号 | |
| 55 | + * @return OAuth2 客户端 | |
| 56 | + */ | |
| 57 | + OAuth2ClientDO getOAuth2ClientFromCache(String clientId); | |
| 58 | + | |
| 59 | + /** | |
| 57 | 60 | * 获得 OAuth2 客户端分页 |
| 58 | 61 | * |
| 59 | 62 | * @param pageReqVO 分页查询 |
| ... | ... | @@ -82,7 +85,7 @@ public interface OAuth2ClientService { |
| 82 | 85 | * @param redirectUri 重定向地址 |
| 83 | 86 | * @return 客户端 |
| 84 | 87 | */ |
| 85 | - OAuth2ClientDO validOAuthClientFromCache(String clientId, String clientSecret, | |
| 86 | - String authorizedGrantType, Collection<String> scopes, String redirectUri); | |
| 88 | + OAuth2ClientDO validOAuthClientFromCache(String clientId, String clientSecret, String authorizedGrantType, | |
| 89 | + Collection<String> scopes, String redirectUri); | |
| 87 | 90 | |
| 88 | 91 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.oauth2; |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.util.ObjectUtil; |
| 5 | 5 | import cn.hutool.core.util.StrUtil; |
| 6 | +import cn.hutool.extra.spring.SpringUtil; | |
| 6 | 7 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 7 | 8 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | 9 | import cn.iocoder.yudao.framework.common.util.string.StrUtils; |
| ... | ... | @@ -12,22 +13,18 @@ import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2Cl |
| 12 | 13 | import cn.iocoder.yudao.module.system.convert.auth.OAuth2ClientConvert; |
| 13 | 14 | import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; |
| 14 | 15 | import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ClientMapper; |
| 15 | -import cn.iocoder.yudao.module.system.mq.producer.auth.OAuth2ClientProducer; | |
| 16 | +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; | |
| 16 | 17 | import com.google.common.annotations.VisibleForTesting; |
| 17 | -import lombok.Getter; | |
| 18 | -import lombok.Setter; | |
| 19 | 18 | import lombok.extern.slf4j.Slf4j; |
| 19 | +import org.springframework.cache.annotation.CacheEvict; | |
| 20 | +import org.springframework.cache.annotation.Cacheable; | |
| 20 | 21 | import org.springframework.stereotype.Service; |
| 21 | 22 | import org.springframework.validation.annotation.Validated; |
| 22 | 23 | |
| 23 | -import javax.annotation.PostConstruct; | |
| 24 | 24 | import javax.annotation.Resource; |
| 25 | 25 | import java.util.Collection; |
| 26 | -import java.util.List; | |
| 27 | -import java.util.Map; | |
| 28 | 26 | |
| 29 | 27 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 30 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 31 | 28 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; |
| 32 | 29 | |
| 33 | 30 | /** |
| ... | ... | @@ -40,48 +37,21 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; |
| 40 | 37 | @Slf4j |
| 41 | 38 | public class OAuth2ClientServiceImpl implements OAuth2ClientService { |
| 42 | 39 | |
| 43 | - /** | |
| 44 | - * 客户端缓存 | |
| 45 | - * key:客户端编号 {@link OAuth2ClientDO#getClientId()} ()} | |
| 46 | - * | |
| 47 | - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | |
| 48 | - */ | |
| 49 | - @Getter // 解决单测 | |
| 50 | - @Setter // 解决单测 | |
| 51 | - private volatile Map<String, OAuth2ClientDO> clientCache; | |
| 52 | - | |
| 53 | 40 | @Resource |
| 54 | 41 | private OAuth2ClientMapper oauth2ClientMapper; |
| 55 | 42 | |
| 56 | - @Resource | |
| 57 | - private OAuth2ClientProducer oauth2ClientProducer; | |
| 58 | - | |
| 59 | - /** | |
| 60 | - * 初始化 {@link #clientCache} 缓存 | |
| 61 | - */ | |
| 62 | - @Override | |
| 63 | - @PostConstruct | |
| 64 | - public void initLocalCache() { | |
| 65 | - // 第一步:查询数据 | |
| 66 | - List<OAuth2ClientDO> clients = oauth2ClientMapper.selectList(); | |
| 67 | - log.info("[initLocalCache][缓存 OAuth2 客户端,数量为:{}]", clients.size()); | |
| 68 | - | |
| 69 | - // 第二步:构建缓存。 | |
| 70 | - clientCache = convertMap(clients, OAuth2ClientDO::getClientId); | |
| 71 | - } | |
| 72 | - | |
| 73 | 43 | @Override |
| 74 | 44 | public Long createOAuth2Client(OAuth2ClientCreateReqVO createReqVO) { |
| 75 | 45 | validateClientIdExists(null, createReqVO.getClientId()); |
| 76 | 46 | // 插入 |
| 77 | 47 | OAuth2ClientDO oauth2Client = OAuth2ClientConvert.INSTANCE.convert(createReqVO); |
| 78 | 48 | oauth2ClientMapper.insert(oauth2Client); |
| 79 | - // 发送刷新消息 | |
| 80 | - oauth2ClientProducer.sendOAuth2ClientRefreshMessage(); | |
| 81 | 49 | return oauth2Client.getId(); |
| 82 | 50 | } |
| 83 | 51 | |
| 84 | 52 | @Override |
| 53 | + @CacheEvict(cacheNames = RedisKeyConstants.OAUTH_CLIENT, | |
| 54 | + allEntries = true) // allEntries 清空所有缓存,因为可能修改到 clientId 字段,不好清理 | |
| 85 | 55 | public void updateOAuth2Client(OAuth2ClientUpdateReqVO updateReqVO) { |
| 86 | 56 | // 校验存在 |
| 87 | 57 | validateOAuth2ClientExists(updateReqVO.getId()); |
| ... | ... | @@ -91,18 +61,16 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService { |
| 91 | 61 | // 更新 |
| 92 | 62 | OAuth2ClientDO updateObj = OAuth2ClientConvert.INSTANCE.convert(updateReqVO); |
| 93 | 63 | oauth2ClientMapper.updateById(updateObj); |
| 94 | - // 发送刷新消息 | |
| 95 | - oauth2ClientProducer.sendOAuth2ClientRefreshMessage(); | |
| 96 | 64 | } |
| 97 | 65 | |
| 98 | 66 | @Override |
| 67 | + @CacheEvict(cacheNames = RedisKeyConstants.OAUTH_CLIENT, | |
| 68 | + allEntries = true) // allEntries 清空所有缓存,因为 id 不是直接的缓存 key,不好清理 | |
| 99 | 69 | public void deleteOAuth2Client(Long id) { |
| 100 | 70 | // 校验存在 |
| 101 | 71 | validateOAuth2ClientExists(id); |
| 102 | 72 | // 删除 |
| 103 | 73 | oauth2ClientMapper.deleteById(id); |
| 104 | - // 发送刷新消息 | |
| 105 | - oauth2ClientProducer.sendOAuth2ClientRefreshMessage(); | |
| 106 | 74 | } |
| 107 | 75 | |
| 108 | 76 | private void validateOAuth2ClientExists(Long id) { |
| ... | ... | @@ -132,15 +100,22 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService { |
| 132 | 100 | } |
| 133 | 101 | |
| 134 | 102 | @Override |
| 103 | + @Cacheable(cacheNames = RedisKeyConstants.OAUTH_CLIENT, key = "#clientId", | |
| 104 | + unless = "#result == null") | |
| 105 | + public OAuth2ClientDO getOAuth2ClientFromCache(String clientId) { | |
| 106 | + return oauth2ClientMapper.selectByClientId(clientId); | |
| 107 | + } | |
| 108 | + | |
| 109 | + @Override | |
| 135 | 110 | public PageResult<OAuth2ClientDO> getOAuth2ClientPage(OAuth2ClientPageReqVO pageReqVO) { |
| 136 | 111 | return oauth2ClientMapper.selectPage(pageReqVO); |
| 137 | 112 | } |
| 138 | 113 | |
| 139 | 114 | @Override |
| 140 | - public OAuth2ClientDO validOAuthClientFromCache(String clientId, String clientSecret, | |
| 141 | - String authorizedGrantType, Collection<String> scopes, String redirectUri) { | |
| 115 | + public OAuth2ClientDO validOAuthClientFromCache(String clientId, String clientSecret, String authorizedGrantType, | |
| 116 | + Collection<String> scopes, String redirectUri) { | |
| 142 | 117 | // 校验客户端存在、且开启 |
| 143 | - OAuth2ClientDO client = clientCache.get(clientId); | |
| 118 | + OAuth2ClientDO client = getSelf().getOAuth2ClientFromCache(clientId); | |
| 144 | 119 | if (client == null) { |
| 145 | 120 | throw exception(OAUTH2_CLIENT_NOT_EXISTS); |
| 146 | 121 | } |
| ... | ... | @@ -167,4 +142,13 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService { |
| 167 | 142 | return client; |
| 168 | 143 | } |
| 169 | 144 | |
| 145 | + /** | |
| 146 | + * 获得自身的代理对象,解决 AOP 生效问题 | |
| 147 | + * | |
| 148 | + * @return 自己 | |
| 149 | + */ | |
| 150 | + private OAuth2ClientServiceImpl getSelf() { | |
| 151 | + return SpringUtil.getBean(getClass()); | |
| 152 | + } | |
| 153 | + | |
| 170 | 154 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuService.java
| ... | ... | @@ -16,11 +16,6 @@ import java.util.List; |
| 16 | 16 | public interface MenuService { |
| 17 | 17 | |
| 18 | 18 | /** |
| 19 | - * 初始化菜单的本地缓存 | |
| 20 | - */ | |
| 21 | - void initLocalCache(); | |
| 22 | - | |
| 23 | - /** | |
| 24 | 19 | * 创建菜单 |
| 25 | 20 | * |
| 26 | 21 | * @param reqVO 菜单信息 |
| ... | ... | @@ -67,36 +62,12 @@ public interface MenuService { |
| 67 | 62 | List<MenuDO> getMenuList(MenuListReqVO reqVO); |
| 68 | 63 | |
| 69 | 64 | /** |
| 70 | - * 获得所有菜单,从缓存中 | |
| 71 | - * | |
| 72 | - * 任一参数为空时,则返回为空 | |
| 73 | - * | |
| 74 | - * @param menuTypes 菜单类型数组 | |
| 75 | - * @param menusStatuses 菜单状态数组 | |
| 76 | - * @return 菜单列表 | |
| 77 | - */ | |
| 78 | - List<MenuDO> getMenuListFromCache(Collection<Integer> menuTypes, Collection<Integer> menusStatuses); | |
| 79 | - | |
| 80 | - /** | |
| 81 | - * 获得指定编号的菜单数组,从缓存中 | |
| 82 | - * | |
| 83 | - * 任一参数为空时,则返回为空 | |
| 84 | - * | |
| 85 | - * @param menuIds 菜单编号数组 | |
| 86 | - * @param menuTypes 菜单类型数组 | |
| 87 | - * @param menusStatuses 菜单状态数组 | |
| 88 | - * @return 菜单数组 | |
| 89 | - */ | |
| 90 | - List<MenuDO> getMenuListFromCache(Collection<Long> menuIds, Collection<Integer> menuTypes, | |
| 91 | - Collection<Integer> menusStatuses); | |
| 92 | - | |
| 93 | - /** | |
| 94 | - * 获得权限对应的菜单数组 | |
| 65 | + * 获得权限对应的菜单编号数组 | |
| 95 | 66 | * |
| 96 | 67 | * @param permission 权限标识 |
| 97 | 68 | * @return 数组 |
| 98 | 69 | */ |
| 99 | - List<MenuDO> getMenuListByPermissionFromCache(String permission); | |
| 70 | + List<Long> getMenuIdListByPermissionFromCache(String permission); | |
| 100 | 71 | |
| 101 | 72 | /** |
| 102 | 73 | * 获得菜单 |
| ... | ... | @@ -106,4 +77,12 @@ public interface MenuService { |
| 106 | 77 | */ |
| 107 | 78 | MenuDO getMenu(Long id); |
| 108 | 79 | |
| 80 | + /** | |
| 81 | + * 获得菜单数组 | |
| 82 | + * | |
| 83 | + * @param ids 菜单编号数组 | |
| 84 | + * @return 菜单数组 | |
| 85 | + */ | |
| 86 | + List<MenuDO> getMenuList(Collection<Long> ids); | |
| 87 | + | |
| 109 | 88 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.system.service.permission; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | -import cn.hutool.core.util.StrUtil; | |
| 5 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 6 | 4 | import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuCreateReqVO; |
| 7 | 5 | import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuListReqVO; |
| 8 | 6 | import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuUpdateReqVO; |
| 9 | 7 | import cn.iocoder.yudao.module.system.convert.permission.MenuConvert; |
| 10 | 8 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; |
| 11 | 9 | import cn.iocoder.yudao.module.system.dal.mysql.permission.MenuMapper; |
| 10 | +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; | |
| 12 | 11 | import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum; |
| 13 | -import cn.iocoder.yudao.module.system.mq.producer.permission.MenuProducer; | |
| 14 | 12 | import cn.iocoder.yudao.module.system.service.tenant.TenantService; |
| 15 | 13 | import com.google.common.annotations.VisibleForTesting; |
| 16 | -import com.google.common.collect.ImmutableMap; | |
| 17 | -import com.google.common.collect.ImmutableMultimap; | |
| 18 | -import com.google.common.collect.Multimap; | |
| 19 | -import lombok.Getter; | |
| 20 | -import lombok.Setter; | |
| 21 | 14 | import lombok.extern.slf4j.Slf4j; |
| 15 | +import org.springframework.cache.annotation.CacheEvict; | |
| 16 | +import org.springframework.cache.annotation.Cacheable; | |
| 22 | 17 | import org.springframework.context.annotation.Lazy; |
| 23 | 18 | import org.springframework.stereotype.Service; |
| 24 | 19 | import org.springframework.transaction.annotation.Transactional; |
| 25 | -import org.springframework.transaction.support.TransactionSynchronization; | |
| 26 | -import org.springframework.transaction.support.TransactionSynchronizationManager; | |
| 27 | 20 | |
| 28 | -import javax.annotation.PostConstruct; | |
| 29 | 21 | import javax.annotation.Resource; |
| 30 | -import java.util.*; | |
| 31 | -import java.util.stream.Collectors; | |
| 22 | +import java.util.Collection; | |
| 23 | +import java.util.List; | |
| 32 | 24 | |
| 33 | 25 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 26 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 34 | 27 | import static cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO.ID_ROOT; |
| 35 | 28 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; |
| 36 | 29 | |
| ... | ... | @@ -43,26 +36,6 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; |
| 43 | 36 | @Slf4j |
| 44 | 37 | public class MenuServiceImpl implements MenuService { |
| 45 | 38 | |
| 46 | - /** | |
| 47 | - * 菜单缓存 | |
| 48 | - * key:菜单编号 | |
| 49 | - * | |
| 50 | - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | |
| 51 | - */ | |
| 52 | - @Getter | |
| 53 | - @Setter | |
| 54 | - private volatile Map<Long, MenuDO> menuCache; | |
| 55 | - /** | |
| 56 | - * 权限与菜单缓存 | |
| 57 | - * key:权限 {@link MenuDO#getPermission()} | |
| 58 | - * value:MenuDO 数组,因为一个权限可能对应多个 MenuDO 对象 | |
| 59 | - * | |
| 60 | - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | |
| 61 | - */ | |
| 62 | - @Getter | |
| 63 | - @Setter | |
| 64 | - private volatile Multimap<String, MenuDO> permissionMenuCache; | |
| 65 | - | |
| 66 | 39 | @Resource |
| 67 | 40 | private MenuMapper menuMapper; |
| 68 | 41 | @Resource |
| ... | ... | @@ -71,33 +44,8 @@ public class MenuServiceImpl implements MenuService { |
| 71 | 44 | @Lazy // 延迟,避免循环依赖报错 |
| 72 | 45 | private TenantService tenantService; |
| 73 | 46 | |
| 74 | - @Resource | |
| 75 | - private MenuProducer menuProducer; | |
| 76 | - | |
| 77 | - /** | |
| 78 | - * 初始化 {@link #menuCache} 和 {@link #permissionMenuCache} 缓存 | |
| 79 | - */ | |
| 80 | - @Override | |
| 81 | - @PostConstruct | |
| 82 | - public synchronized void initLocalCache() { | |
| 83 | - // 第一步:查询数据 | |
| 84 | - List<MenuDO> menuList = menuMapper.selectList(); | |
| 85 | - log.info("[initLocalCache][缓存菜单,数量为:{}]", menuList.size()); | |
| 86 | - | |
| 87 | - // 第二步:构建缓存 | |
| 88 | - ImmutableMap.Builder<Long, MenuDO> menuCacheBuilder = ImmutableMap.builder(); | |
| 89 | - ImmutableMultimap.Builder<String, MenuDO> permMenuCacheBuilder = ImmutableMultimap.builder(); | |
| 90 | - menuList.forEach(menuDO -> { | |
| 91 | - menuCacheBuilder.put(menuDO.getId(), menuDO); | |
| 92 | - if (StrUtil.isNotEmpty(menuDO.getPermission())) { // 会存在 permission 为 null 的情况,导致 put 报 NPE 异常 | |
| 93 | - permMenuCacheBuilder.put(menuDO.getPermission(), menuDO); | |
| 94 | - } | |
| 95 | - }); | |
| 96 | - menuCache = menuCacheBuilder.build(); | |
| 97 | - permissionMenuCache = permMenuCacheBuilder.build(); | |
| 98 | - } | |
| 99 | - | |
| 100 | 47 | @Override |
| 48 | + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#reqVO.permission") | |
| 101 | 49 | public Long createMenu(MenuCreateReqVO reqVO) { |
| 102 | 50 | // 校验父菜单存在 |
| 103 | 51 | validateParentMenu(reqVO.getParentId(), null); |
| ... | ... | @@ -108,13 +56,13 @@ public class MenuServiceImpl implements MenuService { |
| 108 | 56 | MenuDO menu = MenuConvert.INSTANCE.convert(reqVO); |
| 109 | 57 | initMenuProperty(menu); |
| 110 | 58 | menuMapper.insert(menu); |
| 111 | - // 发送刷新消息 | |
| 112 | - menuProducer.sendMenuRefreshMessage(); | |
| 113 | 59 | // 返回 |
| 114 | 60 | return menu.getId(); |
| 115 | 61 | } |
| 116 | 62 | |
| 117 | 63 | @Override |
| 64 | + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, | |
| 65 | + allEntries = true) // allEntries 清空所有缓存,因为 permission 如果变更,涉及到新老两个 permission。直接清理,简单有效 | |
| 118 | 66 | public void updateMenu(MenuUpdateReqVO reqVO) { |
| 119 | 67 | // 校验更新的菜单是否存在 |
| 120 | 68 | if (menuMapper.selectById(reqVO.getId()) == null) { |
| ... | ... | @@ -129,34 +77,25 @@ public class MenuServiceImpl implements MenuService { |
| 129 | 77 | MenuDO updateObject = MenuConvert.INSTANCE.convert(reqVO); |
| 130 | 78 | initMenuProperty(updateObject); |
| 131 | 79 | menuMapper.updateById(updateObject); |
| 132 | - // 发送刷新消息 | |
| 133 | - menuProducer.sendMenuRefreshMessage(); | |
| 134 | 80 | } |
| 135 | 81 | |
| 136 | 82 | @Override |
| 137 | 83 | @Transactional(rollbackFor = Exception.class) |
| 138 | - public void deleteMenu(Long menuId) { | |
| 84 | + @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, | |
| 85 | + allEntries = true) // allEntries 清空所有缓存,因为此时不知道 id 对应的 permission 是多少。直接清理,简单有效 | |
| 86 | + public void deleteMenu(Long id) { | |
| 139 | 87 | // 校验是否还有子菜单 |
| 140 | - if (menuMapper.selectCountByParentId(menuId) > 0) { | |
| 88 | + if (menuMapper.selectCountByParentId(id) > 0) { | |
| 141 | 89 | throw exception(MENU_EXISTS_CHILDREN); |
| 142 | 90 | } |
| 143 | 91 | // 校验删除的菜单是否存在 |
| 144 | - if (menuMapper.selectById(menuId) == null) { | |
| 92 | + if (menuMapper.selectById(id) == null) { | |
| 145 | 93 | throw exception(MENU_NOT_EXISTS); |
| 146 | 94 | } |
| 147 | 95 | // 标记删除 |
| 148 | - menuMapper.deleteById(menuId); | |
| 96 | + menuMapper.deleteById(id); | |
| 149 | 97 | // 删除授予给角色的权限 |
| 150 | - permissionService.processMenuDeleted(menuId); | |
| 151 | - // 发送刷新消息. 注意,需要事务提交后,在进行发送刷新消息。不然 db 还未提交,结果缓存先刷新了 | |
| 152 | - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { | |
| 153 | - | |
| 154 | - @Override | |
| 155 | - public void afterCommit() { | |
| 156 | - menuProducer.sendMenuRefreshMessage(); | |
| 157 | - } | |
| 158 | - | |
| 159 | - }); | |
| 98 | + permissionService.processMenuDeleted(id); | |
| 160 | 99 | } |
| 161 | 100 | |
| 162 | 101 | @Override |
| ... | ... | @@ -178,49 +117,31 @@ public class MenuServiceImpl implements MenuService { |
| 178 | 117 | } |
| 179 | 118 | |
| 180 | 119 | @Override |
| 181 | - public List<MenuDO> getMenuListFromCache(Collection<Integer> menuTypes, Collection<Integer> menusStatuses) { | |
| 182 | - // 任一一个参数为空,则返回空 | |
| 183 | - if (CollectionUtils.isAnyEmpty(menuTypes, menusStatuses)) { | |
| 184 | - return Collections.emptyList(); | |
| 185 | - } | |
| 186 | - // 创建新数组,避免缓存被修改 | |
| 187 | - return menuCache.values().stream().filter(menu -> menuTypes.contains(menu.getType()) | |
| 188 | - && menusStatuses.contains(menu.getStatus())) | |
| 189 | - .collect(Collectors.toList()); | |
| 190 | - } | |
| 191 | - | |
| 192 | - @Override | |
| 193 | - public List<MenuDO> getMenuListFromCache(Collection<Long> menuIds, Collection<Integer> menuTypes, | |
| 194 | - Collection<Integer> menusStatuses) { | |
| 195 | - // 任一一个参数为空,则返回空 | |
| 196 | - if (CollectionUtils.isAnyEmpty(menuIds, menuTypes, menusStatuses)) { | |
| 197 | - return Collections.emptyList(); | |
| 198 | - } | |
| 199 | - return menuCache.values().stream().filter(menu -> menuIds.contains(menu.getId()) | |
| 200 | - && menuTypes.contains(menu.getType()) | |
| 201 | - && menusStatuses.contains(menu.getStatus())) | |
| 202 | - .collect(Collectors.toList()); | |
| 120 | + @Cacheable(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#permission") | |
| 121 | + public List<Long> getMenuIdListByPermissionFromCache(String permission) { | |
| 122 | + List<MenuDO> menus = menuMapper.selectListByPermission(permission); | |
| 123 | + return convertList(menus, MenuDO::getId); | |
| 203 | 124 | } |
| 204 | 125 | |
| 205 | 126 | @Override |
| 206 | - public List<MenuDO> getMenuListByPermissionFromCache(String permission) { | |
| 207 | - return new ArrayList<>(permissionMenuCache.get(permission)); | |
| 127 | + public MenuDO getMenu(Long id) { | |
| 128 | + return menuMapper.selectById(id); | |
| 208 | 129 | } |
| 209 | 130 | |
| 210 | 131 | @Override |
| 211 | - public MenuDO getMenu(Long id) { | |
| 212 | - return menuMapper.selectById(id); | |
| 132 | + public List<MenuDO> getMenuList(Collection<Long> ids) { | |
| 133 | + return menuMapper.selectBatchIds(ids); | |
| 213 | 134 | } |
| 214 | 135 | |
| 215 | 136 | /** |
| 216 | 137 | * 校验父菜单是否合法 |
| 217 | - * | |
| 138 | + * <p> | |
| 218 | 139 | * 1. 不能设置自己为父菜单 |
| 219 | 140 | * 2. 父菜单不存在 |
| 220 | 141 | * 3. 父菜单必须是 {@link MenuTypeEnum#MENU} 菜单类型 |
| 221 | 142 | * |
| 222 | 143 | * @param parentId 父菜单编号 |
| 223 | - * @param childId 当前菜单编号 | |
| 144 | + * @param childId 当前菜单编号 | |
| 224 | 145 | */ |
| 225 | 146 | @VisibleForTesting |
| 226 | 147 | void validateParentMenu(Long parentId, Long childId) { |
| ... | ... | @@ -238,19 +159,19 @@ public class MenuServiceImpl implements MenuService { |
| 238 | 159 | } |
| 239 | 160 | // 父菜单必须是目录或者菜单类型 |
| 240 | 161 | if (!MenuTypeEnum.DIR.getType().equals(menu.getType()) |
| 241 | - && !MenuTypeEnum.MENU.getType().equals(menu.getType())) { | |
| 162 | + && !MenuTypeEnum.MENU.getType().equals(menu.getType())) { | |
| 242 | 163 | throw exception(MENU_PARENT_NOT_DIR_OR_MENU); |
| 243 | 164 | } |
| 244 | 165 | } |
| 245 | 166 | |
| 246 | 167 | /** |
| 247 | 168 | * 校验菜单是否合法 |
| 248 | - * | |
| 169 | + * <p> | |
| 249 | 170 | * 1. 校验相同父菜单编号下,是否存在相同的菜单名 |
| 250 | 171 | * |
| 251 | - * @param name 菜单名字 | |
| 172 | + * @param name 菜单名字 | |
| 252 | 173 | * @param parentId 父菜单编号 |
| 253 | - * @param id 菜单编号 | |
| 174 | + * @param id 菜单编号 | |
| 254 | 175 | */ |
| 255 | 176 | @VisibleForTesting |
| 256 | 177 | void validateMenu(Long parentId, String name, Long id) { |
| ... | ... | @@ -269,7 +190,7 @@ public class MenuServiceImpl implements MenuService { |
| 269 | 190 | |
| 270 | 191 | /** |
| 271 | 192 | * 初始化菜单的通用属性。 |
| 272 | - * | |
| 193 | + * <p> | |
| 273 | 194 | * 例如说,只有目录或者菜单类型的菜单,才设置 icon |
| 274 | 195 | * |
| 275 | 196 | * @param menu 菜单 | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionService.java
| 1 | 1 | package cn.iocoder.yudao.module.system.service.permission; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; |
| 4 | -import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; | |
| 5 | -import org.springframework.lang.Nullable; | |
| 6 | 4 | |
| 7 | 5 | import java.util.Collection; |
| 8 | -import java.util.List; | |
| 9 | 6 | import java.util.Set; |
| 10 | 7 | |
| 8 | +import static java.util.Collections.singleton; | |
| 9 | + | |
| 11 | 10 | /** |
| 12 | 11 | * 权限 Service 接口 |
| 13 | - * | |
| 12 | + * <p> | |
| 14 | 13 | * 提供用户-角色、角色-菜单、角色-部门的关联权限处理 |
| 15 | 14 | * |
| 16 | 15 | * @author 芋道源码 |
| ... | ... | @@ -18,118 +17,123 @@ import java.util.Set; |
| 18 | 17 | public interface PermissionService { |
| 19 | 18 | |
| 20 | 19 | /** |
| 21 | - * 初始化权限的本地缓存 | |
| 20 | + * 判断是否有权限,任一一个即可 | |
| 21 | + * | |
| 22 | + * @param userId 用户编号 | |
| 23 | + * @param permissions 权限 | |
| 24 | + * @return 是否 | |
| 22 | 25 | */ |
| 23 | - void initLocalCache(); | |
| 26 | + boolean hasAnyPermissions(Long userId, String... permissions); | |
| 24 | 27 | |
| 25 | 28 | /** |
| 26 | - * 获得角色们拥有的菜单列表,从缓存中获取 | |
| 27 | - * | |
| 28 | - * 任一参数为空时,则返回为空 | |
| 29 | + * 判断是否有角色,任一一个即可 | |
| 29 | 30 | * |
| 30 | - * @param roleIds 角色编号数组 | |
| 31 | - * @param menuTypes 菜单类型数组 | |
| 32 | - * @param menusStatuses 菜单状态数组 | |
| 33 | - * @return 菜单列表 | |
| 31 | + * @param roles 角色数组 | |
| 32 | + * @return 是否 | |
| 34 | 33 | */ |
| 35 | - List<MenuDO> getRoleMenuListFromCache(Collection<Long> roleIds, Collection<Integer> menuTypes, | |
| 36 | - Collection<Integer> menusStatuses); | |
| 34 | + boolean hasAnyRoles(Long userId, String... roles); | |
| 35 | + | |
| 36 | + // ========== 角色-菜单的相关方法 ========== | |
| 37 | 37 | |
| 38 | 38 | /** |
| 39 | - * 获得用户拥有的角色编号集合,从缓存中获取 | |
| 39 | + * 设置角色菜单 | |
| 40 | 40 | * |
| 41 | - * @param userId 用户编号 | |
| 42 | - * @param roleStatuses 角色状态集合. 允许为空,为空时不过滤 | |
| 43 | - * @return 角色编号集合 | |
| 41 | + * @param roleId 角色编号 | |
| 42 | + * @param menuIds 菜单编号集合 | |
| 44 | 43 | */ |
| 45 | - Set<Long> getUserRoleIdsFromCache(Long userId, @Nullable Collection<Integer> roleStatuses); | |
| 44 | + void assignRoleMenu(Long roleId, Set<Long> menuIds); | |
| 46 | 45 | |
| 47 | 46 | /** |
| 48 | - * 获得角色拥有的菜单编号集合 | |
| 47 | + * 处理角色删除时,删除关联授权数据 | |
| 49 | 48 | * |
| 50 | 49 | * @param roleId 角色编号 |
| 51 | - * @return 菜单编号集合 | |
| 52 | 50 | */ |
| 53 | - Set<Long> getRoleMenuIds(Long roleId); | |
| 51 | + void processRoleDeleted(Long roleId); | |
| 54 | 52 | |
| 55 | 53 | /** |
| 56 | - * 获得拥有多个角色的用户编号集合 | |
| 54 | + * 处理菜单删除时,删除关联授权数据 | |
| 57 | 55 | * |
| 58 | - * @param roleIds 角色编号集合 | |
| 59 | - * @return 用户编号集合 | |
| 56 | + * @param menuId 菜单编号 | |
| 60 | 57 | */ |
| 61 | - Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds); | |
| 58 | + void processMenuDeleted(Long menuId); | |
| 62 | 59 | |
| 63 | 60 | /** |
| 64 | - * 设置角色菜单 | |
| 61 | + * 获得角色拥有的菜单编号集合 | |
| 65 | 62 | * |
| 66 | 63 | * @param roleId 角色编号 |
| 67 | - * @param menuIds 菜单编号集合 | |
| 64 | + * @return 菜单编号集合 | |
| 68 | 65 | */ |
| 69 | - void assignRoleMenu(Long roleId, Set<Long> menuIds); | |
| 66 | + default Set<Long> getRoleMenuListByRoleId(Long roleId) { | |
| 67 | + return getRoleMenuListByRoleId(singleton(roleId)); | |
| 68 | + } | |
| 70 | 69 | |
| 71 | 70 | /** |
| 72 | - * 获得用户拥有的角色编号集合 | |
| 71 | + * 获得角色们拥有的菜单编号集合 | |
| 73 | 72 | * |
| 74 | - * @param userId 用户编号 | |
| 75 | - * @return 角色编号集合 | |
| 73 | + * @param roleIds 角色编号数组 | |
| 74 | + * @return 菜单编号集合 | |
| 76 | 75 | */ |
| 77 | - Set<Long> getUserRoleIdListByUserId(Long userId); | |
| 76 | + Set<Long> getRoleMenuListByRoleId(Collection<Long> roleIds); | |
| 78 | 77 | |
| 79 | 78 | /** |
| 80 | - * 设置用户角色 | |
| 79 | + * 获得拥有指定菜单的角色编号数组,从缓存中获取 | |
| 81 | 80 | * |
| 82 | - * @param userId 角色编号 | |
| 83 | - * @param roleIds 角色编号集合 | |
| 81 | + * @param menuId 菜单编号 | |
| 82 | + * @return 角色编号数组 | |
| 84 | 83 | */ |
| 85 | - void assignUserRole(Long userId, Set<Long> roleIds); | |
| 84 | + Set<Long> getMenuRoleIdListByMenuIdFromCache(Long menuId); | |
| 85 | + | |
| 86 | + // ========== 用户-角色的相关方法 ========== | |
| 86 | 87 | |
| 87 | 88 | /** |
| 88 | - * 设置角色的数据权限 | |
| 89 | + * 设置用户角色 | |
| 89 | 90 | * |
| 90 | - * @param roleId 角色编号 | |
| 91 | - * @param dataScope 数据范围 | |
| 92 | - * @param dataScopeDeptIds 部门编号数组 | |
| 91 | + * @param userId 角色编号 | |
| 92 | + * @param roleIds 角色编号集合 | |
| 93 | 93 | */ |
| 94 | - void assignRoleDataScope(Long roleId, Integer dataScope, Set<Long> dataScopeDeptIds); | |
| 94 | + void assignUserRole(Long userId, Set<Long> roleIds); | |
| 95 | 95 | |
| 96 | 96 | /** |
| 97 | - * 处理角色删除时,删除关联授权数据 | |
| 97 | + * 处理用户删除时,删除关联授权数据 | |
| 98 | 98 | * |
| 99 | - * @param roleId 角色编号 | |
| 99 | + * @param userId 用户编号 | |
| 100 | 100 | */ |
| 101 | - void processRoleDeleted(Long roleId); | |
| 101 | + void processUserDeleted(Long userId); | |
| 102 | 102 | |
| 103 | 103 | /** |
| 104 | - * 处理菜单删除时,删除关联授权数据 | |
| 104 | + * 获得拥有多个角色的用户编号集合 | |
| 105 | 105 | * |
| 106 | - * @param menuId 菜单编号 | |
| 106 | + * @param roleIds 角色编号集合 | |
| 107 | + * @return 用户编号集合 | |
| 107 | 108 | */ |
| 108 | - void processMenuDeleted(Long menuId); | |
| 109 | + Set<Long> getUserRoleIdListByRoleId(Collection<Long> roleIds); | |
| 109 | 110 | |
| 110 | 111 | /** |
| 111 | - * 处理用户删除是,删除关联授权数据 | |
| 112 | + * 获得用户拥有的角色编号集合 | |
| 112 | 113 | * |
| 113 | 114 | * @param userId 用户编号 |
| 115 | + * @return 角色编号集合 | |
| 114 | 116 | */ |
| 115 | - void processUserDeleted(Long userId); | |
| 117 | + Set<Long> getUserRoleIdListByUserId(Long userId); | |
| 116 | 118 | |
| 117 | 119 | /** |
| 118 | - * 判断是否有权限,任一一个即可 | |
| 120 | + * 获得用户拥有的角色编号集合,从缓存中获取 | |
| 119 | 121 | * |
| 120 | 122 | * @param userId 用户编号 |
| 121 | - * @param permissions 权限 | |
| 122 | - * @return 是否 | |
| 123 | + * @return 角色编号集合 | |
| 123 | 124 | */ |
| 124 | - boolean hasAnyPermissions(Long userId, String... permissions); | |
| 125 | + Set<Long> getUserRoleIdListByUserIdFromCache(Long userId); | |
| 126 | + | |
| 127 | + // ========== 用户-部门的相关方法 ========== | |
| 125 | 128 | |
| 126 | 129 | /** |
| 127 | - * 判断是否有角色,任一一个即可 | |
| 130 | + * 设置角色的数据权限 | |
| 128 | 131 | * |
| 129 | - * @param roles 角色数组 | |
| 130 | - * @return 是否 | |
| 132 | + * @param roleId 角色编号 | |
| 133 | + * @param dataScope 数据范围 | |
| 134 | + * @param dataScopeDeptIds 部门编号数组 | |
| 131 | 135 | */ |
| 132 | - boolean hasAnyRoles(Long userId, String... roles); | |
| 136 | + void assignRoleDataScope(Long roleId, Integer dataScope, Set<Long> dataScopeDeptIds); | |
| 133 | 137 | |
| 134 | 138 | /** |
| 135 | 139 | * 获得登陆用户的部门数据权限 | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java
| ... | ... | @@ -3,45 +3,38 @@ package cn.iocoder.yudao.module.system.service.permission; |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.collection.CollectionUtil; |
| 5 | 5 | import cn.hutool.core.util.ArrayUtil; |
| 6 | +import cn.hutool.extra.spring.SpringUtil; | |
| 6 | 7 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 7 | 8 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 8 | -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | |
| 9 | -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 10 | 9 | import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; |
| 11 | -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; | |
| 12 | -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | |
| 13 | 10 | import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; |
| 14 | -import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; | |
| 15 | 11 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; |
| 16 | 12 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; |
| 17 | 13 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO; |
| 18 | 14 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO; |
| 19 | 15 | import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper; |
| 20 | 16 | import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper; |
| 17 | +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; | |
| 21 | 18 | import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; |
| 22 | -import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer; | |
| 23 | 19 | import cn.iocoder.yudao.module.system.service.dept.DeptService; |
| 24 | 20 | import cn.iocoder.yudao.module.system.service.user.AdminUserService; |
| 21 | +import com.baomidou.dynamic.datasource.annotation.DSTransactional; | |
| 25 | 22 | import com.google.common.annotations.VisibleForTesting; |
| 26 | 23 | import com.google.common.base.Suppliers; |
| 27 | -import com.google.common.collect.ImmutableMultimap; | |
| 28 | -import com.google.common.collect.Multimap; | |
| 29 | 24 | import com.google.common.collect.Sets; |
| 30 | -import lombok.Getter; | |
| 31 | -import lombok.Setter; | |
| 32 | 25 | import lombok.extern.slf4j.Slf4j; |
| 26 | +import org.springframework.cache.annotation.CacheEvict; | |
| 27 | +import org.springframework.cache.annotation.Cacheable; | |
| 28 | +import org.springframework.cache.annotation.Caching; | |
| 33 | 29 | import org.springframework.stereotype.Service; |
| 34 | 30 | import org.springframework.transaction.annotation.Transactional; |
| 35 | -import org.springframework.transaction.support.TransactionSynchronization; | |
| 36 | -import org.springframework.transaction.support.TransactionSynchronizationManager; | |
| 37 | 31 | |
| 38 | -import javax.annotation.PostConstruct; | |
| 39 | 32 | import javax.annotation.Resource; |
| 40 | 33 | import java.util.*; |
| 41 | 34 | import java.util.function.Supplier; |
| 42 | 35 | |
| 43 | 36 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 44 | -import static java.util.Collections.singleton; | |
| 37 | +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | |
| 45 | 38 | |
| 46 | 39 | /** |
| 47 | 40 | * 权限 Service 实现类 |
| ... | ... | @@ -52,38 +45,6 @@ import static java.util.Collections.singleton; |
| 52 | 45 | @Slf4j |
| 53 | 46 | public class PermissionServiceImpl implements PermissionService { |
| 54 | 47 | |
| 55 | - /** | |
| 56 | - * 角色编号与菜单编号的缓存映射 | |
| 57 | - * key:角色编号 | |
| 58 | - * value:菜单编号的数组 | |
| 59 | - * | |
| 60 | - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | |
| 61 | - */ | |
| 62 | - @Getter | |
| 63 | - @Setter // 单元测试需要 | |
| 64 | - private volatile Multimap<Long, Long> roleMenuCache; | |
| 65 | - /** | |
| 66 | - * 菜单编号与角色编号的缓存映射 | |
| 67 | - * key:菜单编号 | |
| 68 | - * value:角色编号的数组 | |
| 69 | - * | |
| 70 | - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | |
| 71 | - */ | |
| 72 | - @Getter | |
| 73 | - @Setter // 单元测试需要 | |
| 74 | - private volatile Multimap<Long, Long> menuRoleCache; | |
| 75 | - | |
| 76 | - /** | |
| 77 | - * 用户编号与角色编号的缓存映射 | |
| 78 | - * key:用户编号 | |
| 79 | - * value:角色编号的数组 | |
| 80 | - * | |
| 81 | - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | |
| 82 | - */ | |
| 83 | - @Getter | |
| 84 | - @Setter // 单元测试需要 | |
| 85 | - private volatile Map<Long, Set<Long>> userRoleCache; | |
| 86 | - | |
| 87 | 48 | @Resource |
| 88 | 49 | private RoleMenuMapper roleMenuMapper; |
| 89 | 50 | @Resource |
| ... | ... | @@ -98,115 +59,89 @@ public class PermissionServiceImpl implements PermissionService { |
| 98 | 59 | @Resource |
| 99 | 60 | private AdminUserService userService; |
| 100 | 61 | |
| 101 | - @Resource | |
| 102 | - private PermissionProducer permissionProducer; | |
| 103 | - | |
| 104 | 62 | @Override |
| 105 | - @PostConstruct | |
| 106 | - public void initLocalCache() { | |
| 107 | - initLocalCacheForRoleMenu(); | |
| 108 | - initLocalCacheForUserRole(); | |
| 109 | - } | |
| 63 | + public boolean hasAnyPermissions(Long userId, String... permissions) { | |
| 64 | + // 如果为空,说明已经有权限 | |
| 65 | + if (ArrayUtil.isEmpty(permissions)) { | |
| 66 | + return true; | |
| 67 | + } | |
| 110 | 68 | |
| 111 | - /** | |
| 112 | - * 刷新 RoleMenu 本地缓存 | |
| 113 | - */ | |
| 114 | - @VisibleForTesting | |
| 115 | - void initLocalCacheForRoleMenu() { | |
| 116 | - // 注意:忽略自动多租户,因为要全局初始化缓存 | |
| 117 | - TenantUtils.executeIgnore(() -> { | |
| 118 | - // 第一步:查询数据 | |
| 119 | - List<RoleMenuDO> roleMenus = roleMenuMapper.selectList(); | |
| 120 | - log.info("[initLocalCacheForRoleMenu][缓存角色与菜单,数量为:{}]", roleMenus.size()); | |
| 121 | - | |
| 122 | - // 第二步:构建缓存 | |
| 123 | - ImmutableMultimap.Builder<Long, Long> roleMenuCacheBuilder = ImmutableMultimap.builder(); | |
| 124 | - ImmutableMultimap.Builder<Long, Long> menuRoleCacheBuilder = ImmutableMultimap.builder(); | |
| 125 | - roleMenus.forEach(roleMenuDO -> { | |
| 126 | - roleMenuCacheBuilder.put(roleMenuDO.getRoleId(), roleMenuDO.getMenuId()); | |
| 127 | - menuRoleCacheBuilder.put(roleMenuDO.getMenuId(), roleMenuDO.getRoleId()); | |
| 128 | - }); | |
| 129 | - roleMenuCache = roleMenuCacheBuilder.build(); | |
| 130 | - menuRoleCache = menuRoleCacheBuilder.build(); | |
| 131 | - }); | |
| 69 | + // 获得当前登录的角色。如果为空,说明没有权限 | |
| 70 | + List<RoleDO> roles = getEnableUserRoleListByUserIdFromCache(userId); | |
| 71 | + if (CollUtil.isEmpty(roles)) { | |
| 72 | + return false; | |
| 73 | + } | |
| 74 | + | |
| 75 | + // 情况一:遍历判断每个权限,如果有一满足,说明有权限 | |
| 76 | + for (String permission : permissions) { | |
| 77 | + if (hasAnyPermission(roles, permission)) { | |
| 78 | + return true; | |
| 79 | + } | |
| 80 | + } | |
| 81 | + | |
| 82 | + // 情况二:如果是超管,也说明有权限 | |
| 83 | + return roleService.hasAnySuperAdmin(convertSet(roles, RoleDO::getId)); | |
| 132 | 84 | } |
| 133 | 85 | |
| 134 | 86 | /** |
| 135 | - * 刷新 UserRole 本地缓存 | |
| 87 | + * 判断指定角色,是否拥有该 permission 权限 | |
| 88 | + * | |
| 89 | + * @param roles 指定角色数组 | |
| 90 | + * @param permission 权限标识 | |
| 91 | + * @return 是否拥有 | |
| 136 | 92 | */ |
| 137 | - @VisibleForTesting | |
| 138 | - void initLocalCacheForUserRole() { | |
| 139 | - // 注意:忽略自动多租户,因为要全局初始化缓存 | |
| 140 | - TenantUtils.executeIgnore(() -> { | |
| 141 | - // 第一步:加载数据 | |
| 142 | - List<UserRoleDO> userRoles = userRoleMapper.selectList(); | |
| 143 | - log.info("[initLocalCacheForUserRole][缓存用户与角色,数量为:{}]", userRoles.size()); | |
| 144 | - | |
| 145 | - // 第二步:构建缓存。 | |
| 146 | - ImmutableMultimap.Builder<Long, Long> userRoleCacheBuilder = ImmutableMultimap.builder(); | |
| 147 | - userRoles.forEach(userRoleDO -> userRoleCacheBuilder.put(userRoleDO.getUserId(), userRoleDO.getRoleId())); | |
| 148 | - userRoleCache = CollectionUtils.convertMultiMap2(userRoles, UserRoleDO::getUserId, UserRoleDO::getRoleId); | |
| 149 | - }); | |
| 150 | - } | |
| 151 | - | |
| 152 | - @Override | |
| 153 | - public List<MenuDO> getRoleMenuListFromCache(Collection<Long> roleIds, Collection<Integer> menuTypes, | |
| 154 | - Collection<Integer> menusStatuses) { | |
| 155 | - // 任一一个参数为空时,不返回任何菜单 | |
| 156 | - if (CollectionUtils.isAnyEmpty(roleIds, menuTypes, menusStatuses)) { | |
| 157 | - return Collections.emptyList(); | |
| 93 | + private boolean hasAnyPermission(List<RoleDO> roles, String permission) { | |
| 94 | + List<Long> menuIds = menuService.getMenuIdListByPermissionFromCache(permission); | |
| 95 | + // 采用严格模式,如果权限找不到对应的 Menu 的话,也认为没有权限 | |
| 96 | + if (CollUtil.isEmpty(menuIds)) { | |
| 97 | + return false; | |
| 158 | 98 | } |
| 159 | 99 | |
| 160 | - // 判断角色是否包含超级管理员。如果是超级管理员,获取到全部 | |
| 161 | - List<RoleDO> roleList = roleService.getRoleListFromCache(roleIds); | |
| 162 | - if (roleService.hasAnySuperAdmin(roleList)) { | |
| 163 | - return menuService.getMenuListFromCache(menuTypes, menusStatuses); | |
| 100 | + // 判断是否有权限 | |
| 101 | + Set<Long> roleIds = convertSet(roles, RoleDO::getId); | |
| 102 | + for (Long menuId : menuIds) { | |
| 103 | + // 获得拥有该菜单的角色编号集合 | |
| 104 | + Set<Long> menuRoleIds = getSelf().getMenuRoleIdListByMenuIdFromCache(menuId); | |
| 105 | + // 如果有交集,说明有权限 | |
| 106 | + if (CollUtil.containsAny(menuRoleIds, roleIds)) { | |
| 107 | + return true; | |
| 108 | + } | |
| 164 | 109 | } |
| 165 | - | |
| 166 | - // 获得角色拥有的菜单关联 | |
| 167 | - List<Long> menuIds = MapUtils.getList(roleMenuCache, roleIds); | |
| 168 | - return menuService.getMenuListFromCache(menuIds, menuTypes, menusStatuses); | |
| 110 | + return false; | |
| 169 | 111 | } |
| 170 | 112 | |
| 171 | 113 | @Override |
| 172 | - public Set<Long> getUserRoleIdsFromCache(Long userId, Collection<Integer> roleStatuses) { | |
| 173 | - Set<Long> cacheRoleIds = userRoleCache.get(userId); | |
| 174 | - // 创建用户的时候没有分配角色,会存在空指针异常 | |
| 175 | - if (CollUtil.isEmpty(cacheRoleIds)) { | |
| 176 | - return Collections.emptySet(); | |
| 177 | - } | |
| 178 | - Set<Long> roleIds = new HashSet<>(cacheRoleIds); | |
| 179 | - // 过滤角色状态 | |
| 180 | - if (CollectionUtil.isNotEmpty(roleStatuses)) { | |
| 181 | - roleIds.removeIf(roleId -> { | |
| 182 | - RoleDO role = roleService.getRoleFromCache(roleId); | |
| 183 | - return role == null || !roleStatuses.contains(role.getStatus()); | |
| 184 | - }); | |
| 114 | + public boolean hasAnyRoles(Long userId, String... roles) { | |
| 115 | + // 如果为空,说明已经有权限 | |
| 116 | + if (ArrayUtil.isEmpty(roles)) { | |
| 117 | + return true; | |
| 185 | 118 | } |
| 186 | - return roleIds; | |
| 187 | - } | |
| 188 | 119 | |
| 189 | - @Override | |
| 190 | - public Set<Long> getRoleMenuIds(Long roleId) { | |
| 191 | - // 如果是管理员的情况下,获取全部菜单编号 | |
| 192 | - if (roleService.hasAnySuperAdmin(Collections.singleton(roleId))) { | |
| 193 | - return convertSet(menuService.getMenuList(), MenuDO::getId); | |
| 120 | + // 获得当前登录的角色。如果为空,说明没有权限 | |
| 121 | + List<RoleDO> roleList = getEnableUserRoleListByUserIdFromCache(userId); | |
| 122 | + if (CollUtil.isEmpty(roleList)) { | |
| 123 | + return false; | |
| 194 | 124 | } |
| 195 | - // 如果是非管理员的情况下,获得拥有的菜单编号 | |
| 196 | - return convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId); | |
| 125 | + | |
| 126 | + // 判断是否有角色 | |
| 127 | + Set<String> userRoles = convertSet(roleList, RoleDO::getCode); | |
| 128 | + return CollUtil.containsAny(userRoles, Sets.newHashSet(roles)); | |
| 197 | 129 | } |
| 198 | 130 | |
| 131 | + // ========== 角色-菜单的相关方法 ========== | |
| 132 | + | |
| 199 | 133 | @Override |
| 200 | - @Transactional(rollbackFor = Exception.class) | |
| 134 | + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 | |
| 135 | + @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, | |
| 136 | + allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快 | |
| 201 | 137 | public void assignRoleMenu(Long roleId, Set<Long> menuIds) { |
| 202 | 138 | // 获得角色拥有菜单编号 |
| 203 | - Set<Long> dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), | |
| 204 | - RoleMenuDO::getMenuId); | |
| 139 | + Set<Long> dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId); | |
| 205 | 140 | // 计算新增和删除的菜单编号 |
| 206 | 141 | Collection<Long> createMenuIds = CollUtil.subtract(menuIds, dbMenuIds); |
| 207 | 142 | Collection<Long> deleteMenuIds = CollUtil.subtract(dbMenuIds, menuIds); |
| 208 | 143 | // 执行新增和删除。对于已经授权的菜单,不用做任何处理 |
| 209 | - if (!CollectionUtil.isEmpty(createMenuIds)) { | |
| 144 | + if (CollUtil.isNotEmpty(createMenuIds)) { | |
| 210 | 145 | roleMenuMapper.insertBatch(CollectionUtils.convertList(createMenuIds, menuId -> { |
| 211 | 146 | RoleMenuDO entity = new RoleMenuDO(); |
| 212 | 147 | entity.setRoleId(roleId); |
| ... | ... | @@ -214,34 +149,57 @@ public class PermissionServiceImpl implements PermissionService { |
| 214 | 149 | return entity; |
| 215 | 150 | })); |
| 216 | 151 | } |
| 217 | - if (!CollectionUtil.isEmpty(deleteMenuIds)) { | |
| 152 | + if (CollUtil.isNotEmpty(deleteMenuIds)) { | |
| 218 | 153 | roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds); |
| 219 | 154 | } |
| 220 | - // 发送刷新消息. 注意,需要事务提交后,在进行发送刷新消息。不然 db 还未提交,结果缓存先刷新了 | |
| 221 | - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { | |
| 155 | + } | |
| 222 | 156 | |
| 223 | - @Override | |
| 224 | - public void afterCommit() { | |
| 225 | - permissionProducer.sendRoleMenuRefreshMessage(); | |
| 226 | - } | |
| 157 | + @Override | |
| 158 | + @Transactional(rollbackFor = Exception.class) | |
| 159 | + @Caching(evict = { | |
| 160 | + @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, | |
| 161 | + allEntries = true), // allEntries 清空所有缓存,此处无法方便获得 roleId 对应的 menu 缓存们 | |
| 162 | + @CacheEvict(value = RedisKeyConstants.USER_ROLE_ID_LIST, | |
| 163 | + allEntries = true) // allEntries 清空所有缓存,此处无法方便获得 roleId 对应的 user 缓存们 | |
| 164 | + }) | |
| 165 | + public void processRoleDeleted(Long roleId) { | |
| 166 | + // 标记删除 UserRole | |
| 167 | + userRoleMapper.deleteListByRoleId(roleId); | |
| 168 | + // 标记删除 RoleMenu | |
| 169 | + roleMenuMapper.deleteListByRoleId(roleId); | |
| 170 | + } | |
| 227 | 171 | |
| 228 | - }); | |
| 172 | + @Override | |
| 173 | + @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, key = "#menuId") | |
| 174 | + public void processMenuDeleted(Long menuId) { | |
| 175 | + roleMenuMapper.deleteListByMenuId(menuId); | |
| 229 | 176 | } |
| 230 | 177 | |
| 231 | 178 | @Override |
| 232 | - public Set<Long> getUserRoleIdListByUserId(Long userId) { | |
| 233 | - return convertSet(userRoleMapper.selectListByUserId(userId), | |
| 234 | - UserRoleDO::getRoleId); | |
| 179 | + public Set<Long> getRoleMenuListByRoleId(Collection<Long> roleIds) { | |
| 180 | + if (CollUtil.isEmpty(roleIds)) { | |
| 181 | + return Collections.emptySet(); | |
| 182 | + } | |
| 183 | + | |
| 184 | + // 如果是管理员的情况下,获取全部菜单编号 | |
| 185 | + if (roleService.hasAnySuperAdmin(roleIds)) { | |
| 186 | + return convertSet(menuService.getMenuList(), MenuDO::getId); | |
| 187 | + } | |
| 188 | + // 如果是非管理员的情况下,获得拥有的菜单编号 | |
| 189 | + return convertSet(roleMenuMapper.selectListByRoleId(roleIds), RoleMenuDO::getMenuId); | |
| 235 | 190 | } |
| 236 | 191 | |
| 237 | 192 | @Override |
| 238 | - public Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds) { | |
| 239 | - return convertSet(userRoleMapper.selectListByRoleIds(roleIds), | |
| 240 | - UserRoleDO::getUserId); | |
| 193 | + @Cacheable(value = RedisKeyConstants.MENU_ROLE_ID_LIST, key = "#menuId") | |
| 194 | + public Set<Long> getMenuRoleIdListByMenuIdFromCache(Long menuId) { | |
| 195 | + return convertSet(roleMenuMapper.selectListByMenuId(menuId), RoleMenuDO::getRoleId); | |
| 241 | 196 | } |
| 242 | 197 | |
| 198 | + // ========== 用户-角色的相关方法 ========== | |
| 199 | + | |
| 243 | 200 | @Override |
| 244 | - @Transactional(rollbackFor = Exception.class) | |
| 201 | + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 | |
| 202 | + @CacheEvict(value = RedisKeyConstants.USER_ROLE_ID_LIST, key = "#userId") | |
| 245 | 203 | public void assignUserRole(Long userId, Set<Long> roleIds) { |
| 246 | 204 | // 获得角色拥有角色编号 |
| 247 | 205 | Set<Long> dbRoleIds = convertSet(userRoleMapper.selectListByUserId(userId), |
| ... | ... | @@ -261,137 +219,68 @@ public class PermissionServiceImpl implements PermissionService { |
| 261 | 219 | if (!CollectionUtil.isEmpty(deleteMenuIds)) { |
| 262 | 220 | userRoleMapper.deleteListByUserIdAndRoleIdIds(userId, deleteMenuIds); |
| 263 | 221 | } |
| 264 | - // 发送刷新消息. 注意,需要事务提交后,在进行发送刷新消息。不然 db 还未提交,结果缓存先刷新了 | |
| 265 | - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { | |
| 266 | - | |
| 267 | - @Override | |
| 268 | - public void afterCommit() { | |
| 269 | - permissionProducer.sendUserRoleRefreshMessage(); | |
| 270 | - } | |
| 271 | - | |
| 272 | - }); | |
| 273 | 222 | } |
| 274 | 223 | |
| 275 | 224 | @Override |
| 276 | - public void assignRoleDataScope(Long roleId, Integer dataScope, Set<Long> dataScopeDeptIds) { | |
| 277 | - roleService.updateRoleDataScope(roleId, dataScope, dataScopeDeptIds); | |
| 225 | + @CacheEvict(value = RedisKeyConstants.USER_ROLE_ID_LIST, key = "#userId") | |
| 226 | + public void processUserDeleted(Long userId) { | |
| 227 | + userRoleMapper.deleteListByUserId(userId); | |
| 278 | 228 | } |
| 279 | 229 | |
| 280 | 230 | @Override |
| 281 | - @Transactional(rollbackFor = Exception.class) | |
| 282 | - public void processRoleDeleted(Long roleId) { | |
| 283 | - // 标记删除 UserRole | |
| 284 | - userRoleMapper.deleteListByRoleId(roleId); | |
| 285 | - // 标记删除 RoleMenu | |
| 286 | - roleMenuMapper.deleteListByRoleId(roleId); | |
| 287 | - // 发送刷新消息. 注意,需要事务提交后,在进行发送刷新消息。不然 db 还未提交,结果缓存先刷新了 | |
| 288 | - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { | |
| 289 | - | |
| 290 | - @Override | |
| 291 | - public void afterCommit() { | |
| 292 | - permissionProducer.sendRoleMenuRefreshMessage(); | |
| 293 | - permissionProducer.sendUserRoleRefreshMessage(); | |
| 294 | - } | |
| 295 | - | |
| 296 | - }); | |
| 231 | + public Set<Long> getUserRoleIdListByUserId(Long userId) { | |
| 232 | + return convertSet(userRoleMapper.selectListByUserId(userId), UserRoleDO::getRoleId); | |
| 297 | 233 | } |
| 298 | 234 | |
| 299 | 235 | @Override |
| 300 | - @Transactional(rollbackFor = Exception.class) | |
| 301 | - public void processMenuDeleted(Long menuId) { | |
| 302 | - roleMenuMapper.deleteListByMenuId(menuId); | |
| 303 | - // 发送刷新消息. 注意,需要事务提交后,在进行发送刷新消息。不然 db 还未提交,结果缓存先刷新了 | |
| 304 | - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { | |
| 305 | - | |
| 306 | - @Override | |
| 307 | - public void afterCommit() { | |
| 308 | - permissionProducer.sendRoleMenuRefreshMessage(); | |
| 309 | - } | |
| 310 | - | |
| 311 | - }); | |
| 236 | + @Cacheable(value = RedisKeyConstants.USER_ROLE_ID_LIST, key = "#userId") | |
| 237 | + public Set<Long> getUserRoleIdListByUserIdFromCache(Long userId) { | |
| 238 | + return getUserRoleIdListByUserId(userId); | |
| 312 | 239 | } |
| 313 | 240 | |
| 314 | 241 | @Override |
| 315 | - @Transactional(rollbackFor = Exception.class) | |
| 316 | - public void processUserDeleted(Long userId) { | |
| 317 | - userRoleMapper.deleteListByUserId(userId); | |
| 318 | - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { | |
| 319 | - | |
| 320 | - @Override | |
| 321 | - public void afterCommit() { | |
| 322 | - permissionProducer.sendUserRoleRefreshMessage(); | |
| 323 | - } | |
| 324 | - | |
| 325 | - }); | |
| 242 | + public Set<Long> getUserRoleIdListByRoleId(Collection<Long> roleIds) { | |
| 243 | + return convertSet(userRoleMapper.selectListByRoleIds(roleIds), UserRoleDO::getUserId); | |
| 326 | 244 | } |
| 327 | 245 | |
| 328 | - @Override | |
| 329 | - public boolean hasAnyPermissions(Long userId, String... permissions) { | |
| 330 | - // 如果为空,说明已经有权限 | |
| 331 | - if (ArrayUtil.isEmpty(permissions)) { | |
| 332 | - return true; | |
| 333 | - } | |
| 334 | - | |
| 335 | - // 获得当前登录的角色。如果为空,说明没有权限 | |
| 336 | - Set<Long> roleIds = getUserRoleIdsFromCache(userId, singleton(CommonStatusEnum.ENABLE.getStatus())); | |
| 337 | - if (CollUtil.isEmpty(roleIds)) { | |
| 338 | - return false; | |
| 339 | - } | |
| 340 | - // 判断是否是超管。如果是,当然符合条件 | |
| 341 | - if (roleService.hasAnySuperAdmin(roleIds)) { | |
| 342 | - return true; | |
| 343 | - } | |
| 344 | - | |
| 345 | - // 遍历权限,判断是否有一个满足 | |
| 346 | - return Arrays.stream(permissions).anyMatch(permission -> { | |
| 347 | - List<MenuDO> menuList = menuService.getMenuListByPermissionFromCache(permission); | |
| 348 | - // 采用严格模式,如果权限找不到对应的 Menu 的话,认为 | |
| 349 | - if (CollUtil.isEmpty(menuList)) { | |
| 350 | - return false; | |
| 351 | - } | |
| 352 | - // 获得是否拥有该权限,任一一个 | |
| 353 | - return menuList.stream().anyMatch(menu -> CollUtil.containsAny(roleIds, | |
| 354 | - menuRoleCache.get(menu.getId()))); | |
| 355 | - }); | |
| 246 | + /** | |
| 247 | + * 获得用户拥有的角色,并且这些角色是开启状态的 | |
| 248 | + * | |
| 249 | + * @param userId 用户编号 | |
| 250 | + * @return 用户拥有的角色 | |
| 251 | + */ | |
| 252 | + @VisibleForTesting | |
| 253 | + List<RoleDO> getEnableUserRoleListByUserIdFromCache(Long userId) { | |
| 254 | + // 获得用户拥有的角色编号 | |
| 255 | + Set<Long> roleIds = getSelf().getUserRoleIdListByUserIdFromCache(userId); | |
| 256 | + // 获得角色数组,并移除被禁用的 | |
| 257 | + List<RoleDO> roles = roleService.getRoleListFromCache(roleIds); | |
| 258 | + roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); | |
| 259 | + return roles; | |
| 356 | 260 | } |
| 357 | 261 | |
| 358 | - @Override | |
| 359 | - public boolean hasAnyRoles(Long userId, String... roles) { | |
| 360 | - // 如果为空,说明已经有权限 | |
| 361 | - if (ArrayUtil.isEmpty(roles)) { | |
| 362 | - return true; | |
| 363 | - } | |
| 262 | + // ========== 用户-部门的相关方法 ========== | |
| 364 | 263 | |
| 365 | - // 获得当前登录的角色。如果为空,说明没有权限 | |
| 366 | - Set<Long> roleIds = getUserRoleIdsFromCache(userId, singleton(CommonStatusEnum.ENABLE.getStatus())); | |
| 367 | - if (CollUtil.isEmpty(roleIds)) { | |
| 368 | - return false; | |
| 369 | - } | |
| 370 | - // 判断是否是超管。如果是,当然符合条件 | |
| 371 | - if (roleService.hasAnySuperAdmin(roleIds)) { | |
| 372 | - return true; | |
| 373 | - } | |
| 374 | - Set<String> userRoles = convertSet(roleService.getRoleListFromCache(roleIds), | |
| 375 | - RoleDO::getCode); | |
| 376 | - return CollUtil.containsAny(userRoles, Sets.newHashSet(roles)); | |
| 264 | + @Override | |
| 265 | + public void assignRoleDataScope(Long roleId, Integer dataScope, Set<Long> dataScopeDeptIds) { | |
| 266 | + roleService.updateRoleDataScope(roleId, dataScope, dataScopeDeptIds); | |
| 377 | 267 | } |
| 378 | 268 | |
| 379 | 269 | @Override |
| 380 | 270 | @DataPermission(enable = false) // 关闭数据权限,不然就会出现递归获取数据权限的问题 |
| 381 | - @TenantIgnore // 忽略多租户的自动过滤。如果不忽略,会导致添加租户时,因为切换租户,导致获取不到 User。即使忽略,本身该方法不存在跨租户的操作,不会存在问题。 | |
| 382 | 271 | public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) { |
| 383 | 272 | // 获得用户的角色 |
| 384 | - Set<Long> roleIds = getUserRoleIdsFromCache(userId, singleton(CommonStatusEnum.ENABLE.getStatus())); | |
| 273 | + List<RoleDO> roles = getEnableUserRoleListByUserIdFromCache(userId); | |
| 274 | + | |
| 385 | 275 | // 如果角色为空,则只能查看自己 |
| 386 | 276 | DeptDataPermissionRespDTO result = new DeptDataPermissionRespDTO(); |
| 387 | - if (CollUtil.isEmpty(roleIds)) { | |
| 277 | + if (CollUtil.isEmpty(roles)) { | |
| 388 | 278 | result.setSelf(true); |
| 389 | 279 | return result; |
| 390 | 280 | } |
| 391 | - List<RoleDO> roles = roleService.getRoleListFromCache(roleIds); | |
| 392 | 281 | |
| 393 | 282 | // 获得用户的部门编号的缓存,通过 Guava 的 Suppliers 惰性求值,即有且仅有第一次发起 DB 的查询 |
| 394 | - Supplier<Long> userDeptIdCache = Suppliers.memoize(() -> userService.getUser(userId).getDeptId()); | |
| 283 | + Supplier<Long> userDeptId = Suppliers.memoize(() -> userService.getUser(userId).getDeptId()); | |
| 395 | 284 | // 遍历每个角色,计算 |
| 396 | 285 | for (RoleDO role : roles) { |
| 397 | 286 | // 为空时,跳过 |
| ... | ... | @@ -408,20 +297,19 @@ public class PermissionServiceImpl implements PermissionService { |
| 408 | 297 | CollUtil.addAll(result.getDeptIds(), role.getDataScopeDeptIds()); |
| 409 | 298 | // 自定义可见部门时,保证可以看到自己所在的部门。否则,一些场景下可能会有问题。 |
| 410 | 299 | // 例如说,登录时,基于 t_user 的 username 查询会可能被 dept_id 过滤掉 |
| 411 | - CollUtil.addAll(result.getDeptIds(), userDeptIdCache.get()); | |
| 300 | + CollUtil.addAll(result.getDeptIds(), userDeptId.get()); | |
| 412 | 301 | continue; |
| 413 | 302 | } |
| 414 | 303 | // 情况三,DEPT_ONLY |
| 415 | 304 | if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_ONLY.getScope())) { |
| 416 | - CollectionUtils.addIfNotNull(result.getDeptIds(), userDeptIdCache.get()); | |
| 305 | + CollectionUtils.addIfNotNull(result.getDeptIds(), userDeptId.get()); | |
| 417 | 306 | continue; |
| 418 | 307 | } |
| 419 | 308 | // 情况四,DEPT_DEPT_AND_CHILD |
| 420 | 309 | if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_AND_CHILD.getScope())) { |
| 421 | - List<DeptDO> depts = deptService.getDeptListByParentIdFromCache(userDeptIdCache.get(), true); | |
| 422 | - CollUtil.addAll(result.getDeptIds(), CollectionUtils.convertList(depts, DeptDO::getId)); | |
| 310 | + CollUtil.addAll(result.getDeptIds(), deptService.getChildDeptIdListFromCache(userDeptId.get())); | |
| 423 | 311 | // 添加本身部门编号 |
| 424 | - CollUtil.addAll(result.getDeptIds(), userDeptIdCache.get()); | |
| 312 | + CollUtil.addAll(result.getDeptIds(), userDeptId.get()); | |
| 425 | 313 | continue; |
| 426 | 314 | } |
| 427 | 315 | // 情况五,SELF |
| ... | ... | @@ -430,9 +318,18 @@ public class PermissionServiceImpl implements PermissionService { |
| 430 | 318 | continue; |
| 431 | 319 | } |
| 432 | 320 | // 未知情况,error log 即可 |
| 433 | - log.error("[getDeptDataPermission][LoginUser({}) role({}) 无法处理]", userId, JsonUtils.toJsonString(result)); | |
| 321 | + log.error("[getDeptDataPermission][LoginUser({}) role({}) 无法处理]", userId, toJsonString(result)); | |
| 434 | 322 | } |
| 435 | 323 | return result; |
| 436 | 324 | } |
| 437 | 325 | |
| 326 | + /** | |
| 327 | + * 获得自身的代理对象,解决 AOP 生效问题 | |
| 328 | + * | |
| 329 | + * @return 自己 | |
| 330 | + */ | |
| 331 | + private PermissionServiceImpl getSelf() { | |
| 332 | + return SpringUtil.getBean(getClass()); | |
| 333 | + } | |
| 334 | + | |
| 438 | 335 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleService.java
| ... | ... | @@ -6,7 +6,6 @@ import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleEx |
| 6 | 6 | import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO; |
| 7 | 7 | import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleUpdateReqVO; |
| 8 | 8 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; |
| 9 | -import org.springframework.lang.Nullable; | |
| 10 | 9 | |
| 11 | 10 | import javax.validation.Valid; |
| 12 | 11 | import java.util.Collection; |
| ... | ... | @@ -21,11 +20,6 @@ import java.util.Set; |
| 21 | 20 | public interface RoleService { |
| 22 | 21 | |
| 23 | 22 | /** |
| 24 | - * 初始化角色的本地缓存 | |
| 25 | - */ | |
| 26 | - void initLocalCache(); | |
| 27 | - | |
| 28 | - /** | |
| 29 | 23 | * 创建角色 |
| 30 | 24 | * |
| 31 | 25 | * @param reqVO 创建角色信息 |
| ... | ... | @@ -66,6 +60,14 @@ public interface RoleService { |
| 66 | 60 | void updateRoleDataScope(Long id, Integer dataScope, Set<Long> dataScopeDeptIds); |
| 67 | 61 | |
| 68 | 62 | /** |
| 63 | + * 获得角色 | |
| 64 | + * | |
| 65 | + * @param id 角色编号 | |
| 66 | + * @return 角色 | |
| 67 | + */ | |
| 68 | + RoleDO getRole(Long id); | |
| 69 | + | |
| 70 | + /** | |
| 69 | 71 | * 获得角色,从缓存中 |
| 70 | 72 | * |
| 71 | 73 | * @param id 角色编号 |
| ... | ... | @@ -76,10 +78,10 @@ public interface RoleService { |
| 76 | 78 | /** |
| 77 | 79 | * 获得角色列表 |
| 78 | 80 | * |
| 79 | - * @param statuses 筛选的状态。允许空,空时不筛选 | |
| 81 | + * @param ids 角色编号数组 | |
| 80 | 82 | * @return 角色列表 |
| 81 | 83 | */ |
| 82 | - List<RoleDO> getRoleListByStatus(@Nullable Collection<Integer> statuses); | |
| 84 | + List<RoleDO> getRoleList(Collection<Long> ids); | |
| 83 | 85 | |
| 84 | 86 | /** |
| 85 | 87 | * 获得角色数组,从缓存中 |
| ... | ... | @@ -90,30 +92,19 @@ public interface RoleService { |
| 90 | 92 | List<RoleDO> getRoleListFromCache(Collection<Long> ids); |
| 91 | 93 | |
| 92 | 94 | /** |
| 93 | - * 判断角色数组中,是否有超级管理员 | |
| 94 | - * | |
| 95 | - * @param roleList 角色数组 | |
| 96 | - * @return 是否有管理员 | |
| 97 | - */ | |
| 98 | - boolean hasAnySuperAdmin(Collection<RoleDO> roleList); | |
| 99 | - | |
| 100 | - /** | |
| 101 | - * 判断角色编号数组中,是否有管理员 | |
| 95 | + * 获得角色列表 | |
| 102 | 96 | * |
| 103 | - * @param ids 角色编号数组 | |
| 104 | - * @return 是否有管理员 | |
| 97 | + * @param statuses 筛选的状态 | |
| 98 | + * @return 角色列表 | |
| 105 | 99 | */ |
| 106 | - default boolean hasAnySuperAdmin(Set<Long> ids) { | |
| 107 | - return hasAnySuperAdmin(getRoleListFromCache(ids)); | |
| 108 | - } | |
| 100 | + List<RoleDO> getRoleListByStatus(Collection<Integer> statuses); | |
| 109 | 101 | |
| 110 | 102 | /** |
| 111 | - * 获得角色 | |
| 103 | + * 获得所有角色列表 | |
| 112 | 104 | * |
| 113 | - * @param id 角色编号 | |
| 114 | - * @return 角色 | |
| 105 | + * @return 角色列表 | |
| 115 | 106 | */ |
| 116 | - RoleDO getRole(Long id); | |
| 107 | + List<RoleDO> getRoleList(); | |
| 117 | 108 | |
| 118 | 109 | /** |
| 119 | 110 | * 获得角色分页 |
| ... | ... | @@ -132,6 +123,14 @@ public interface RoleService { |
| 132 | 123 | List<RoleDO> getRoleList(RoleExportReqVO reqVO); |
| 133 | 124 | |
| 134 | 125 | /** |
| 126 | + * 判断角色编号数组中,是否有管理员 | |
| 127 | + * | |
| 128 | + * @param ids 角色编号数组 | |
| 129 | + * @return 是否有管理员 | |
| 130 | + */ | |
| 131 | + boolean hasAnySuperAdmin(Collection<Long> ids); | |
| 132 | + | |
| 133 | + /** | |
| 135 | 134 | * 校验角色们是否有效。如下情况,视为无效: |
| 136 | 135 | * 1. 角色编号不存在 |
| 137 | 136 | * 2. 角色被禁用 | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java
| ... | ... | @@ -3,9 +3,9 @@ package cn.iocoder.yudao.module.system.service.permission; |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.collection.CollectionUtil; |
| 5 | 5 | import cn.hutool.core.util.ObjectUtil; |
| 6 | +import cn.hutool.extra.spring.SpringUtil; | |
| 6 | 7 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 7 | 8 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | |
| 9 | 9 | import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO; |
| 10 | 10 | import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO; |
| 11 | 11 | import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO; |
| ... | ... | @@ -13,26 +13,23 @@ import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleUp |
| 13 | 13 | import cn.iocoder.yudao.module.system.convert.permission.RoleConvert; |
| 14 | 14 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; |
| 15 | 15 | import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMapper; |
| 16 | +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; | |
| 16 | 17 | import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; |
| 17 | 18 | import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; |
| 18 | 19 | import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; |
| 19 | -import cn.iocoder.yudao.module.system.mq.producer.permission.RoleProducer; | |
| 20 | 20 | import com.google.common.annotations.VisibleForTesting; |
| 21 | -import lombok.Getter; | |
| 22 | 21 | import lombok.extern.slf4j.Slf4j; |
| 23 | -import org.springframework.lang.Nullable; | |
| 22 | +import org.springframework.cache.annotation.CacheEvict; | |
| 23 | +import org.springframework.cache.annotation.Cacheable; | |
| 24 | 24 | import org.springframework.stereotype.Service; |
| 25 | 25 | import org.springframework.transaction.annotation.Transactional; |
| 26 | -import org.springframework.transaction.support.TransactionSynchronization; | |
| 27 | -import org.springframework.transaction.support.TransactionSynchronizationManager; | |
| 28 | 26 | import org.springframework.util.StringUtils; |
| 29 | 27 | |
| 30 | -import javax.annotation.PostConstruct; | |
| 31 | 28 | import javax.annotation.Resource; |
| 32 | 29 | import java.util.*; |
| 33 | -import java.util.stream.Collectors; | |
| 34 | 30 | |
| 35 | 31 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 32 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 36 | 33 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; |
| 37 | 34 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; |
| 38 | 35 | |
| ... | ... | @@ -45,43 +42,14 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; |
| 45 | 42 | @Slf4j |
| 46 | 43 | public class RoleServiceImpl implements RoleService { |
| 47 | 44 | |
| 48 | - /** | |
| 49 | - * 角色缓存 | |
| 50 | - * key:角色编号 {@link RoleDO#getId()} | |
| 51 | - * | |
| 52 | - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | |
| 53 | - */ | |
| 54 | - @Getter | |
| 55 | - private volatile Map<Long, RoleDO> roleCache; | |
| 56 | - | |
| 57 | 45 | @Resource |
| 58 | 46 | private PermissionService permissionService; |
| 59 | 47 | |
| 60 | 48 | @Resource |
| 61 | 49 | private RoleMapper roleMapper; |
| 62 | 50 | |
| 63 | - @Resource | |
| 64 | - private RoleProducer roleProducer; | |
| 65 | - | |
| 66 | - /** | |
| 67 | - * 初始化 {@link #roleCache} 缓存 | |
| 68 | - */ | |
| 69 | - @Override | |
| 70 | - @PostConstruct | |
| 71 | - public void initLocalCache() { | |
| 72 | - // 注意:忽略自动多租户,因为要全局初始化缓存 | |
| 73 | - TenantUtils.executeIgnore(() -> { | |
| 74 | - // 第一步:查询数据 | |
| 75 | - List<RoleDO> roleList = roleMapper.selectList(); | |
| 76 | - log.info("[initLocalCache][缓存角色,数量为:{}]", roleList.size()); | |
| 77 | - | |
| 78 | - // 第二步:构建缓存 | |
| 79 | - roleCache = convertMap(roleList, RoleDO::getId); | |
| 80 | - }); | |
| 81 | - } | |
| 82 | - | |
| 83 | 51 | @Override |
| 84 | - @Transactional | |
| 52 | + @Transactional(rollbackFor = Exception.class) | |
| 85 | 53 | public Long createRole(RoleCreateReqVO reqVO, Integer type) { |
| 86 | 54 | // 校验角色 |
| 87 | 55 | validateRoleDuplicate(reqVO.getName(), reqVO.getCode(), null); |
| ... | ... | @@ -91,18 +59,12 @@ public class RoleServiceImpl implements RoleService { |
| 91 | 59 | role.setStatus(CommonStatusEnum.ENABLE.getStatus()); |
| 92 | 60 | role.setDataScope(DataScopeEnum.ALL.getScope()); // 默认可查看所有数据。原因是,可能一些项目不需要项目权限 |
| 93 | 61 | roleMapper.insert(role); |
| 94 | - // 发送刷新消息 | |
| 95 | - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { | |
| 96 | - @Override | |
| 97 | - public void afterCommit() { | |
| 98 | - roleProducer.sendRoleRefreshMessage(); | |
| 99 | - } | |
| 100 | - }); | |
| 101 | 62 | // 返回 |
| 102 | 63 | return role.getId(); |
| 103 | 64 | } |
| 104 | 65 | |
| 105 | 66 | @Override |
| 67 | + @CacheEvict(value = RedisKeyConstants.ROLE, key = "#reqVO.id") | |
| 106 | 68 | public void updateRole(RoleUpdateReqVO reqVO) { |
| 107 | 69 | // 校验是否可以更新 |
| 108 | 70 | validateRoleForUpdate(reqVO.getId()); |
| ... | ... | @@ -112,11 +74,10 @@ public class RoleServiceImpl implements RoleService { |
| 112 | 74 | // 更新到数据库 |
| 113 | 75 | RoleDO updateObj = RoleConvert.INSTANCE.convert(reqVO); |
| 114 | 76 | roleMapper.updateById(updateObj); |
| 115 | - // 发送刷新消息 | |
| 116 | - roleProducer.sendRoleRefreshMessage(); | |
| 117 | 77 | } |
| 118 | 78 | |
| 119 | 79 | @Override |
| 80 | + @CacheEvict(value = RedisKeyConstants.ROLE, key = "#id") | |
| 120 | 81 | public void updateRoleStatus(Long id, Integer status) { |
| 121 | 82 | // 校验是否可以更新 |
| 122 | 83 | validateRoleForUpdate(id); |
| ... | ... | @@ -124,11 +85,10 @@ public class RoleServiceImpl implements RoleService { |
| 124 | 85 | // 更新状态 |
| 125 | 86 | RoleDO updateObj = new RoleDO().setId(id).setStatus(status); |
| 126 | 87 | roleMapper.updateById(updateObj); |
| 127 | - // 发送刷新消息 | |
| 128 | - roleProducer.sendRoleRefreshMessage(); | |
| 129 | 88 | } |
| 130 | 89 | |
| 131 | 90 | @Override |
| 91 | + @CacheEvict(value = RedisKeyConstants.ROLE, key = "#id") | |
| 132 | 92 | public void updateRoleDataScope(Long id, Integer dataScope, Set<Long> dataScopeDeptIds) { |
| 133 | 93 | // 校验是否可以更新 |
| 134 | 94 | validateRoleForUpdate(id); |
| ... | ... | @@ -139,12 +99,11 @@ public class RoleServiceImpl implements RoleService { |
| 139 | 99 | updateObject.setDataScope(dataScope); |
| 140 | 100 | updateObject.setDataScopeDeptIds(dataScopeDeptIds); |
| 141 | 101 | roleMapper.updateById(updateObject); |
| 142 | - // 发送刷新消息 | |
| 143 | - roleProducer.sendRoleRefreshMessage(); | |
| 144 | 102 | } |
| 145 | 103 | |
| 146 | 104 | @Override |
| 147 | 105 | @Transactional(rollbackFor = Exception.class) |
| 106 | + @CacheEvict(value = RedisKeyConstants.ROLE, key = "#id") | |
| 148 | 107 | public void deleteRole(Long id) { |
| 149 | 108 | // 校验是否可以更新 |
| 150 | 109 | validateRoleForUpdate(id); |
| ... | ... | @@ -152,60 +111,6 @@ public class RoleServiceImpl implements RoleService { |
| 152 | 111 | roleMapper.deleteById(id); |
| 153 | 112 | // 删除相关数据 |
| 154 | 113 | permissionService.processRoleDeleted(id); |
| 155 | - // 发送刷新消息. 注意,需要事务提交后,在进行发送刷新消息。不然 db 还未提交,结果缓存先刷新了 | |
| 156 | - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { | |
| 157 | - | |
| 158 | - @Override | |
| 159 | - public void afterCommit() { | |
| 160 | - roleProducer.sendRoleRefreshMessage(); | |
| 161 | - } | |
| 162 | - | |
| 163 | - }); | |
| 164 | - } | |
| 165 | - | |
| 166 | - @Override | |
| 167 | - public RoleDO getRoleFromCache(Long id) { | |
| 168 | - return roleCache.get(id); | |
| 169 | - } | |
| 170 | - | |
| 171 | - @Override | |
| 172 | - public List<RoleDO> getRoleListByStatus(@Nullable Collection<Integer> statuses) { | |
| 173 | - if (CollUtil.isEmpty(statuses)) { | |
| 174 | - return roleMapper.selectList(); | |
| 175 | - } | |
| 176 | - return roleMapper.selectListByStatus(statuses); | |
| 177 | - } | |
| 178 | - | |
| 179 | - @Override | |
| 180 | - public List<RoleDO> getRoleListFromCache(Collection<Long> ids) { | |
| 181 | - if (CollectionUtil.isEmpty(ids)) { | |
| 182 | - return Collections.emptyList(); | |
| 183 | - } | |
| 184 | - return roleCache.values().stream().filter(roleDO -> ids.contains(roleDO.getId())) | |
| 185 | - .collect(Collectors.toList()); | |
| 186 | - } | |
| 187 | - | |
| 188 | - @Override | |
| 189 | - public boolean hasAnySuperAdmin(Collection<RoleDO> roleList) { | |
| 190 | - if (CollectionUtil.isEmpty(roleList)) { | |
| 191 | - return false; | |
| 192 | - } | |
| 193 | - return roleList.stream().anyMatch(role -> RoleCodeEnum.isSuperAdmin(role.getCode())); | |
| 194 | - } | |
| 195 | - | |
| 196 | - @Override | |
| 197 | - public RoleDO getRole(Long id) { | |
| 198 | - return roleMapper.selectById(id); | |
| 199 | - } | |
| 200 | - | |
| 201 | - @Override | |
| 202 | - public PageResult<RoleDO> getRolePage(RolePageReqVO reqVO) { | |
| 203 | - return roleMapper.selectPage(reqVO); | |
| 204 | - } | |
| 205 | - | |
| 206 | - @Override | |
| 207 | - public List<RoleDO> getRoleList(RoleExportReqVO reqVO) { | |
| 208 | - return roleMapper.selectList(reqVO); | |
| 209 | 114 | } |
| 210 | 115 | |
| 211 | 116 | /** |
| ... | ... | @@ -258,6 +163,69 @@ public class RoleServiceImpl implements RoleService { |
| 258 | 163 | } |
| 259 | 164 | |
| 260 | 165 | @Override |
| 166 | + public RoleDO getRole(Long id) { | |
| 167 | + return roleMapper.selectById(id); | |
| 168 | + } | |
| 169 | + | |
| 170 | + @Override | |
| 171 | + @Cacheable(value = RedisKeyConstants.ROLE, key = "#id", | |
| 172 | + unless = "#result == null") | |
| 173 | + public RoleDO getRoleFromCache(Long id) { | |
| 174 | + return roleMapper.selectById(id); | |
| 175 | + } | |
| 176 | + | |
| 177 | + | |
| 178 | + @Override | |
| 179 | + public List<RoleDO> getRoleListByStatus(Collection<Integer> statuses) { | |
| 180 | + return roleMapper.selectListByStatus(statuses); | |
| 181 | + } | |
| 182 | + | |
| 183 | + @Override | |
| 184 | + public List<RoleDO> getRoleList() { | |
| 185 | + return roleMapper.selectList(); | |
| 186 | + } | |
| 187 | + | |
| 188 | + @Override | |
| 189 | + public List<RoleDO> getRoleList(Collection<Long> ids) { | |
| 190 | + if (CollectionUtil.isEmpty(ids)) { | |
| 191 | + return Collections.emptyList(); | |
| 192 | + } | |
| 193 | + return roleMapper.selectBatchIds(ids); | |
| 194 | + } | |
| 195 | + | |
| 196 | + @Override | |
| 197 | + public List<RoleDO> getRoleListFromCache(Collection<Long> ids) { | |
| 198 | + if (CollectionUtil.isEmpty(ids)) { | |
| 199 | + return Collections.emptyList(); | |
| 200 | + } | |
| 201 | + // 这里采用 for 循环从缓存中获取,主要考虑 Spring CacheManager 无法批量操作的问题 | |
| 202 | + RoleServiceImpl self = getSelf(); | |
| 203 | + return convertList(ids, self::getRoleFromCache); | |
| 204 | + } | |
| 205 | + | |
| 206 | + @Override | |
| 207 | + public PageResult<RoleDO> getRolePage(RolePageReqVO reqVO) { | |
| 208 | + return roleMapper.selectPage(reqVO); | |
| 209 | + } | |
| 210 | + | |
| 211 | + @Override | |
| 212 | + public List<RoleDO> getRoleList(RoleExportReqVO reqVO) { | |
| 213 | + return roleMapper.selectList(reqVO); | |
| 214 | + } | |
| 215 | + | |
| 216 | + @Override | |
| 217 | + public boolean hasAnySuperAdmin(Collection<Long> ids) { | |
| 218 | + if (CollectionUtil.isEmpty(ids)) { | |
| 219 | + return false; | |
| 220 | + } | |
| 221 | + RoleServiceImpl self = getSelf(); | |
| 222 | + return ids.stream().anyMatch(id -> { | |
| 223 | + RoleDO role = self.getRoleFromCache(id); | |
| 224 | + return role != null && RoleCodeEnum.isSuperAdmin(role.getCode()); | |
| 225 | + }); | |
| 226 | + } | |
| 227 | + | |
| 228 | + @Override | |
| 261 | 229 | public void validateRoleList(Collection<Long> ids) { |
| 262 | 230 | if (CollUtil.isEmpty(ids)) { |
| 263 | 231 | return; |
| ... | ... | @@ -276,4 +244,14 @@ public class RoleServiceImpl implements RoleService { |
| 276 | 244 | } |
| 277 | 245 | }); |
| 278 | 246 | } |
| 247 | + | |
| 248 | + /** | |
| 249 | + * 获得自身的代理对象,解决 AOP 生效问题 | |
| 250 | + * | |
| 251 | + * @return 自己 | |
| 252 | + */ | |
| 253 | + private RoleServiceImpl getSelf() { | |
| 254 | + return SpringUtil.getBean(getClass()); | |
| 255 | + } | |
| 256 | + | |
| 279 | 257 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordService.java
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImpl.java
| ... | ... | @@ -11,21 +11,24 @@ import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.Sensitiv |
| 11 | 11 | import cn.iocoder.yudao.module.system.convert.sensitiveword.SensitiveWordConvert; |
| 12 | 12 | import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO; |
| 13 | 13 | import cn.iocoder.yudao.module.system.dal.mysql.sensitiveword.SensitiveWordMapper; |
| 14 | -import cn.iocoder.yudao.module.system.mq.producer.sensitiveword.SensitiveWordProducer; | |
| 15 | 14 | import cn.iocoder.yudao.module.system.util.collection.SimpleTrie; |
| 16 | 15 | import com.google.common.collect.HashMultimap; |
| 17 | 16 | import com.google.common.collect.Multimap; |
| 18 | 17 | import lombok.Getter; |
| 19 | 18 | import lombok.extern.slf4j.Slf4j; |
| 19 | +import org.springframework.scheduling.annotation.Scheduled; | |
| 20 | 20 | import org.springframework.stereotype.Service; |
| 21 | 21 | import org.springframework.validation.annotation.Validated; |
| 22 | 22 | |
| 23 | 23 | import javax.annotation.PostConstruct; |
| 24 | 24 | import javax.annotation.Resource; |
| 25 | +import java.time.LocalDateTime; | |
| 25 | 26 | import java.util.*; |
| 27 | +import java.util.concurrent.TimeUnit; | |
| 26 | 28 | |
| 27 | 29 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 28 | 30 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; |
| 31 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue; | |
| 29 | 32 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SENSITIVE_WORD_EXISTS; |
| 30 | 33 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SENSITIVE_WORD_NOT_EXISTS; |
| 31 | 34 | |
| ... | ... | @@ -40,6 +43,11 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SENSITIVE_ |
| 40 | 43 | public class SensitiveWordServiceImpl implements SensitiveWordService { |
| 41 | 44 | |
| 42 | 45 | /** |
| 46 | + * 敏感词列表缓存 | |
| 47 | + */ | |
| 48 | + @Getter | |
| 49 | + private volatile List<SensitiveWordDO> sensitiveWordCache = Collections.emptyList(); | |
| 50 | + /** | |
| 43 | 51 | * 敏感词标签缓存 |
| 44 | 52 | * key:敏感词编号 {@link SensitiveWordDO#getId()} |
| 45 | 53 | * <p> |
| ... | ... | @@ -51,9 +59,6 @@ public class SensitiveWordServiceImpl implements SensitiveWordService { |
| 51 | 59 | @Resource |
| 52 | 60 | private SensitiveWordMapper sensitiveWordMapper; |
| 53 | 61 | |
| 54 | - @Resource | |
| 55 | - private SensitiveWordProducer sensitiveWordProducer; | |
| 56 | - | |
| 57 | 62 | /** |
| 58 | 63 | * 默认的敏感词的字典树,包含所有敏感词 |
| 59 | 64 | */ |
| ... | ... | @@ -68,7 +73,6 @@ public class SensitiveWordServiceImpl implements SensitiveWordService { |
| 68 | 73 | /** |
| 69 | 74 | * 初始化缓存 |
| 70 | 75 | */ |
| 71 | - @Override | |
| 72 | 76 | @PostConstruct |
| 73 | 77 | public void initLocalCache() { |
| 74 | 78 | // 第一步:查询数据 |
| ... | ... | @@ -80,6 +84,7 @@ public class SensitiveWordServiceImpl implements SensitiveWordService { |
| 80 | 84 | Set<String> tags = new HashSet<>(); |
| 81 | 85 | sensitiveWords.forEach(word -> tags.addAll(word.getTags())); |
| 82 | 86 | sensitiveWordTagsCache = tags; |
| 87 | + sensitiveWordCache = sensitiveWords; | |
| 83 | 88 | // 写入 defaultSensitiveWordTrie、tagSensitiveWordTries 缓存 |
| 84 | 89 | initSensitiveWordTrie(sensitiveWords); |
| 85 | 90 | } |
| ... | ... | @@ -105,6 +110,26 @@ public class SensitiveWordServiceImpl implements SensitiveWordService { |
| 105 | 110 | this.tagSensitiveWordTries = tagSensitiveWordTries; |
| 106 | 111 | } |
| 107 | 112 | |
| 113 | + /** | |
| 114 | + * 通过定时任务轮询,刷新缓存 | |
| 115 | + * | |
| 116 | + * 目的:多节点部署时,通过轮询”通知“所有节点,进行刷新 | |
| 117 | + */ | |
| 118 | + @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS) | |
| 119 | + public void refreshLocalCache() { | |
| 120 | + // 情况一:如果缓存里没有数据,则直接刷新缓存 | |
| 121 | + if (CollUtil.isEmpty(sensitiveWordCache)) { | |
| 122 | + initLocalCache(); | |
| 123 | + return; | |
| 124 | + } | |
| 125 | + | |
| 126 | + // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存 | |
| 127 | + LocalDateTime maxTime = getMaxValue(sensitiveWordCache, SensitiveWordDO::getUpdateTime); | |
| 128 | + if (sensitiveWordMapper.selectCountByUpdateTimeGt(maxTime) > 0) { | |
| 129 | + initLocalCache(); | |
| 130 | + } | |
| 131 | + } | |
| 132 | + | |
| 108 | 133 | @Override |
| 109 | 134 | public Long createSensitiveWord(SensitiveWordCreateReqVO createReqVO) { |
| 110 | 135 | // 校验唯一性 |
| ... | ... | @@ -113,8 +138,9 @@ public class SensitiveWordServiceImpl implements SensitiveWordService { |
| 113 | 138 | // 插入 |
| 114 | 139 | SensitiveWordDO sensitiveWord = SensitiveWordConvert.INSTANCE.convert(createReqVO); |
| 115 | 140 | sensitiveWordMapper.insert(sensitiveWord); |
| 116 | - // 发送消息,刷新缓存 | |
| 117 | - sensitiveWordProducer.sendSensitiveWordRefreshMessage(); | |
| 141 | + | |
| 142 | + // 刷新缓存 | |
| 143 | + initLocalCache(); | |
| 118 | 144 | return sensitiveWord.getId(); |
| 119 | 145 | } |
| 120 | 146 | |
| ... | ... | @@ -127,8 +153,9 @@ public class SensitiveWordServiceImpl implements SensitiveWordService { |
| 127 | 153 | // 更新 |
| 128 | 154 | SensitiveWordDO updateObj = SensitiveWordConvert.INSTANCE.convert(updateReqVO); |
| 129 | 155 | sensitiveWordMapper.updateById(updateObj); |
| 130 | - // 发送消息,刷新缓存 | |
| 131 | - sensitiveWordProducer.sendSensitiveWordRefreshMessage(); | |
| 156 | + | |
| 157 | + // 刷新缓存 | |
| 158 | + initLocalCache(); | |
| 132 | 159 | } |
| 133 | 160 | |
| 134 | 161 | @Override |
| ... | ... | @@ -137,8 +164,9 @@ public class SensitiveWordServiceImpl implements SensitiveWordService { |
| 137 | 164 | validateSensitiveWordExists(id); |
| 138 | 165 | // 删除 |
| 139 | 166 | sensitiveWordMapper.deleteById(id); |
| 140 | - // 发送消息,刷新缓存 | |
| 141 | - sensitiveWordProducer.sendSensitiveWordRefreshMessage(); | |
| 167 | + | |
| 168 | + // 刷新缓存 | |
| 169 | + initLocalCache(); | |
| 142 | 170 | } |
| 143 | 171 | |
| 144 | 172 | private void validateSensitiveWordNameUnique(Long id, String name) { | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.system.service.sms; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 3 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 5 | import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; |
| 5 | 6 | import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; |
| ... | ... | @@ -9,15 +10,20 @@ import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannel |
| 9 | 10 | import cn.iocoder.yudao.module.system.convert.sms.SmsChannelConvert; |
| 10 | 11 | import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; |
| 11 | 12 | import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper; |
| 12 | -import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer; | |
| 13 | +import lombok.Getter; | |
| 13 | 14 | import lombok.extern.slf4j.Slf4j; |
| 15 | +import org.springframework.scheduling.annotation.Scheduled; | |
| 14 | 16 | import org.springframework.stereotype.Service; |
| 15 | 17 | |
| 16 | 18 | import javax.annotation.PostConstruct; |
| 17 | 19 | import javax.annotation.Resource; |
| 20 | +import java.time.LocalDateTime; | |
| 21 | +import java.util.Collections; | |
| 18 | 22 | import java.util.List; |
| 23 | +import java.util.concurrent.TimeUnit; | |
| 19 | 24 | |
| 20 | 25 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 26 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue; | |
| 21 | 27 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN; |
| 22 | 28 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS; |
| 23 | 29 | |
| ... | ... | @@ -30,6 +36,12 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNE |
| 30 | 36 | @Slf4j |
| 31 | 37 | public class SmsChannelServiceImpl implements SmsChannelService { |
| 32 | 38 | |
| 39 | + /** | |
| 40 | + * 短信渠道列表的缓存 | |
| 41 | + */ | |
| 42 | + @Getter | |
| 43 | + private volatile List<SmsChannelDO> channelCache = Collections.emptyList(); | |
| 44 | + | |
| 33 | 45 | @Resource |
| 34 | 46 | private SmsClientFactory smsClientFactory; |
| 35 | 47 | |
| ... | ... | @@ -39,9 +51,6 @@ public class SmsChannelServiceImpl implements SmsChannelService { |
| 39 | 51 | @Resource |
| 40 | 52 | private SmsTemplateService smsTemplateService; |
| 41 | 53 | |
| 42 | - @Resource | |
| 43 | - private SmsProducer smsProducer; | |
| 44 | - | |
| 45 | 54 | @Override |
| 46 | 55 | @PostConstruct |
| 47 | 56 | public void initLocalCache() { |
| ... | ... | @@ -52,6 +61,27 @@ public class SmsChannelServiceImpl implements SmsChannelService { |
| 52 | 61 | // 第二步:构建缓存:创建或更新短信 Client |
| 53 | 62 | List<SmsChannelProperties> propertiesList = SmsChannelConvert.INSTANCE.convertList02(channels); |
| 54 | 63 | propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties)); |
| 64 | + this.channelCache = channels; | |
| 65 | + } | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * 通过定时任务轮询,刷新缓存 | |
| 69 | + * | |
| 70 | + * 目的:多节点部署时,通过轮询”通知“所有节点,进行刷新 | |
| 71 | + */ | |
| 72 | + @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS) | |
| 73 | + public void refreshLocalCache() { | |
| 74 | + // 情况一:如果缓存里没有数据,则直接刷新缓存 | |
| 75 | + if (CollUtil.isEmpty(channelCache)) { | |
| 76 | + initLocalCache(); | |
| 77 | + return; | |
| 78 | + } | |
| 79 | + | |
| 80 | + // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存 | |
| 81 | + LocalDateTime maxTime = getMaxValue(channelCache, SmsChannelDO::getUpdateTime); | |
| 82 | + if (smsChannelMapper.selectCountByUpdateTimeGt(maxTime) > 0) { | |
| 83 | + initLocalCache(); | |
| 84 | + } | |
| 55 | 85 | } |
| 56 | 86 | |
| 57 | 87 | @Override |
| ... | ... | @@ -59,9 +89,9 @@ public class SmsChannelServiceImpl implements SmsChannelService { |
| 59 | 89 | // 插入 |
| 60 | 90 | SmsChannelDO smsChannel = SmsChannelConvert.INSTANCE.convert(createReqVO); |
| 61 | 91 | smsChannelMapper.insert(smsChannel); |
| 62 | - // 发送刷新消息 | |
| 63 | - smsProducer.sendSmsChannelRefreshMessage(); | |
| 64 | - // 返回 | |
| 92 | + | |
| 93 | + // 刷新缓存 | |
| 94 | + initLocalCache(); | |
| 65 | 95 | return smsChannel.getId(); |
| 66 | 96 | } |
| 67 | 97 | |
| ... | ... | @@ -72,8 +102,9 @@ public class SmsChannelServiceImpl implements SmsChannelService { |
| 72 | 102 | // 更新 |
| 73 | 103 | SmsChannelDO updateObj = SmsChannelConvert.INSTANCE.convert(updateReqVO); |
| 74 | 104 | smsChannelMapper.updateById(updateObj); |
| 75 | - // 发送刷新消息 | |
| 76 | - smsProducer.sendSmsChannelRefreshMessage(); | |
| 105 | + | |
| 106 | + // 刷新缓存 | |
| 107 | + initLocalCache(); | |
| 77 | 108 | } |
| 78 | 109 | |
| 79 | 110 | @Override |
| ... | ... | @@ -86,8 +117,9 @@ public class SmsChannelServiceImpl implements SmsChannelService { |
| 86 | 117 | } |
| 87 | 118 | // 删除 |
| 88 | 119 | smsChannelMapper.deleteById(id); |
| 89 | - // 发送刷新消息 | |
| 90 | - smsProducer.sendSmsChannelRefreshMessage(); | |
| 120 | + | |
| 121 | + // 刷新缓存 | |
| 122 | + initLocalCache(); | |
| 91 | 123 | } |
| 92 | 124 | |
| 93 | 125 | private void validateSmsChannelExists(Long id) { | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateService.java
| ... | ... | @@ -8,7 +8,6 @@ import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; |
| 8 | 8 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 9 | 9 | |
| 10 | 10 | import javax.validation.Valid; |
| 11 | -import java.util.Collection; | |
| 12 | 11 | import java.util.List; |
| 13 | 12 | import java.util.Map; |
| 14 | 13 | |
| ... | ... | @@ -16,41 +15,11 @@ import java.util.Map; |
| 16 | 15 | * 短信模板 Service 接口 |
| 17 | 16 | * |
| 18 | 17 | * @author zzf |
| 19 | - * @date 2021/1/25 9:24 | |
| 18 | + * @since 2021/1/25 9:24 | |
| 20 | 19 | */ |
| 21 | 20 | public interface SmsTemplateService { |
| 22 | 21 | |
| 23 | 22 | /** |
| 24 | - * 初始化短信模板的本地缓存 | |
| 25 | - */ | |
| 26 | - void initLocalCache(); | |
| 27 | - | |
| 28 | - /** | |
| 29 | - * 获得短信模板,从缓存中 | |
| 30 | - * | |
| 31 | - * @param code 模板编码 | |
| 32 | - * @return 短信模板 | |
| 33 | - */ | |
| 34 | - SmsTemplateDO getSmsTemplateByCodeFromCache(String code); | |
| 35 | - | |
| 36 | - /** | |
| 37 | - * 格式化短信内容 | |
| 38 | - * | |
| 39 | - * @param content 短信模板的内容 | |
| 40 | - * @param params 内容的参数 | |
| 41 | - * @return 格式化后的内容 | |
| 42 | - */ | |
| 43 | - String formatSmsTemplateContent(String content, Map<String, Object> params); | |
| 44 | - | |
| 45 | - /** | |
| 46 | - * 获得短信模板 | |
| 47 | - * | |
| 48 | - * @param code 模板编码 | |
| 49 | - * @return 短信模板 | |
| 50 | - */ | |
| 51 | - SmsTemplateDO getSmsTemplateByCode(String code); | |
| 52 | - | |
| 53 | - /** | |
| 54 | 23 | * 创建短信模板 |
| 55 | 24 | * |
| 56 | 25 | * @param createReqVO 创建信息 |
| ... | ... | @@ -81,12 +50,12 @@ public interface SmsTemplateService { |
| 81 | 50 | SmsTemplateDO getSmsTemplate(Long id); |
| 82 | 51 | |
| 83 | 52 | /** |
| 84 | - * 获得短信模板列表 | |
| 53 | + * 获得短信模板,从缓存中 | |
| 85 | 54 | * |
| 86 | - * @param ids 编号 | |
| 87 | - * @return 短信模板列表 | |
| 55 | + * @param code 模板编码 | |
| 56 | + * @return 短信模板 | |
| 88 | 57 | */ |
| 89 | - List<SmsTemplateDO> getSmsTemplateList(Collection<Long> ids); | |
| 58 | + SmsTemplateDO getSmsTemplateByCodeFromCache(String code); | |
| 90 | 59 | |
| 91 | 60 | /** |
| 92 | 61 | * 获得短信模板分页 |
| ... | ... | @@ -112,4 +81,14 @@ public interface SmsTemplateService { |
| 112 | 81 | */ |
| 113 | 82 | Long countByChannelId(Long channelId); |
| 114 | 83 | |
| 84 | + | |
| 85 | + /** | |
| 86 | + * 格式化短信内容 | |
| 87 | + * | |
| 88 | + * @param content 短信模板的内容 | |
| 89 | + * @param params 内容的参数 | |
| 90 | + * @return 格式化后的内容 | |
| 91 | + */ | |
| 92 | + String formatSmsTemplateContent(String content, Map<String, Object> params); | |
| 93 | + | |
| 115 | 94 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java
| ... | ... | @@ -4,7 +4,6 @@ import cn.hutool.core.util.ReUtil; |
| 4 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 6 | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 8 | 7 | import cn.iocoder.yudao.framework.sms.core.client.SmsClient; |
| 9 | 8 | import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; |
| 10 | 9 | import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; |
| ... | ... | @@ -17,16 +16,15 @@ import cn.iocoder.yudao.module.system.convert.sms.SmsTemplateConvert; |
| 17 | 16 | import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; |
| 18 | 17 | import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; |
| 19 | 18 | import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsTemplateMapper; |
| 20 | -import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer; | |
| 19 | +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; | |
| 21 | 20 | import com.google.common.annotations.VisibleForTesting; |
| 22 | -import lombok.Getter; | |
| 23 | 21 | import lombok.extern.slf4j.Slf4j; |
| 22 | +import org.springframework.cache.annotation.CacheEvict; | |
| 23 | +import org.springframework.cache.annotation.Cacheable; | |
| 24 | 24 | import org.springframework.stereotype.Service; |
| 25 | 25 | import org.springframework.util.Assert; |
| 26 | 26 | |
| 27 | -import javax.annotation.PostConstruct; | |
| 28 | 27 | import javax.annotation.Resource; |
| 29 | -import java.util.Collection; | |
| 30 | 28 | import java.util.List; |
| 31 | 29 | import java.util.Map; |
| 32 | 30 | import java.util.Objects; |
| ... | ... | @@ -59,49 +57,6 @@ public class SmsTemplateServiceImpl implements SmsTemplateService { |
| 59 | 57 | @Resource |
| 60 | 58 | private SmsClientFactory smsClientFactory; |
| 61 | 59 | |
| 62 | - @Resource | |
| 63 | - private SmsProducer smsProducer; | |
| 64 | - | |
| 65 | - /** | |
| 66 | - * 短信模板缓存 | |
| 67 | - * key:短信模板编码 {@link SmsTemplateDO#getCode()} | |
| 68 | - * | |
| 69 | - * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | |
| 70 | - */ | |
| 71 | - @Getter // 为了方便测试,这里提供 getter 方法 | |
| 72 | - private volatile Map<String, SmsTemplateDO> smsTemplateCache; | |
| 73 | - | |
| 74 | - @Override | |
| 75 | - @PostConstruct | |
| 76 | - public void initLocalCache() { | |
| 77 | - // 第一步:查询数据 | |
| 78 | - List<SmsTemplateDO> smsTemplateList = smsTemplateMapper.selectList(); | |
| 79 | - log.info("[initLocalCache][缓存短信模版,数量为:{}]", smsTemplateList.size()); | |
| 80 | - | |
| 81 | - // 第二步:构建缓存 | |
| 82 | - smsTemplateCache = CollectionUtils.convertMap(smsTemplateList, SmsTemplateDO::getCode); | |
| 83 | - } | |
| 84 | - | |
| 85 | - @Override | |
| 86 | - public SmsTemplateDO getSmsTemplateByCodeFromCache(String code) { | |
| 87 | - return smsTemplateCache.get(code); | |
| 88 | - } | |
| 89 | - | |
| 90 | - @Override | |
| 91 | - public String formatSmsTemplateContent(String content, Map<String, Object> params) { | |
| 92 | - return StrUtil.format(content, params); | |
| 93 | - } | |
| 94 | - | |
| 95 | - @Override | |
| 96 | - public SmsTemplateDO getSmsTemplateByCode(String code) { | |
| 97 | - return smsTemplateMapper.selectByCode(code); | |
| 98 | - } | |
| 99 | - | |
| 100 | - @VisibleForTesting | |
| 101 | - public List<String> parseTemplateContentParams(String content) { | |
| 102 | - return ReUtil.findAllGroup1(PATTERN_PARAMS, content); | |
| 103 | - } | |
| 104 | - | |
| 105 | 60 | @Override |
| 106 | 61 | public Long createSmsTemplate(SmsTemplateCreateReqVO createReqVO) { |
| 107 | 62 | // 校验短信渠道 |
| ... | ... | @@ -116,13 +71,13 @@ public class SmsTemplateServiceImpl implements SmsTemplateService { |
| 116 | 71 | template.setParams(parseTemplateContentParams(template.getContent())); |
| 117 | 72 | template.setChannelCode(channelDO.getCode()); |
| 118 | 73 | smsTemplateMapper.insert(template); |
| 119 | - // 发送刷新消息 | |
| 120 | - smsProducer.sendSmsTemplateRefreshMessage(); | |
| 121 | 74 | // 返回 |
| 122 | 75 | return template.getId(); |
| 123 | 76 | } |
| 124 | 77 | |
| 125 | 78 | @Override |
| 79 | + @CacheEvict(cacheNames = RedisKeyConstants.SMS_TEMPLATE, | |
| 80 | + allEntries = true) // allEntries 清空所有缓存,因为可能修改到 code 字段,不好清理 | |
| 126 | 81 | public void updateSmsTemplate(SmsTemplateUpdateReqVO updateReqVO) { |
| 127 | 82 | // 校验存在 |
| 128 | 83 | validateSmsTemplateExists(updateReqVO.getId()); |
| ... | ... | @@ -138,18 +93,16 @@ public class SmsTemplateServiceImpl implements SmsTemplateService { |
| 138 | 93 | updateObj.setParams(parseTemplateContentParams(updateObj.getContent())); |
| 139 | 94 | updateObj.setChannelCode(channelDO.getCode()); |
| 140 | 95 | smsTemplateMapper.updateById(updateObj); |
| 141 | - // 发送刷新消息 | |
| 142 | - smsProducer.sendSmsTemplateRefreshMessage(); | |
| 143 | 96 | } |
| 144 | 97 | |
| 145 | 98 | @Override |
| 99 | + @CacheEvict(cacheNames = RedisKeyConstants.SMS_TEMPLATE, | |
| 100 | + allEntries = true) // allEntries 清空所有缓存,因为 id 不是直接的缓存 code,不好清理 | |
| 146 | 101 | public void deleteSmsTemplate(Long id) { |
| 147 | 102 | // 校验存在 |
| 148 | 103 | validateSmsTemplateExists(id); |
| 149 | 104 | // 更新 |
| 150 | 105 | smsTemplateMapper.deleteById(id); |
| 151 | - // 发送刷新消息 | |
| 152 | - smsProducer.sendSmsTemplateRefreshMessage(); | |
| 153 | 106 | } |
| 154 | 107 | |
| 155 | 108 | private void validateSmsTemplateExists(Long id) { |
| ... | ... | @@ -164,8 +117,10 @@ public class SmsTemplateServiceImpl implements SmsTemplateService { |
| 164 | 117 | } |
| 165 | 118 | |
| 166 | 119 | @Override |
| 167 | - public List<SmsTemplateDO> getSmsTemplateList(Collection<Long> ids) { | |
| 168 | - return smsTemplateMapper.selectBatchIds(ids); | |
| 120 | + @Cacheable(cacheNames = RedisKeyConstants.SMS_TEMPLATE, key = "#code", | |
| 121 | + unless = "#result == null") | |
| 122 | + public SmsTemplateDO getSmsTemplateByCodeFromCache(String code) { | |
| 123 | + return smsTemplateMapper.selectByCode(code); | |
| 169 | 124 | } |
| 170 | 125 | |
| 171 | 126 | @Override |
| ... | ... | @@ -217,7 +172,7 @@ public class SmsTemplateServiceImpl implements SmsTemplateService { |
| 217 | 172 | * @param apiTemplateId API 模板编号 |
| 218 | 173 | */ |
| 219 | 174 | @VisibleForTesting |
| 220 | - public void validateApiTemplate(Long channelId, String apiTemplateId) { | |
| 175 | + void validateApiTemplate(Long channelId, String apiTemplateId) { | |
| 221 | 176 | // 获得短信模板 |
| 222 | 177 | SmsClient smsClient = smsClientFactory.getSmsClient(channelId); |
| 223 | 178 | Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", channelId)); |
| ... | ... | @@ -226,4 +181,14 @@ public class SmsTemplateServiceImpl implements SmsTemplateService { |
| 226 | 181 | templateResult.checkError(); |
| 227 | 182 | } |
| 228 | 183 | |
| 184 | + @Override | |
| 185 | + public String formatSmsTemplateContent(String content, Map<String, Object> params) { | |
| 186 | + return StrUtil.format(content, params); | |
| 187 | + } | |
| 188 | + | |
| 189 | + @VisibleForTesting | |
| 190 | + List<String> parseTemplateContentParams(String content) { | |
| 191 | + return ReUtil.findAllGroup1(PATTERN_PARAMS, content); | |
| 192 | + } | |
| 193 | + | |
| 229 | 194 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImpl.java
| ... | ... | @@ -10,9 +10,9 @@ import cn.iocoder.yudao.module.system.convert.tenant.TenantPackageConvert; |
| 10 | 10 | import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; |
| 11 | 11 | import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; |
| 12 | 12 | import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantPackageMapper; |
| 13 | +import com.baomidou.dynamic.datasource.annotation.DSTransactional; | |
| 13 | 14 | import org.springframework.context.annotation.Lazy; |
| 14 | 15 | import org.springframework.stereotype.Service; |
| 15 | -import org.springframework.transaction.annotation.Transactional; | |
| 16 | 16 | import org.springframework.validation.annotation.Validated; |
| 17 | 17 | |
| 18 | 18 | import javax.annotation.Resource; |
| ... | ... | @@ -47,7 +47,7 @@ public class TenantPackageServiceImpl implements TenantPackageService { |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | 49 | @Override |
| 50 | - @Transactional(rollbackFor = Exception.class) | |
| 50 | + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 | |
| 51 | 51 | public void updateTenantPackage(TenantPackageUpdateReqVO updateReqVO) { |
| 52 | 52 | // 校验存在 |
| 53 | 53 | TenantPackageDO tenantPackage = validateTenantPackageExists(updateReqVO.getId()); | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java
| ... | ... | @@ -29,6 +29,7 @@ import cn.iocoder.yudao.module.system.service.permission.RoleService; |
| 29 | 29 | import cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler; |
| 30 | 30 | import cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler; |
| 31 | 31 | import cn.iocoder.yudao.module.system.service.user.AdminUserService; |
| 32 | +import com.baomidou.dynamic.datasource.annotation.DSTransactional; | |
| 32 | 33 | import lombok.extern.slf4j.Slf4j; |
| 33 | 34 | import org.springframework.beans.factory.annotation.Autowired; |
| 34 | 35 | import org.springframework.context.annotation.Lazy; |
| ... | ... | @@ -95,7 +96,7 @@ public class TenantServiceImpl implements TenantService { |
| 95 | 96 | } |
| 96 | 97 | |
| 97 | 98 | @Override |
| 98 | - @Transactional(rollbackFor = Exception.class) | |
| 99 | + @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 | |
| 99 | 100 | public Long createTenant(TenantCreateReqVO createReqVO) { |
| 100 | 101 | // 校验租户名称是否重复 |
| 101 | 102 | validTenantNameDuplicate(createReqVO.getName(), null); |
| ... | ... | @@ -137,7 +138,7 @@ public class TenantServiceImpl implements TenantService { |
| 137 | 138 | } |
| 138 | 139 | |
| 139 | 140 | @Override |
| 140 | - @Transactional(rollbackFor = Exception.class) | |
| 141 | + @DSTransactional | |
| 141 | 142 | public void updateTenant(TenantUpdateReqVO updateReqVO) { |
| 142 | 143 | // 校验存在 |
| 143 | 144 | TenantDO tenant = validateUpdateTenant(updateReqVO.getId()); |
| ... | ... | @@ -170,7 +171,7 @@ public class TenantServiceImpl implements TenantService { |
| 170 | 171 | } |
| 171 | 172 | |
| 172 | 173 | @Override |
| 173 | - @Transactional(rollbackFor = Exception.class) | |
| 174 | + @DSTransactional | |
| 174 | 175 | public void updateTenantRoleMenu(Long tenantId, Set<Long> menuIds) { |
| 175 | 176 | TenantUtils.execute(tenantId, () -> { |
| 176 | 177 | // 获得所有角色 |
| ... | ... | @@ -186,7 +187,7 @@ public class TenantServiceImpl implements TenantService { |
| 186 | 187 | return; |
| 187 | 188 | } |
| 188 | 189 | // 如果是其他角色,则去掉超过套餐的权限 |
| 189 | - Set<Long> roleMenuIds = permissionService.getRoleMenuIds(role.getId()); | |
| 190 | + Set<Long> roleMenuIds = permissionService.getRoleMenuListByRoleId(role.getId()); | |
| 190 | 191 | roleMenuIds = CollUtil.intersectionDistinct(roleMenuIds, menuIds); |
| 191 | 192 | permissionService.assignRoleMenu(role.getId(), roleMenuIds); |
| 192 | 193 | log.info("[updateTenantRoleMenu][角色({}/{}) 的权限修改为({})]", role.getId(), role.getTenantId(), roleMenuIds); | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
| ... | ... | @@ -290,14 +290,13 @@ public class AdminUserServiceImpl implements AdminUserService { |
| 290 | 290 | if (deptId == null) { |
| 291 | 291 | return Collections.emptySet(); |
| 292 | 292 | } |
| 293 | - Set<Long> deptIds = convertSet(deptService.getDeptListByParentIdFromCache( | |
| 294 | - deptId, true), DeptDO::getId); | |
| 293 | + Set<Long> deptIds = convertSet(deptService.getChildDeptList(deptId), DeptDO::getId); | |
| 295 | 294 | deptIds.add(deptId); // 包括自身 |
| 296 | 295 | return deptIds; |
| 297 | 296 | } |
| 298 | 297 | |
| 299 | 298 | private void validateUserForCreateOrUpdate(Long id, String username, String mobile, String email, |
| 300 | - Long deptId, Set<Long> postIds) { | |
| 299 | + Long deptId, Set<Long> postIds) { | |
| 301 | 300 | // 关闭数据权限,避免因为没有数据权限,查询不到数据,进而导致唯一校验不正确 |
| 302 | 301 | DataPermissionUtils.executeIgnore(() -> { |
| 303 | 302 | // 校验用户存在 | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java
| ... | ... | @@ -39,6 +39,9 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServic |
| 39 | 39 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
| 40 | 40 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; |
| 41 | 41 | import static java.util.Arrays.asList; |
| 42 | +import static org.hamcrest.CoreMatchers.anyOf; | |
| 43 | +import static org.hamcrest.CoreMatchers.is; | |
| 44 | +import static org.hamcrest.MatcherAssert.assertThat; | |
| 42 | 45 | import static org.junit.jupiter.api.Assertions.*; |
| 43 | 46 | import static org.mockito.ArgumentMatchers.eq; |
| 44 | 47 | import static org.mockito.ArgumentMatchers.isNull; |
| ... | ... | @@ -289,7 +292,10 @@ public class OAuth2OpenControllerTest extends BaseMockitoUnitTest { |
| 289 | 292 | scope, redirectUri, true, state); |
| 290 | 293 | // 断言 |
| 291 | 294 | assertEquals(0, result.getCode()); |
| 292 | - assertEquals("https://www.iocoder.cn#access_token=test_access_token&token_type=bearer&state=test&expires_in=30&scope=read", result.getData()); | |
| 295 | + assertThat(result.getData(), anyOf( // 29 和 30 都有一定概率,主要是时间计算 | |
| 296 | + is("https://www.iocoder.cn#access_token=test_access_token&token_type=bearer&state=test&expires_in=29&scope=read"), | |
| 297 | + is("https://www.iocoder.cn#access_token=test_access_token&token_type=bearer&state=test&expires_in=30&scope=read") | |
| 298 | + )); | |
| 293 | 299 | } |
| 294 | 300 | |
| 295 | 301 | @Test // autoApprove = false,通过 + code | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java
| ... | ... | @@ -148,7 +148,7 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest { |
| 148 | 148 | ); |
| 149 | 149 | } |
| 150 | 150 | |
| 151 | - @Test | |
| 151 | + @Test | |
| 152 | 152 | public void testLogin_success() { |
| 153 | 153 | // 准备参数 |
| 154 | 154 | AuthLoginReqVO reqVO = randomPojo(AuthLoginReqVO.class, o -> |
| ... | ... | @@ -174,9 +174,9 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest { |
| 174 | 174 | assertPojoEquals(accessTokenDO, loginRespVO); |
| 175 | 175 | // 校验调用参数 |
| 176 | 176 | verify(loginLogService).createLoginLog( |
| 177 | - argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) | |
| 178 | - && o.getResult().equals(LoginResultEnum.SUCCESS.getResult()) | |
| 179 | - && o.getUserId().equals(user.getId())) | |
| 177 | + argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) | |
| 178 | + && o.getResult().equals(LoginResultEnum.SUCCESS.getResult()) | |
| 179 | + && o.getUserId().equals(user.getId())) | |
| 180 | 180 | ); |
| 181 | 181 | verify(socialUserService).bindSocialUser(eq(new SocialUserBindReqDTO( |
| 182 | 182 | user.getId(), UserTypeEnum.ADMIN.getValue(), |
| ... | ... | @@ -317,8 +317,8 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest { |
| 317 | 317 | assertServiceException(() -> authService.validateCaptcha(reqVO), AUTH_LOGIN_CAPTCHA_CODE_ERROR, "就是不对"); |
| 318 | 318 | // 校验调用参数 |
| 319 | 319 | verify(loginLogService).createLoginLog( |
| 320 | - argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) | |
| 321 | - && o.getResult().equals(LoginResultEnum.CAPTCHA_CODE_ERROR.getResult())) | |
| 320 | + argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGIN_USERNAME.getType()) | |
| 321 | + && o.getResult().equals(LoginResultEnum.CAPTCHA_CODE_ERROR.getResult())) | |
| 322 | 322 | ); |
| 323 | 323 | } |
| 324 | 324 | |
| ... | ... | @@ -349,8 +349,9 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest { |
| 349 | 349 | // 调用 |
| 350 | 350 | authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType()); |
| 351 | 351 | // 校验调用参数 |
| 352 | - verify(loginLogService).createLoginLog(argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGOUT_SELF.getType()) | |
| 353 | - && o.getResult().equals(LoginResultEnum.SUCCESS.getResult())) | |
| 352 | + verify(loginLogService).createLoginLog( | |
| 353 | + argThat(o -> o.getLogType().equals(LoginLogTypeEnum.LOGOUT_SELF.getType()) | |
| 354 | + && o.getResult().equals(LoginResultEnum.SUCCESS.getResult())) | |
| 354 | 355 | ); |
| 355 | 356 | // 调用,并校验 |
| 356 | 357 | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImplTest.java
| 1 | 1 | package cn.iocoder.yudao.module.system.service.dept; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 4 | -import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; | |
| 5 | 4 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; |
| 6 | -import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | |
| 7 | 5 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 8 | 6 | import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptCreateReqVO; |
| 9 | 7 | import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO; |
| ... | ... | @@ -11,27 +9,20 @@ import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateRe |
| 11 | 9 | import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; |
| 12 | 10 | import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper; |
| 13 | 11 | import cn.iocoder.yudao.module.system.enums.dept.DeptIdEnum; |
| 14 | -import cn.iocoder.yudao.module.system.mq.producer.dept.DeptProducer; | |
| 15 | -import com.google.common.collect.Multimap; | |
| 16 | -import org.junit.jupiter.api.BeforeEach; | |
| 17 | 12 | import org.junit.jupiter.api.Test; |
| 18 | -import org.springframework.boot.test.mock.mockito.MockBean; | |
| 19 | 13 | import org.springframework.context.annotation.Import; |
| 20 | 14 | |
| 21 | 15 | import javax.annotation.Resource; |
| 22 | 16 | import java.util.Arrays; |
| 23 | 17 | import java.util.List; |
| 24 | -import java.util.Map; | |
| 25 | -import java.util.function.Consumer; | |
| 18 | +import java.util.Set; | |
| 26 | 19 | |
| 27 | -import static cn.hutool.core.util.RandomUtil.randomEle; | |
| 28 | 20 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; |
| 29 | 21 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; |
| 30 | 22 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; |
| 31 | 23 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; |
| 32 | 24 | import static java.util.Collections.singletonList; |
| 33 | 25 | import static org.junit.jupiter.api.Assertions.*; |
| 34 | -import static org.mockito.Mockito.verify; | |
| 35 | 26 | |
| 36 | 27 | /** |
| 37 | 28 | * {@link DeptServiceImpl} 的单元测试类 |
| ... | ... | @@ -45,63 +36,9 @@ public class DeptServiceImplTest extends BaseDbUnitTest { |
| 45 | 36 | private DeptServiceImpl deptService; |
| 46 | 37 | @Resource |
| 47 | 38 | private DeptMapper deptMapper; |
| 48 | - @MockBean | |
| 49 | - private DeptProducer deptProducer; | |
| 50 | - | |
| 51 | - @BeforeEach | |
| 52 | - public void setUp() { | |
| 53 | - // 清理租户上下文 | |
| 54 | - TenantContextHolder.clear(); | |
| 55 | - } | |
| 56 | - | |
| 57 | - @Test | |
| 58 | - public void testInitLocalCache() { | |
| 59 | - // mock 数据 | |
| 60 | - DeptDO deptDO1 = randomDeptDO(); | |
| 61 | - deptMapper.insert(deptDO1); | |
| 62 | - DeptDO deptDO2 = randomDeptDO(); | |
| 63 | - deptMapper.insert(deptDO2); | |
| 64 | - | |
| 65 | - // 调用 | |
| 66 | - deptService.initLocalCache(); | |
| 67 | - // 断言 deptCache 缓存 | |
| 68 | - Map<Long, DeptDO> deptCache = deptService.getDeptCache(); | |
| 69 | - assertEquals(2, deptCache.size()); | |
| 70 | - assertPojoEquals(deptDO1, deptCache.get(deptDO1.getId())); | |
| 71 | - assertPojoEquals(deptDO2, deptCache.get(deptDO2.getId())); | |
| 72 | - // 断言 parentDeptCache 缓存 | |
| 73 | - Multimap<Long, DeptDO> parentDeptCache = deptService.getParentDeptCache(); | |
| 74 | - assertEquals(2, parentDeptCache.size()); | |
| 75 | - assertPojoEquals(deptDO1, parentDeptCache.get(deptDO1.getParentId())); | |
| 76 | - assertPojoEquals(deptDO2, parentDeptCache.get(deptDO2.getParentId())); | |
| 77 | - } | |
| 78 | - | |
| 79 | - @Test | |
| 80 | - public void testListDepts() { | |
| 81 | - // mock 数据 | |
| 82 | - DeptDO dept = randomPojo(DeptDO.class, o -> { // 等会查询到 | |
| 83 | - o.setName("开发部"); | |
| 84 | - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 85 | - }); | |
| 86 | - deptMapper.insert(dept); | |
| 87 | - // 测试 name 不匹配 | |
| 88 | - deptMapper.insert(ObjectUtils.cloneIgnoreId(dept, o -> o.setName("发"))); | |
| 89 | - // 测试 status 不匹配 | |
| 90 | - deptMapper.insert(ObjectUtils.cloneIgnoreId(dept, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); | |
| 91 | - // 准备参数 | |
| 92 | - DeptListReqVO reqVO = new DeptListReqVO(); | |
| 93 | - reqVO.setName("开"); | |
| 94 | - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 95 | - | |
| 96 | - // 调用 | |
| 97 | - List<DeptDO> sysDeptDOS = deptService.getDeptList(reqVO); | |
| 98 | - // 断言 | |
| 99 | - assertEquals(1, sysDeptDOS.size()); | |
| 100 | - assertPojoEquals(dept, sysDeptDOS.get(0)); | |
| 101 | - } | |
| 102 | 39 | |
| 103 | 40 | @Test |
| 104 | - public void testCreateDept_success() { | |
| 41 | + public void testCreateDept() { | |
| 105 | 42 | // 准备参数 |
| 106 | 43 | DeptCreateReqVO reqVO = randomPojo(DeptCreateReqVO.class, o -> { |
| 107 | 44 | o.setParentId(DeptIdEnum.ROOT.getId()); |
| ... | ... | @@ -115,12 +52,10 @@ public class DeptServiceImplTest extends BaseDbUnitTest { |
| 115 | 52 | // 校验记录的属性是否正确 |
| 116 | 53 | DeptDO deptDO = deptMapper.selectById(deptId); |
| 117 | 54 | assertPojoEquals(reqVO, deptDO); |
| 118 | - // 校验调用 | |
| 119 | - verify(deptProducer).sendDeptRefreshMessage(); | |
| 120 | 55 | } |
| 121 | 56 | |
| 122 | 57 | @Test |
| 123 | - public void testUpdateDept_success() { | |
| 58 | + public void testUpdateDept() { | |
| 124 | 59 | // mock 数据 |
| 125 | 60 | DeptDO dbDeptDO = randomPojo(DeptDO.class, o -> o.setStatus(randomCommonStatus())); |
| 126 | 61 | deptMapper.insert(dbDeptDO);// @Sql: 先插入出一条存在的数据 |
| ... | ... | @@ -137,14 +72,12 @@ public class DeptServiceImplTest extends BaseDbUnitTest { |
| 137 | 72 | // 校验是否更新正确 |
| 138 | 73 | DeptDO deptDO = deptMapper.selectById(reqVO.getId()); // 获取最新的 |
| 139 | 74 | assertPojoEquals(reqVO, deptDO); |
| 140 | - // 校验调用 | |
| 141 | - verify(deptProducer).sendDeptRefreshMessage(); | |
| 142 | 75 | } |
| 143 | 76 | |
| 144 | 77 | @Test |
| 145 | 78 | public void testDeleteDept_success() { |
| 146 | 79 | // mock 数据 |
| 147 | - DeptDO dbDeptDO = randomPojo(DeptDO.class, o -> o.setStatus(randomCommonStatus())); | |
| 80 | + DeptDO dbDeptDO = randomPojo(DeptDO.class); | |
| 148 | 81 | deptMapper.insert(dbDeptDO);// @Sql: 先插入出一条存在的数据 |
| 149 | 82 | // 准备参数 |
| 150 | 83 | Long id = dbDeptDO.getId(); |
| ... | ... | @@ -153,134 +86,99 @@ public class DeptServiceImplTest extends BaseDbUnitTest { |
| 153 | 86 | deptService.deleteDept(id); |
| 154 | 87 | // 校验数据不存在了 |
| 155 | 88 | assertNull(deptMapper.selectById(id)); |
| 156 | - // 校验调用 | |
| 157 | - verify(deptProducer).sendDeptRefreshMessage(); | |
| 158 | 89 | } |
| 159 | 90 | |
| 160 | 91 | @Test |
| 161 | - public void testValidateDept_nameDuplicateForUpdate() { | |
| 92 | + public void testDeleteDept_exitsChildren() { | |
| 162 | 93 | // mock 数据 |
| 163 | - DeptDO deptDO = randomDeptDO(); | |
| 164 | - // 设置根节点部门 | |
| 165 | - deptDO.setParentId(DeptIdEnum.ROOT.getId()); | |
| 166 | - deptMapper.insert(deptDO); | |
| 167 | - // mock 数据 稍后模拟重复它的 name | |
| 168 | - DeptDO nameDeptDO = randomDeptDO(); | |
| 169 | - // 设置根节点部门 | |
| 170 | - nameDeptDO.setParentId(DeptIdEnum.ROOT.getId()); | |
| 171 | - deptMapper.insert(nameDeptDO); | |
| 94 | + DeptDO parentDept = randomPojo(DeptDO.class); | |
| 95 | + deptMapper.insert(parentDept);// @Sql: 先插入出一条存在的数据 | |
| 172 | 96 | // 准备参数 |
| 173 | - DeptUpdateReqVO reqVO = randomPojo(DeptUpdateReqVO.class, o -> { | |
| 174 | - // 设置根节点部门 | |
| 175 | - o.setParentId(DeptIdEnum.ROOT.getId()); | |
| 176 | - // 设置更新的 ID | |
| 177 | - o.setId(deptDO.getId()); | |
| 178 | - // 模拟 name 重复 | |
| 179 | - o.setName(nameDeptDO.getName()); | |
| 97 | + DeptDO childrenDeptDO = randomPojo(DeptDO.class, o -> { | |
| 98 | + o.setParentId(parentDept.getId()); | |
| 99 | + o.setStatus(randomCommonStatus()); | |
| 180 | 100 | }); |
| 101 | + // 插入子部门 | |
| 102 | + deptMapper.insert(childrenDeptDO); | |
| 181 | 103 | |
| 182 | 104 | // 调用, 并断言异常 |
| 183 | - assertServiceException(() -> deptService.updateDept(reqVO), DEPT_NAME_DUPLICATE); | |
| 105 | + assertServiceException(() -> deptService.deleteDept(parentDept.getId()), DEPT_EXITS_CHILDREN); | |
| 184 | 106 | } |
| 185 | 107 | |
| 186 | 108 | @Test |
| 187 | - public void testValidateDept_parentNotExitsForCreate() { | |
| 109 | + public void testValidateDeptExists_notFound() { | |
| 188 | 110 | // 准备参数 |
| 189 | - DeptCreateReqVO reqVO = randomPojo(DeptCreateReqVO.class, | |
| 190 | - o -> o.setStatus(randomCommonStatus())); | |
| 111 | + Long id = randomLongId(); | |
| 191 | 112 | |
| 192 | - // 调用,并断言异常 | |
| 193 | - assertServiceException(() -> deptService.createDept(reqVO), DEPT_PARENT_NOT_EXITS); | |
| 113 | + // 调用, 并断言异常 | |
| 114 | + assertServiceException(() -> deptService.validateDeptExists(id), DEPT_NOT_FOUND); | |
| 194 | 115 | } |
| 195 | 116 | |
| 196 | 117 | @Test |
| 197 | - public void testValidateDept_notFoundForDelete() { | |
| 118 | + public void testValidateParentDept_parentError() { | |
| 198 | 119 | // 准备参数 |
| 199 | 120 | Long id = randomLongId(); |
| 200 | 121 | |
| 201 | 122 | // 调用, 并断言异常 |
| 202 | - assertServiceException(() -> deptService.deleteDept(id), DEPT_NOT_FOUND); | |
| 123 | + assertServiceException(() -> deptService.validateParentDept(id, id), | |
| 124 | + DEPT_PARENT_ERROR); | |
| 203 | 125 | } |
| 204 | 126 | |
| 205 | 127 | @Test |
| 206 | - public void testValidateDept_exitsChildrenForDelete() { | |
| 207 | - // mock 数据 | |
| 208 | - DeptDO parentDept = randomPojo(DeptDO.class, o -> o.setStatus(randomCommonStatus())); | |
| 209 | - deptMapper.insert(parentDept);// @Sql: 先插入出一条存在的数据 | |
| 210 | - // 准备参数 | |
| 211 | - DeptDO childrenDeptDO = randomPojo(DeptDO.class, o -> { | |
| 128 | + public void testValidateParentDept_parentIsChild() { | |
| 129 | + // mock 数据(父节点) | |
| 130 | + DeptDO parentDept = randomPojo(DeptDO.class); | |
| 131 | + deptMapper.insert(parentDept); | |
| 132 | + // mock 数据(子节点) | |
| 133 | + DeptDO childDept = randomPojo(DeptDO.class, o -> { | |
| 212 | 134 | o.setParentId(parentDept.getId()); |
| 213 | - o.setStatus(randomCommonStatus()); | |
| 214 | 135 | }); |
| 215 | - // 插入子部门 | |
| 216 | - deptMapper.insert(childrenDeptDO); | |
| 217 | - // 调用, 并断言异常 | |
| 218 | - assertServiceException(() -> deptService.deleteDept(parentDept.getId()), DEPT_EXITS_CHILDREN); | |
| 219 | - } | |
| 136 | + deptMapper.insert(childDept); | |
| 220 | 137 | |
| 221 | - @Test | |
| 222 | - public void testValidateDept_parentErrorForUpdate() { | |
| 223 | - // mock 数据 | |
| 224 | - DeptDO dbDeptDO = randomPojo(DeptDO.class, o -> o.setStatus(randomCommonStatus())); | |
| 225 | - deptMapper.insert(dbDeptDO); | |
| 226 | 138 | // 准备参数 |
| 227 | - DeptUpdateReqVO reqVO = randomPojo(DeptUpdateReqVO.class, o -> { | |
| 228 | - // 设置自己为父部门 | |
| 229 | - o.setParentId(dbDeptDO.getId()); | |
| 230 | - // 设置更新的 ID | |
| 231 | - o.setId(dbDeptDO.getId()); | |
| 232 | - }); | |
| 139 | + Long id = parentDept.getId(); | |
| 140 | + Long parentId = childDept.getId(); | |
| 233 | 141 | |
| 234 | 142 | // 调用, 并断言异常 |
| 235 | - assertServiceException(() -> deptService.updateDept(reqVO), DEPT_PARENT_ERROR); | |
| 143 | + assertServiceException(() -> deptService.validateParentDept(id, parentId), DEPT_PARENT_IS_CHILD); | |
| 236 | 144 | } |
| 237 | 145 | |
| 238 | 146 | @Test |
| 239 | - public void testValidateDept_notEnableForCreate() { | |
| 147 | + public void testValidateNameUnique_duplicate() { | |
| 240 | 148 | // mock 数据 |
| 241 | - DeptDO deptDO = randomPojo(DeptDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())); | |
| 149 | + DeptDO deptDO = randomPojo(DeptDO.class); | |
| 242 | 150 | deptMapper.insert(deptDO); |
| 151 | + | |
| 243 | 152 | // 准备参数 |
| 244 | - DeptCreateReqVO reqVO = randomPojo(DeptCreateReqVO.class, o -> { | |
| 245 | - // 设置未启用的部门为父部门 | |
| 246 | - o.setParentId(deptDO.getId()); | |
| 247 | - }); | |
| 153 | + Long id = randomLongId(); | |
| 154 | + Long parentId = deptDO.getParentId(); | |
| 155 | + String name = deptDO.getName(); | |
| 248 | 156 | |
| 249 | 157 | // 调用, 并断言异常 |
| 250 | - assertServiceException(() -> deptService.createDept(reqVO), DEPT_NOT_ENABLE); | |
| 158 | + assertServiceException(() -> deptService.validateDeptNameUnique(id, parentId, name), | |
| 159 | + DEPT_NAME_DUPLICATE); | |
| 251 | 160 | } |
| 252 | 161 | |
| 253 | 162 | @Test |
| 254 | - public void testCheckDept_parentIsChildForUpdate() { | |
| 163 | + public void testGetDept() { | |
| 255 | 164 | // mock 数据 |
| 256 | - DeptDO parentDept = randomPojo(DeptDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 257 | - deptMapper.insert(parentDept); | |
| 258 | - DeptDO childDept = randomPojo(DeptDO.class, o -> { | |
| 259 | - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 260 | - o.setParentId(parentDept.getId()); | |
| 261 | - }); | |
| 262 | - deptMapper.insert(childDept); | |
| 263 | - // 初始化本地缓存 | |
| 264 | - deptService.initLocalCache(); | |
| 265 | - | |
| 165 | + DeptDO deptDO = randomPojo(DeptDO.class); | |
| 166 | + deptMapper.insert(deptDO); | |
| 266 | 167 | // 准备参数 |
| 267 | - DeptUpdateReqVO reqVO = randomPojo(DeptUpdateReqVO.class, o -> { | |
| 268 | - // 设置自己的子部门为父部门 | |
| 269 | - o.setParentId(childDept.getId()); | |
| 270 | - // 设置更新的 ID | |
| 271 | - o.setId(parentDept.getId()); | |
| 272 | - }); | |
| 168 | + Long id = deptDO.getId(); | |
| 273 | 169 | |
| 274 | - // 调用, 并断言异常 | |
| 275 | - assertServiceException(() -> deptService.updateDept(reqVO), DEPT_PARENT_IS_CHILD); | |
| 170 | + // 调用 | |
| 171 | + DeptDO dbDept = deptService.getDept(id); | |
| 172 | + // 断言 | |
| 173 | + assertEquals(deptDO, dbDept); | |
| 276 | 174 | } |
| 277 | 175 | |
| 278 | 176 | @Test |
| 279 | - public void testGetDeptList() { | |
| 177 | + public void testGetDeptList_ids() { | |
| 280 | 178 | // mock 数据 |
| 281 | - DeptDO deptDO01 = randomDeptDO(); | |
| 179 | + DeptDO deptDO01 = randomPojo(DeptDO.class); | |
| 282 | 180 | deptMapper.insert(deptDO01); |
| 283 | - DeptDO deptDO02 = randomDeptDO(); | |
| 181 | + DeptDO deptDO02 = randomPojo(DeptDO.class); | |
| 284 | 182 | deptMapper.insert(deptDO02); |
| 285 | 183 | // 准备参数 |
| 286 | 184 | List<Long> ids = Arrays.asList(deptDO01.getId(), deptDO02.getId()); |
| ... | ... | @@ -294,23 +192,79 @@ public class DeptServiceImplTest extends BaseDbUnitTest { |
| 294 | 192 | } |
| 295 | 193 | |
| 296 | 194 | @Test |
| 297 | - public void testGetDept() { | |
| 195 | + public void testGetDeptList_reqVO() { | |
| 298 | 196 | // mock 数据 |
| 299 | - DeptDO deptDO = randomDeptDO(); | |
| 300 | - deptMapper.insert(deptDO); | |
| 197 | + DeptDO dept = randomPojo(DeptDO.class, o -> { // 等会查询到 | |
| 198 | + o.setName("开发部"); | |
| 199 | + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 200 | + }); | |
| 201 | + deptMapper.insert(dept); | |
| 202 | + // 测试 name 不匹配 | |
| 203 | + deptMapper.insert(ObjectUtils.cloneIgnoreId(dept, o -> o.setName("发"))); | |
| 204 | + // 测试 status 不匹配 | |
| 205 | + deptMapper.insert(ObjectUtils.cloneIgnoreId(dept, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); | |
| 301 | 206 | // 准备参数 |
| 302 | - Long id = deptDO.getId(); | |
| 207 | + DeptListReqVO reqVO = new DeptListReqVO(); | |
| 208 | + reqVO.setName("开"); | |
| 209 | + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 303 | 210 | |
| 304 | 211 | // 调用 |
| 305 | - DeptDO dbDept = deptService.getDept(id); | |
| 212 | + List<DeptDO> sysDeptDOS = deptService.getDeptList(reqVO); | |
| 306 | 213 | // 断言 |
| 307 | - assertEquals(deptDO, dbDept); | |
| 214 | + assertEquals(1, sysDeptDOS.size()); | |
| 215 | + assertPojoEquals(dept, sysDeptDOS.get(0)); | |
| 216 | + } | |
| 217 | + | |
| 218 | + @Test | |
| 219 | + public void testGetChildDeptList() { | |
| 220 | + // mock 数据(1 级别子节点) | |
| 221 | + DeptDO dept1 = randomPojo(DeptDO.class, o -> o.setName("1")); | |
| 222 | + deptMapper.insert(dept1); | |
| 223 | + DeptDO dept2 = randomPojo(DeptDO.class, o -> o.setName("2")); | |
| 224 | + deptMapper.insert(dept2); | |
| 225 | + // mock 数据(2 级子节点) | |
| 226 | + DeptDO dept1a = randomPojo(DeptDO.class, o -> o.setName("1-a").setParentId(dept1.getId())); | |
| 227 | + deptMapper.insert(dept1a); | |
| 228 | + DeptDO dept2a = randomPojo(DeptDO.class, o -> o.setName("2-a").setParentId(dept2.getId())); | |
| 229 | + deptMapper.insert(dept2a); | |
| 230 | + // 准备参数 | |
| 231 | + Long id = dept1.getParentId(); | |
| 232 | + | |
| 233 | + // 调用 | |
| 234 | + List<DeptDO> result = deptService.getChildDeptList(id); | |
| 235 | + // 断言 | |
| 236 | + assertEquals(result.size(), 2); | |
| 237 | + assertPojoEquals(dept1, result.get(0)); | |
| 238 | + assertPojoEquals(dept1a, result.get(1)); | |
| 239 | + } | |
| 240 | + | |
| 241 | + @Test | |
| 242 | + public void testGetChildDeptListFromCache() { | |
| 243 | + // mock 数据(1 级别子节点) | |
| 244 | + DeptDO dept1 = randomPojo(DeptDO.class, o -> o.setName("1")); | |
| 245 | + deptMapper.insert(dept1); | |
| 246 | + DeptDO dept2 = randomPojo(DeptDO.class, o -> o.setName("2")); | |
| 247 | + deptMapper.insert(dept2); | |
| 248 | + // mock 数据(2 级子节点) | |
| 249 | + DeptDO dept1a = randomPojo(DeptDO.class, o -> o.setName("1-a").setParentId(dept1.getId())); | |
| 250 | + deptMapper.insert(dept1a); | |
| 251 | + DeptDO dept2a = randomPojo(DeptDO.class, o -> o.setName("2-a").setParentId(dept2.getId())); | |
| 252 | + deptMapper.insert(dept2a); | |
| 253 | + // 准备参数 | |
| 254 | + Long id = dept1.getParentId(); | |
| 255 | + | |
| 256 | + // 调用 | |
| 257 | + Set<Long> result = deptService.getChildDeptIdListFromCache(id); | |
| 258 | + // 断言 | |
| 259 | + assertEquals(result.size(), 2); | |
| 260 | + assertTrue(result.contains(dept1.getId())); | |
| 261 | + assertTrue(result.contains(dept1a.getId())); | |
| 308 | 262 | } |
| 309 | 263 | |
| 310 | 264 | @Test |
| 311 | 265 | public void testValidateDeptList_success() { |
| 312 | 266 | // mock 数据 |
| 313 | - DeptDO deptDO = randomDeptDO().setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 267 | + DeptDO deptDO = randomPojo(DeptDO.class).setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 314 | 268 | deptMapper.insert(deptDO); |
| 315 | 269 | // 准备参数 |
| 316 | 270 | List<Long> ids = singletonList(deptDO.getId()); |
| ... | ... | @@ -331,7 +285,7 @@ public class DeptServiceImplTest extends BaseDbUnitTest { |
| 331 | 285 | @Test |
| 332 | 286 | public void testValidateDeptList_notEnable() { |
| 333 | 287 | // mock 数据 |
| 334 | - DeptDO deptDO = randomDeptDO().setStatus(CommonStatusEnum.DISABLE.getStatus()); | |
| 288 | + DeptDO deptDO = randomPojo(DeptDO.class).setStatus(CommonStatusEnum.DISABLE.getStatus()); | |
| 335 | 289 | deptMapper.insert(deptDO); |
| 336 | 290 | // 准备参数 |
| 337 | 291 | List<Long> ids = singletonList(deptDO.getId()); |
| ... | ... | @@ -340,12 +294,4 @@ public class DeptServiceImplTest extends BaseDbUnitTest { |
| 340 | 294 | assertServiceException(() -> deptService.validateDeptList(ids), DEPT_NOT_ENABLE, deptDO.getName()); |
| 341 | 295 | } |
| 342 | 296 | |
| 343 | - @SafeVarargs | |
| 344 | - private static DeptDO randomDeptDO(Consumer<DeptDO>... consumers) { | |
| 345 | - Consumer<DeptDO> consumer = (o) -> { | |
| 346 | - o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 | |
| 347 | - }; | |
| 348 | - return randomPojo(DeptDO.class, ArrayUtils.append(consumer, consumers)); | |
| 349 | - } | |
| 350 | - | |
| 351 | 297 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImplTest.java
| ... | ... | @@ -7,14 +7,12 @@ import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccou |
| 7 | 7 | import cn.iocoder.yudao.module.system.controller.admin.mail.vo.account.MailAccountUpdateReqVO; |
| 8 | 8 | import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; |
| 9 | 9 | import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper; |
| 10 | -import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; | |
| 11 | 10 | import org.junit.jupiter.api.Test; |
| 12 | 11 | import org.springframework.boot.test.mock.mockito.MockBean; |
| 13 | 12 | import org.springframework.context.annotation.Import; |
| 14 | 13 | |
| 15 | 14 | import javax.annotation.Resource; |
| 16 | 15 | import java.util.List; |
| 17 | -import java.util.Map; | |
| 18 | 16 | |
| 19 | 17 | import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; |
| 20 | 18 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; |
| ... | ... | @@ -23,14 +21,13 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; |
| 23 | 21 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS; |
| 24 | 22 | import static org.junit.jupiter.api.Assertions.*; |
| 25 | 23 | import static org.mockito.ArgumentMatchers.eq; |
| 26 | -import static org.mockito.Mockito.verify; | |
| 27 | 24 | import static org.mockito.Mockito.when; |
| 28 | 25 | |
| 29 | 26 | /** |
| 30 | -* {@link MailAccountServiceImpl} 的单元测试类 | |
| 31 | -* | |
| 32 | -* @author 芋道源码 | |
| 33 | -*/ | |
| 27 | + * {@link MailAccountServiceImpl} 的单元测试类 | |
| 28 | + * | |
| 29 | + * @author 芋道源码 | |
| 30 | + */ | |
| 34 | 31 | @Import(MailAccountServiceImpl.class) |
| 35 | 32 | public class MailAccountServiceImplTest extends BaseDbUnitTest { |
| 36 | 33 | |
| ... | ... | @@ -42,23 +39,6 @@ public class MailAccountServiceImplTest extends BaseDbUnitTest { |
| 42 | 39 | |
| 43 | 40 | @MockBean |
| 44 | 41 | private MailTemplateService mailTemplateService; |
| 45 | - @MockBean | |
| 46 | - private MailProducer mailProducer; | |
| 47 | - | |
| 48 | - @Test | |
| 49 | - public void testInitLocalCache() { | |
| 50 | - MailAccountDO accountDO1 = randomPojo(MailAccountDO.class); | |
| 51 | - mailAccountMapper.insert(accountDO1); | |
| 52 | - MailAccountDO accountDO02 = randomPojo(MailAccountDO.class); | |
| 53 | - mailAccountMapper.insert(accountDO02); | |
| 54 | - | |
| 55 | - // 调用 | |
| 56 | - mailAccountService.initLocalCache(); | |
| 57 | - // 断言 mailAccountCache 缓存 | |
| 58 | - Map<Long, MailAccountDO> mailAccountCache = mailAccountService.getMailAccountCache(); | |
| 59 | - assertPojoEquals(accountDO1, mailAccountCache.get(accountDO1.getId())); | |
| 60 | - assertPojoEquals(accountDO02, mailAccountCache.get(accountDO02.getId())); | |
| 61 | - } | |
| 62 | 42 | |
| 63 | 43 | @Test |
| 64 | 44 | public void testCreateMailAccount_success() { |
| ... | ... | @@ -72,7 +52,6 @@ public class MailAccountServiceImplTest extends BaseDbUnitTest { |
| 72 | 52 | // 校验记录的属性是否正确 |
| 73 | 53 | MailAccountDO mailAccount = mailAccountMapper.selectById(mailAccountId); |
| 74 | 54 | assertPojoEquals(reqVO, mailAccount); |
| 75 | - verify(mailProducer).sendMailAccountRefreshMessage(); | |
| 76 | 55 | } |
| 77 | 56 | |
| 78 | 57 | @Test |
| ... | ... | @@ -91,7 +70,6 @@ public class MailAccountServiceImplTest extends BaseDbUnitTest { |
| 91 | 70 | // 校验是否更新正确 |
| 92 | 71 | MailAccountDO mailAccount = mailAccountMapper.selectById(reqVO.getId()); // 获取最新的 |
| 93 | 72 | assertPojoEquals(reqVO, mailAccount); |
| 94 | - verify(mailProducer).sendMailAccountRefreshMessage(); | |
| 95 | 73 | } |
| 96 | 74 | |
| 97 | 75 | @Test |
| ... | ... | @@ -115,9 +93,8 @@ public class MailAccountServiceImplTest extends BaseDbUnitTest { |
| 115 | 93 | |
| 116 | 94 | // 调用 |
| 117 | 95 | mailAccountService.deleteMailAccount(id); |
| 118 | - // 校验数据不存在了 | |
| 119 | - assertNull(mailAccountMapper.selectById(id)); | |
| 120 | - verify(mailProducer).sendMailAccountRefreshMessage(); | |
| 96 | + // 校验数据不存在了 | |
| 97 | + assertNull(mailAccountMapper.selectById(id)); | |
| 121 | 98 | } |
| 122 | 99 | |
| 123 | 100 | @Test |
| ... | ... | @@ -125,7 +102,6 @@ public class MailAccountServiceImplTest extends BaseDbUnitTest { |
| 125 | 102 | // mock 数据 |
| 126 | 103 | MailAccountDO dbMailAccount = randomPojo(MailAccountDO.class); |
| 127 | 104 | mailAccountMapper.insert(dbMailAccount);// @Sql: 先插入出一条存在的数据 |
| 128 | - mailAccountService.initLocalCache(); | |
| 129 | 105 | // 准备参数 |
| 130 | 106 | Long id = dbMailAccount.getId(); |
| 131 | 107 | |
| ... | ... | @@ -146,27 +122,27 @@ public class MailAccountServiceImplTest extends BaseDbUnitTest { |
| 146 | 122 | |
| 147 | 123 | @Test |
| 148 | 124 | public void testGetMailAccountPage() { |
| 149 | - // mock 数据 | |
| 150 | - MailAccountDO dbMailAccount = randomPojo(MailAccountDO.class, o -> { // 等会查询到 | |
| 151 | - o.setMail("768@qq.com"); | |
| 152 | - o.setUsername("yunai"); | |
| 153 | - }); | |
| 154 | - mailAccountMapper.insert(dbMailAccount); | |
| 155 | - // 测试 mail 不匹配 | |
| 156 | - mailAccountMapper.insert(cloneIgnoreId(dbMailAccount, o -> o.setMail("788@qq.com"))); | |
| 157 | - // 测试 username 不匹配 | |
| 158 | - mailAccountMapper.insert(cloneIgnoreId(dbMailAccount, o -> o.setUsername("tudou"))); | |
| 159 | - // 准备参数 | |
| 160 | - MailAccountPageReqVO reqVO = new MailAccountPageReqVO(); | |
| 161 | - reqVO.setMail("768"); | |
| 162 | - reqVO.setUsername("yu"); | |
| 163 | - | |
| 164 | - // 调用 | |
| 165 | - PageResult<MailAccountDO> pageResult = mailAccountService.getMailAccountPage(reqVO); | |
| 166 | - // 断言 | |
| 167 | - assertEquals(1, pageResult.getTotal()); | |
| 168 | - assertEquals(1, pageResult.getList().size()); | |
| 169 | - assertPojoEquals(dbMailAccount, pageResult.getList().get(0)); | |
| 125 | + // mock 数据 | |
| 126 | + MailAccountDO dbMailAccount = randomPojo(MailAccountDO.class, o -> { // 等会查询到 | |
| 127 | + o.setMail("768@qq.com"); | |
| 128 | + o.setUsername("yunai"); | |
| 129 | + }); | |
| 130 | + mailAccountMapper.insert(dbMailAccount); | |
| 131 | + // 测试 mail 不匹配 | |
| 132 | + mailAccountMapper.insert(cloneIgnoreId(dbMailAccount, o -> o.setMail("788@qq.com"))); | |
| 133 | + // 测试 username 不匹配 | |
| 134 | + mailAccountMapper.insert(cloneIgnoreId(dbMailAccount, o -> o.setUsername("tudou"))); | |
| 135 | + // 准备参数 | |
| 136 | + MailAccountPageReqVO reqVO = new MailAccountPageReqVO(); | |
| 137 | + reqVO.setMail("768"); | |
| 138 | + reqVO.setUsername("yu"); | |
| 139 | + | |
| 140 | + // 调用 | |
| 141 | + PageResult<MailAccountDO> pageResult = mailAccountService.getMailAccountPage(reqVO); | |
| 142 | + // 断言 | |
| 143 | + assertEquals(1, pageResult.getTotal()); | |
| 144 | + assertEquals(1, pageResult.getList().size()); | |
| 145 | + assertPojoEquals(dbMailAccount, pageResult.getList().get(0)); | |
| 170 | 146 | } |
| 171 | 147 | |
| 172 | 148 | @Test | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImplTest.java
| ... | ... | @@ -25,10 +25,10 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; |
| 25 | 25 | import static org.junit.jupiter.api.Assertions.*; |
| 26 | 26 | |
| 27 | 27 | /** |
| 28 | -* {@link MailLogServiceImpl} 的单元测试类 | |
| 29 | -* | |
| 30 | -* @author 芋道源码 | |
| 31 | -*/ | |
| 28 | + * {@link MailLogServiceImpl} 的单元测试类 | |
| 29 | + * | |
| 30 | + * @author 芋道源码 | |
| 31 | + */ | |
| 32 | 32 | @Import(MailLogServiceImpl.class) |
| 33 | 33 | public class MailLogServiceImplTest extends BaseDbUnitTest { |
| 34 | 34 | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java
| ... | ... | @@ -33,7 +33,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; |
| 33 | 33 | import static org.mockito.ArgumentMatchers.eq; |
| 34 | 34 | import static org.mockito.Mockito.*; |
| 35 | 35 | |
| 36 | -class MailSendServiceImplTest extends BaseMockitoUnitTest { | |
| 36 | +public class MailSendServiceImplTest extends BaseMockitoUnitTest { | |
| 37 | 37 | |
| 38 | 38 | @InjectMocks |
| 39 | 39 | private MailSendServiceImpl mailSendService; |
| ... | ... | @@ -278,16 +278,17 @@ class MailSendServiceImplTest extends BaseMockitoUnitTest { |
| 278 | 278 | |
| 279 | 279 | // mock 方法(发送邮件) |
| 280 | 280 | String messageId = randomString(); |
| 281 | - mailUtilMock.when(() -> MailUtil.send(argThat(mailAccount -> { | |
| 282 | - assertEquals("芋艿 <7685@qq.com>", mailAccount.getFrom()); | |
| 283 | - assertTrue(mailAccount.isAuth()); | |
| 284 | - assertEquals(account.getUsername(), mailAccount.getUser()); | |
| 285 | - assertEquals(account.getPassword(), mailAccount.getPass()); | |
| 286 | - assertEquals(account.getHost(), mailAccount.getHost()); | |
| 287 | - assertEquals(account.getPort(), mailAccount.getPort()); | |
| 288 | - assertEquals(account.getSslEnable(), mailAccount.isSslEnable()); | |
| 289 | - return true; | |
| 290 | - }), eq(message.getMail()), eq(message.getTitle()), eq(message.getContent()), eq(true))) | |
| 281 | + mailUtilMock.when(() -> MailUtil.send( | |
| 282 | + argThat(mailAccount -> { | |
| 283 | + assertEquals("芋艿 <7685@qq.com>", mailAccount.getFrom()); | |
| 284 | + assertTrue(mailAccount.isAuth()); | |
| 285 | + assertEquals(account.getUsername(), mailAccount.getUser()); | |
| 286 | + assertEquals(account.getPassword(), mailAccount.getPass()); | |
| 287 | + assertEquals(account.getHost(), mailAccount.getHost()); | |
| 288 | + assertEquals(account.getPort(), mailAccount.getPort()); | |
| 289 | + assertEquals(account.getSslEnable(), mailAccount.isSslEnable()); | |
| 290 | + return true; | |
| 291 | + }), eq(message.getMail()), eq(message.getTitle()), eq(message.getContent()), eq(true))) | |
| 291 | 292 | .thenReturn(messageId); |
| 292 | 293 | |
| 293 | 294 | // 调用 | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImplTest.java
| ... | ... | @@ -8,9 +8,7 @@ import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemp |
| 8 | 8 | import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateUpdateReqVO; |
| 9 | 9 | import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; |
| 10 | 10 | import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper; |
| 11 | -import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; | |
| 12 | 11 | import org.junit.jupiter.api.Test; |
| 13 | -import org.springframework.boot.test.mock.mockito.MockBean; | |
| 14 | 12 | import org.springframework.context.annotation.Import; |
| 15 | 13 | |
| 16 | 14 | import javax.annotation.Resource; |
| ... | ... | @@ -27,13 +25,12 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId |
| 27 | 25 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
| 28 | 26 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_NOT_EXISTS; |
| 29 | 27 | import static org.junit.jupiter.api.Assertions.*; |
| 30 | -import static org.mockito.Mockito.verify; | |
| 31 | 28 | |
| 32 | 29 | /** |
| 33 | -* {@link MailTemplateServiceImpl} 的单元测试类 | |
| 34 | -* | |
| 35 | -* @author 芋道源码 | |
| 36 | -*/ | |
| 30 | + * {@link MailTemplateServiceImpl} 的单元测试类 | |
| 31 | + * | |
| 32 | + * @author 芋道源码 | |
| 33 | + */ | |
| 37 | 34 | @Import(MailTemplateServiceImpl.class) |
| 38 | 35 | public class MailTemplateServiceImplTest extends BaseDbUnitTest { |
| 39 | 36 | |
| ... | ... | @@ -43,24 +40,6 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest { |
| 43 | 40 | @Resource |
| 44 | 41 | private MailTemplateMapper mailTemplateMapper; |
| 45 | 42 | |
| 46 | - @MockBean | |
| 47 | - private MailProducer mailProducer; | |
| 48 | - | |
| 49 | - @Test | |
| 50 | - public void testInitLocalCache() { | |
| 51 | - MailTemplateDO templateDO01 = randomPojo(MailTemplateDO.class); | |
| 52 | - mailTemplateMapper.insert(templateDO01); | |
| 53 | - MailTemplateDO templateDO02 = randomPojo(MailTemplateDO.class); | |
| 54 | - mailTemplateMapper.insert(templateDO02); | |
| 55 | - | |
| 56 | - // 调用 | |
| 57 | - mailTemplateService.initLocalCache(); | |
| 58 | - // 断言 mailTemplateCache 缓存 | |
| 59 | - Map<String, MailTemplateDO> mailTemplateCache = mailTemplateService.getMailTemplateCache(); | |
| 60 | - assertPojoEquals(templateDO01, mailTemplateCache.get(templateDO01.getCode())); | |
| 61 | - assertPojoEquals(templateDO02, mailTemplateCache.get(templateDO02.getCode())); | |
| 62 | - } | |
| 63 | - | |
| 64 | 43 | @Test |
| 65 | 44 | public void testCreateMailTemplate_success() { |
| 66 | 45 | // 准备参数 |
| ... | ... | @@ -73,7 +52,6 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest { |
| 73 | 52 | // 校验记录的属性是否正确 |
| 74 | 53 | MailTemplateDO mailTemplate = mailTemplateMapper.selectById(mailTemplateId); |
| 75 | 54 | assertPojoEquals(reqVO, mailTemplate); |
| 76 | - verify(mailProducer).sendMailTemplateRefreshMessage(); | |
| 77 | 55 | } |
| 78 | 56 | |
| 79 | 57 | @Test |
| ... | ... | @@ -91,7 +69,6 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest { |
| 91 | 69 | // 校验是否更新正确 |
| 92 | 70 | MailTemplateDO mailTemplate = mailTemplateMapper.selectById(reqVO.getId()); // 获取最新的 |
| 93 | 71 | assertPojoEquals(reqVO, mailTemplate); |
| 94 | - verify(mailProducer).sendMailTemplateRefreshMessage(); | |
| 95 | 72 | } |
| 96 | 73 | |
| 97 | 74 | @Test |
| ... | ... | @@ -115,7 +92,6 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest { |
| 115 | 92 | mailTemplateService.deleteMailTemplate(id); |
| 116 | 93 | // 校验数据不存在了 |
| 117 | 94 | assertNull(mailTemplateMapper.selectById(id)); |
| 118 | - verify(mailProducer).sendMailTemplateRefreshMessage(); | |
| 119 | 95 | } |
| 120 | 96 | |
| 121 | 97 | @Test |
| ... | ... | @@ -129,39 +105,39 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest { |
| 129 | 105 | |
| 130 | 106 | @Test |
| 131 | 107 | public void testGetMailTemplatePage() { |
| 132 | - // mock 数据 | |
| 133 | - MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class, o -> { // 等会查询到 | |
| 134 | - o.setName("源码"); | |
| 135 | - o.setCode("test_01"); | |
| 136 | - o.setAccountId(1L); | |
| 137 | - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 138 | - o.setCreateTime(buildTime(2023, 2, 3)); | |
| 139 | - }); | |
| 140 | - mailTemplateMapper.insert(dbMailTemplate); | |
| 141 | - // 测试 name 不匹配 | |
| 142 | - mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setName("芋道"))); | |
| 143 | - // 测试 code 不匹配 | |
| 144 | - mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setCode("test_02"))); | |
| 145 | - // 测试 accountId 不匹配 | |
| 146 | - mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setAccountId(2L))); | |
| 147 | - // 测试 status 不匹配 | |
| 148 | - mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); | |
| 149 | - // 测试 createTime 不匹配 | |
| 150 | - mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setCreateTime(buildTime(2023, 1, 5)))); | |
| 151 | - // 准备参数 | |
| 152 | - MailTemplatePageReqVO reqVO = new MailTemplatePageReqVO(); | |
| 153 | - reqVO.setName("源"); | |
| 154 | - reqVO.setCode("est_01"); | |
| 155 | - reqVO.setAccountId(1L); | |
| 156 | - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 157 | - reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 5)); | |
| 158 | - | |
| 159 | - // 调用 | |
| 160 | - PageResult<MailTemplateDO> pageResult = mailTemplateService.getMailTemplatePage(reqVO); | |
| 161 | - // 断言 | |
| 162 | - assertEquals(1, pageResult.getTotal()); | |
| 163 | - assertEquals(1, pageResult.getList().size()); | |
| 164 | - assertPojoEquals(dbMailTemplate, pageResult.getList().get(0)); | |
| 108 | + // mock 数据 | |
| 109 | + MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class, o -> { // 等会查询到 | |
| 110 | + o.setName("源码"); | |
| 111 | + o.setCode("test_01"); | |
| 112 | + o.setAccountId(1L); | |
| 113 | + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 114 | + o.setCreateTime(buildTime(2023, 2, 3)); | |
| 115 | + }); | |
| 116 | + mailTemplateMapper.insert(dbMailTemplate); | |
| 117 | + // 测试 name 不匹配 | |
| 118 | + mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setName("芋道"))); | |
| 119 | + // 测试 code 不匹配 | |
| 120 | + mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setCode("test_02"))); | |
| 121 | + // 测试 accountId 不匹配 | |
| 122 | + mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setAccountId(2L))); | |
| 123 | + // 测试 status 不匹配 | |
| 124 | + mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); | |
| 125 | + // 测试 createTime 不匹配 | |
| 126 | + mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setCreateTime(buildTime(2023, 1, 5)))); | |
| 127 | + // 准备参数 | |
| 128 | + MailTemplatePageReqVO reqVO = new MailTemplatePageReqVO(); | |
| 129 | + reqVO.setName("源"); | |
| 130 | + reqVO.setCode("est_01"); | |
| 131 | + reqVO.setAccountId(1L); | |
| 132 | + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 133 | + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 5)); | |
| 134 | + | |
| 135 | + // 调用 | |
| 136 | + PageResult<MailTemplateDO> pageResult = mailTemplateService.getMailTemplatePage(reqVO); | |
| 137 | + // 断言 | |
| 138 | + assertEquals(1, pageResult.getTotal()); | |
| 139 | + assertEquals(1, pageResult.getList().size()); | |
| 140 | + assertPojoEquals(dbMailTemplate, pageResult.getList().get(0)); | |
| 165 | 141 | } |
| 166 | 142 | |
| 167 | 143 | @Test |
| ... | ... | @@ -199,7 +175,6 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest { |
| 199 | 175 | // mock 数据 |
| 200 | 176 | MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class); |
| 201 | 177 | mailTemplateMapper.insert(dbMailTemplate); |
| 202 | - mailTemplateService.initLocalCache(); | |
| 203 | 178 | // 准备参数 |
| 204 | 179 | String code = dbMailTemplate.getCode(); |
| 205 | 180 | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImplTest.java
| ... | ... | @@ -8,9 +8,7 @@ import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.Notify |
| 8 | 8 | import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateUpdateReqVO; |
| 9 | 9 | import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; |
| 10 | 10 | import cn.iocoder.yudao.module.system.dal.mysql.notify.NotifyTemplateMapper; |
| 11 | -import cn.iocoder.yudao.module.system.mq.producer.notify.NotifyProducer; | |
| 12 | 11 | import org.junit.jupiter.api.Test; |
| 13 | -import org.springframework.boot.test.mock.mockito.MockBean; | |
| 14 | 12 | import org.springframework.context.annotation.Import; |
| 15 | 13 | |
| 16 | 14 | import javax.annotation.Resource; |
| ... | ... | @@ -25,13 +23,12 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServic |
| 25 | 23 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; |
| 26 | 24 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.NOTIFY_TEMPLATE_NOT_EXISTS; |
| 27 | 25 | import static org.junit.jupiter.api.Assertions.*; |
| 28 | -import static org.mockito.Mockito.verify; | |
| 29 | 26 | |
| 30 | 27 | /** |
| 31 | -* {@link NotifyTemplateServiceImpl} 的单元测试类 | |
| 32 | -* | |
| 33 | -* @author 芋道源码 | |
| 34 | -*/ | |
| 28 | + * {@link NotifyTemplateServiceImpl} 的单元测试类 | |
| 29 | + * | |
| 30 | + * @author 芋道源码 | |
| 31 | + */ | |
| 35 | 32 | @Import(NotifyTemplateServiceImpl.class) |
| 36 | 33 | public class NotifyTemplateServiceImplTest extends BaseDbUnitTest { |
| 37 | 34 | |
| ... | ... | @@ -41,9 +38,6 @@ public class NotifyTemplateServiceImplTest extends BaseDbUnitTest { |
| 41 | 38 | @Resource |
| 42 | 39 | private NotifyTemplateMapper notifyTemplateMapper; |
| 43 | 40 | |
| 44 | - @MockBean | |
| 45 | - private NotifyProducer notifyProducer; | |
| 46 | - | |
| 47 | 41 | @Test |
| 48 | 42 | public void testCreateNotifyTemplate_success() { |
| 49 | 43 | // 准备参数 |
| ... | ... | @@ -57,7 +51,6 @@ public class NotifyTemplateServiceImplTest extends BaseDbUnitTest { |
| 57 | 51 | // 校验记录的属性是否正确 |
| 58 | 52 | NotifyTemplateDO notifyTemplate = notifyTemplateMapper.selectById(notifyTemplateId); |
| 59 | 53 | assertPojoEquals(reqVO, notifyTemplate); |
| 60 | - verify(notifyProducer).sendNotifyTemplateRefreshMessage(); | |
| 61 | 54 | } |
| 62 | 55 | |
| 63 | 56 | @Test |
| ... | ... | @@ -76,7 +69,6 @@ public class NotifyTemplateServiceImplTest extends BaseDbUnitTest { |
| 76 | 69 | // 校验是否更新正确 |
| 77 | 70 | NotifyTemplateDO notifyTemplate = notifyTemplateMapper.selectById(reqVO.getId()); // 获取最新的 |
| 78 | 71 | assertPojoEquals(reqVO, notifyTemplate); |
| 79 | - verify(notifyProducer).sendNotifyTemplateRefreshMessage(); | |
| 80 | 72 | } |
| 81 | 73 | |
| 82 | 74 | @Test |
| ... | ... | @@ -98,9 +90,8 @@ public class NotifyTemplateServiceImplTest extends BaseDbUnitTest { |
| 98 | 90 | |
| 99 | 91 | // 调用 |
| 100 | 92 | notifyTemplateService.deleteNotifyTemplate(id); |
| 101 | - // 校验数据不存在了 | |
| 102 | - assertNull(notifyTemplateMapper.selectById(id)); | |
| 103 | - verify(notifyProducer).sendNotifyTemplateRefreshMessage(); | |
| 93 | + // 校验数据不存在了 | |
| 94 | + assertNull(notifyTemplateMapper.selectById(id)); | |
| 104 | 95 | } |
| 105 | 96 | |
| 106 | 97 | @Test |
| ... | ... | @@ -114,35 +105,35 @@ public class NotifyTemplateServiceImplTest extends BaseDbUnitTest { |
| 114 | 105 | |
| 115 | 106 | @Test |
| 116 | 107 | public void testGetNotifyTemplatePage() { |
| 117 | - // mock 数据 | |
| 118 | - NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class, o -> { // 等会查询到 | |
| 119 | - o.setName("芋头"); | |
| 120 | - o.setCode("test_01"); | |
| 121 | - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 122 | - o.setCreateTime(buildTime(2022, 2, 3)); | |
| 123 | - }); | |
| 124 | - notifyTemplateMapper.insert(dbNotifyTemplate); | |
| 125 | - // 测试 name 不匹配 | |
| 126 | - notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setName("投"))); | |
| 127 | - // 测试 code 不匹配 | |
| 128 | - notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setCode("test_02"))); | |
| 129 | - // 测试 status 不匹配 | |
| 130 | - notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); | |
| 131 | - // 测试 createTime 不匹配 | |
| 132 | - notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setCreateTime(buildTime(2022, 1, 5)))); | |
| 133 | - // 准备参数 | |
| 134 | - NotifyTemplatePageReqVO reqVO = new NotifyTemplatePageReqVO(); | |
| 135 | - reqVO.setName("芋"); | |
| 136 | - reqVO.setCode("est_01"); | |
| 137 | - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 138 | - reqVO.setCreateTime(buildBetweenTime(2022, 2, 1, 2022, 2, 5)); | |
| 139 | - | |
| 140 | - // 调用 | |
| 141 | - PageResult<NotifyTemplateDO> pageResult = notifyTemplateService.getNotifyTemplatePage(reqVO); | |
| 142 | - // 断言 | |
| 143 | - assertEquals(1, pageResult.getTotal()); | |
| 144 | - assertEquals(1, pageResult.getList().size()); | |
| 145 | - assertPojoEquals(dbNotifyTemplate, pageResult.getList().get(0)); | |
| 108 | + // mock 数据 | |
| 109 | + NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class, o -> { // 等会查询到 | |
| 110 | + o.setName("芋头"); | |
| 111 | + o.setCode("test_01"); | |
| 112 | + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 113 | + o.setCreateTime(buildTime(2022, 2, 3)); | |
| 114 | + }); | |
| 115 | + notifyTemplateMapper.insert(dbNotifyTemplate); | |
| 116 | + // 测试 name 不匹配 | |
| 117 | + notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setName("投"))); | |
| 118 | + // 测试 code 不匹配 | |
| 119 | + notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setCode("test_02"))); | |
| 120 | + // 测试 status 不匹配 | |
| 121 | + notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); | |
| 122 | + // 测试 createTime 不匹配 | |
| 123 | + notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate, o -> o.setCreateTime(buildTime(2022, 1, 5)))); | |
| 124 | + // 准备参数 | |
| 125 | + NotifyTemplatePageReqVO reqVO = new NotifyTemplatePageReqVO(); | |
| 126 | + reqVO.setName("芋"); | |
| 127 | + reqVO.setCode("est_01"); | |
| 128 | + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 129 | + reqVO.setCreateTime(buildBetweenTime(2022, 2, 1, 2022, 2, 5)); | |
| 130 | + | |
| 131 | + // 调用 | |
| 132 | + PageResult<NotifyTemplateDO> pageResult = notifyTemplateService.getNotifyTemplatePage(reqVO); | |
| 133 | + // 断言 | |
| 134 | + assertEquals(1, pageResult.getTotal()); | |
| 135 | + assertEquals(1, pageResult.getList().size()); | |
| 136 | + assertPojoEquals(dbNotifyTemplate, pageResult.getList().get(0)); | |
| 146 | 137 | } |
| 147 | 138 | |
| 148 | 139 | @Test |
| ... | ... | @@ -164,7 +155,6 @@ public class NotifyTemplateServiceImplTest extends BaseDbUnitTest { |
| 164 | 155 | // mock 数据 |
| 165 | 156 | NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class); |
| 166 | 157 | notifyTemplateMapper.insert(dbNotifyTemplate); |
| 167 | - notifyTemplateService.initLocalCache(); | |
| 168 | 158 | // 准备参数 |
| 169 | 159 | String code = dbNotifyTemplate.getCode(); |
| 170 | 160 | |
| ... | ... | @@ -173,7 +163,7 @@ public class NotifyTemplateServiceImplTest extends BaseDbUnitTest { |
| 173 | 163 | // 断言 |
| 174 | 164 | assertPojoEquals(dbNotifyTemplate, notifyTemplate); |
| 175 | 165 | } |
| 176 | - | |
| 166 | + | |
| 177 | 167 | @Test |
| 178 | 168 | public void testFormatNotifyTemplateContent() { |
| 179 | 169 | // 准备参数 | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImplTest.java
| 1 | 1 | package cn.iocoder.yudao.module.system.service.oauth2; |
| 2 | 2 | |
| 3 | -import cn.hutool.core.map.MapUtil; | |
| 3 | +import cn.hutool.extra.spring.SpringUtil; | |
| 4 | 4 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | 6 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| ... | ... | @@ -9,14 +9,12 @@ import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2Cl |
| 9 | 9 | import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2ClientUpdateReqVO; |
| 10 | 10 | import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO; |
| 11 | 11 | import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ClientMapper; |
| 12 | -import cn.iocoder.yudao.module.system.mq.producer.auth.OAuth2ClientProducer; | |
| 13 | 12 | import org.junit.jupiter.api.Test; |
| 14 | -import org.springframework.boot.test.mock.mockito.MockBean; | |
| 13 | +import org.mockito.MockedStatic; | |
| 15 | 14 | import org.springframework.context.annotation.Import; |
| 16 | 15 | |
| 17 | 16 | import javax.annotation.Resource; |
| 18 | 17 | import java.util.Collections; |
| 19 | -import java.util.Map; | |
| 20 | 18 | |
| 21 | 19 | import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; |
| 22 | 20 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; |
| ... | ... | @@ -24,13 +22,14 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServic |
| 24 | 22 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; |
| 25 | 23 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; |
| 26 | 24 | import static org.junit.jupiter.api.Assertions.*; |
| 27 | -import static org.mockito.Mockito.verify; | |
| 25 | +import static org.mockito.ArgumentMatchers.eq; | |
| 26 | +import static org.mockito.Mockito.mockStatic; | |
| 28 | 27 | |
| 29 | 28 | /** |
| 30 | -* {@link OAuth2ClientServiceImpl} 的单元测试类 | |
| 31 | -* | |
| 32 | -* @author 芋道源码 | |
| 33 | -*/ | |
| 29 | + * {@link OAuth2ClientServiceImpl} 的单元测试类 | |
| 30 | + * | |
| 31 | + * @author 芋道源码 | |
| 32 | + */ | |
| 34 | 33 | @Import(OAuth2ClientServiceImpl.class) |
| 35 | 34 | public class OAuth2ClientServiceImplTest extends BaseDbUnitTest { |
| 36 | 35 | |
| ... | ... | @@ -40,26 +39,6 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest { |
| 40 | 39 | @Resource |
| 41 | 40 | private OAuth2ClientMapper oauth2ClientMapper; |
| 42 | 41 | |
| 43 | - @MockBean | |
| 44 | - private OAuth2ClientProducer oauth2ClientProducer; | |
| 45 | - | |
| 46 | - @Test | |
| 47 | - public void testInitLocalCache() { | |
| 48 | - // mock 数据 | |
| 49 | - OAuth2ClientDO clientDO1 = randomPojo(OAuth2ClientDO.class); | |
| 50 | - oauth2ClientMapper.insert(clientDO1); | |
| 51 | - OAuth2ClientDO clientDO2 = randomPojo(OAuth2ClientDO.class); | |
| 52 | - oauth2ClientMapper.insert(clientDO2); | |
| 53 | - | |
| 54 | - // 调用 | |
| 55 | - oauth2ClientService.initLocalCache(); | |
| 56 | - // 断言 clientCache 缓存 | |
| 57 | - Map<String, OAuth2ClientDO> clientCache = oauth2ClientService.getClientCache(); | |
| 58 | - assertEquals(2, clientCache.size()); | |
| 59 | - assertPojoEquals(clientDO1, clientCache.get(clientDO1.getClientId())); | |
| 60 | - assertPojoEquals(clientDO2, clientCache.get(clientDO2.getClientId())); | |
| 61 | - } | |
| 62 | - | |
| 63 | 42 | @Test |
| 64 | 43 | public void testCreateOAuth2Client_success() { |
| 65 | 44 | // 准备参数 |
| ... | ... | @@ -73,7 +52,6 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest { |
| 73 | 52 | // 校验记录的属性是否正确 |
| 74 | 53 | OAuth2ClientDO oAuth2Client = oauth2ClientMapper.selectById(oauth2ClientId); |
| 75 | 54 | assertPojoEquals(reqVO, oAuth2Client); |
| 76 | - verify(oauth2ClientProducer).sendOAuth2ClientRefreshMessage(); | |
| 77 | 55 | } |
| 78 | 56 | |
| 79 | 57 | @Test |
| ... | ... | @@ -92,7 +70,6 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest { |
| 92 | 70 | // 校验是否更新正确 |
| 93 | 71 | OAuth2ClientDO oAuth2Client = oauth2ClientMapper.selectById(reqVO.getId()); // 获取最新的 |
| 94 | 72 | assertPojoEquals(reqVO, oAuth2Client); |
| 95 | - verify(oauth2ClientProducer).sendOAuth2ClientRefreshMessage(); | |
| 96 | 73 | } |
| 97 | 74 | |
| 98 | 75 | @Test |
| ... | ... | @@ -116,7 +93,6 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest { |
| 116 | 93 | oauth2ClientService.deleteOAuth2Client(id); |
| 117 | 94 | // 校验数据不存在了 |
| 118 | 95 | assertNull(oauth2ClientMapper.selectById(id)); |
| 119 | - verify(oauth2ClientProducer).sendOAuth2ClientRefreshMessage(); | |
| 120 | 96 | } |
| 121 | 97 | |
| 122 | 98 | @Test |
| ... | ... | @@ -167,62 +143,78 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest { |
| 167 | 143 | } |
| 168 | 144 | |
| 169 | 145 | @Test |
| 146 | + public void testGetOAuth2ClientFromCache() { | |
| 147 | + // mock 数据 | |
| 148 | + OAuth2ClientDO clientDO = randomPojo(OAuth2ClientDO.class); | |
| 149 | + oauth2ClientMapper.insert(clientDO); | |
| 150 | + // 准备参数 | |
| 151 | + String clientId = clientDO.getClientId(); | |
| 152 | + | |
| 153 | + // 调用,并断言 | |
| 154 | + OAuth2ClientDO dbClientDO = oauth2ClientService.getOAuth2ClientFromCache(clientId); | |
| 155 | + assertPojoEquals(clientDO, dbClientDO); | |
| 156 | + } | |
| 157 | + | |
| 158 | + @Test | |
| 170 | 159 | public void testGetOAuth2ClientPage() { |
| 171 | - // mock 数据 | |
| 172 | - OAuth2ClientDO dbOAuth2Client = randomPojo(OAuth2ClientDO.class, o -> { // 等会查询到 | |
| 173 | - o.setName("潜龙"); | |
| 174 | - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 175 | - }); | |
| 176 | - oauth2ClientMapper.insert(dbOAuth2Client); | |
| 177 | - // 测试 name 不匹配 | |
| 178 | - oauth2ClientMapper.insert(cloneIgnoreId(dbOAuth2Client, o -> o.setName("凤凰"))); | |
| 179 | - // 测试 status 不匹配 | |
| 180 | - oauth2ClientMapper.insert(cloneIgnoreId(dbOAuth2Client, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); | |
| 181 | - // 准备参数 | |
| 182 | - OAuth2ClientPageReqVO reqVO = new OAuth2ClientPageReqVO(); | |
| 183 | - reqVO.setName("龙"); | |
| 184 | - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 185 | - | |
| 186 | - // 调用 | |
| 187 | - PageResult<OAuth2ClientDO> pageResult = oauth2ClientService.getOAuth2ClientPage(reqVO); | |
| 188 | - // 断言 | |
| 189 | - assertEquals(1, pageResult.getTotal()); | |
| 190 | - assertEquals(1, pageResult.getList().size()); | |
| 191 | - assertPojoEquals(dbOAuth2Client, pageResult.getList().get(0)); | |
| 160 | + // mock 数据 | |
| 161 | + OAuth2ClientDO dbOAuth2Client = randomPojo(OAuth2ClientDO.class, o -> { // 等会查询到 | |
| 162 | + o.setName("潜龙"); | |
| 163 | + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 164 | + }); | |
| 165 | + oauth2ClientMapper.insert(dbOAuth2Client); | |
| 166 | + // 测试 name 不匹配 | |
| 167 | + oauth2ClientMapper.insert(cloneIgnoreId(dbOAuth2Client, o -> o.setName("凤凰"))); | |
| 168 | + // 测试 status 不匹配 | |
| 169 | + oauth2ClientMapper.insert(cloneIgnoreId(dbOAuth2Client, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); | |
| 170 | + // 准备参数 | |
| 171 | + OAuth2ClientPageReqVO reqVO = new OAuth2ClientPageReqVO(); | |
| 172 | + reqVO.setName("龙"); | |
| 173 | + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 174 | + | |
| 175 | + // 调用 | |
| 176 | + PageResult<OAuth2ClientDO> pageResult = oauth2ClientService.getOAuth2ClientPage(reqVO); | |
| 177 | + // 断言 | |
| 178 | + assertEquals(1, pageResult.getTotal()); | |
| 179 | + assertEquals(1, pageResult.getList().size()); | |
| 180 | + assertPojoEquals(dbOAuth2Client, pageResult.getList().get(0)); | |
| 192 | 181 | } |
| 193 | 182 | |
| 194 | 183 | @Test |
| 195 | 184 | public void testValidOAuthClientFromCache() { |
| 196 | - // mock 方法 | |
| 197 | - OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("default") | |
| 198 | - .setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 199 | - OAuth2ClientDO client02 = randomPojo(OAuth2ClientDO.class).setClientId("disable") | |
| 200 | - .setStatus(CommonStatusEnum.DISABLE.getStatus()); | |
| 201 | - Map<String, OAuth2ClientDO> clientCache = MapUtil.<String, OAuth2ClientDO>builder() | |
| 202 | - .put(client.getClientId(), client) | |
| 203 | - .put(client02.getClientId(), client02).build(); | |
| 204 | - oauth2ClientService.setClientCache(clientCache); | |
| 205 | - | |
| 206 | - // 调用,并断言 | |
| 207 | - assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache(randomString(), | |
| 208 | - null, null, null, null), OAUTH2_CLIENT_NOT_EXISTS); | |
| 209 | - assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("disable", | |
| 210 | - null, null, null, null), OAUTH2_CLIENT_DISABLE); | |
| 211 | - assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default", | |
| 212 | - randomString(), null, null, null), OAUTH2_CLIENT_CLIENT_SECRET_ERROR); | |
| 213 | - assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default", | |
| 214 | - null, randomString(), null, null), OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS); | |
| 215 | - assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default", | |
| 216 | - null, null, Collections.singleton(randomString()), null), OAUTH2_CLIENT_SCOPE_OVER); | |
| 217 | - assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default", | |
| 218 | - null, null, null, "test"), OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH, "test"); | |
| 219 | - // 成功调用(1:参数完整) | |
| 220 | - OAuth2ClientDO result = oauth2ClientService.validOAuthClientFromCache(client.getClientId(), client.getSecret(), | |
| 221 | - client.getAuthorizedGrantTypes().get(0), client.getScopes(), client.getRedirectUris().get(0)); | |
| 222 | - assertPojoEquals(client, result); | |
| 223 | - // 成功调用(2:只有 clientId 参数) | |
| 224 | - result = oauth2ClientService.validOAuthClientFromCache(client.getClientId()); | |
| 225 | - assertPojoEquals(client, result); | |
| 185 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | |
| 186 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(OAuth2ClientServiceImpl.class))) | |
| 187 | + .thenReturn(oauth2ClientService); | |
| 188 | + | |
| 189 | + // mock 方法 | |
| 190 | + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("default") | |
| 191 | + .setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 192 | + oauth2ClientMapper.insert(client); | |
| 193 | + OAuth2ClientDO client02 = randomPojo(OAuth2ClientDO.class).setClientId("disable") | |
| 194 | + .setStatus(CommonStatusEnum.DISABLE.getStatus()); | |
| 195 | + oauth2ClientMapper.insert(client02); | |
| 196 | + | |
| 197 | + // 调用,并断言 | |
| 198 | + assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache(randomString(), | |
| 199 | + null, null, null, null), OAUTH2_CLIENT_NOT_EXISTS); | |
| 200 | + assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("disable", | |
| 201 | + null, null, null, null), OAUTH2_CLIENT_DISABLE); | |
| 202 | + assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default", | |
| 203 | + randomString(), null, null, null), OAUTH2_CLIENT_CLIENT_SECRET_ERROR); | |
| 204 | + assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default", | |
| 205 | + null, randomString(), null, null), OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS); | |
| 206 | + assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default", | |
| 207 | + null, null, Collections.singleton(randomString()), null), OAUTH2_CLIENT_SCOPE_OVER); | |
| 208 | + assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default", | |
| 209 | + null, null, null, "test"), OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH, "test"); | |
| 210 | + // 成功调用(1:参数完整) | |
| 211 | + OAuth2ClientDO result = oauth2ClientService.validOAuthClientFromCache(client.getClientId(), client.getSecret(), | |
| 212 | + client.getAuthorizedGrantTypes().get(0), client.getScopes(), client.getRedirectUris().get(0)); | |
| 213 | + assertPojoEquals(client, result); | |
| 214 | + // 成功调用(2:只有 clientId 参数) | |
| 215 | + result = oauth2ClientService.validOAuthClientFromCache(client.getClientId()); | |
| 216 | + assertPojoEquals(client, result); | |
| 217 | + } | |
| 226 | 218 | } |
| 227 | 219 | |
| 228 | 220 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImplTest.java
| ... | ... | @@ -8,10 +8,7 @@ import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuUp |
| 8 | 8 | import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; |
| 9 | 9 | import cn.iocoder.yudao.module.system.dal.mysql.permission.MenuMapper; |
| 10 | 10 | import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum; |
| 11 | -import cn.iocoder.yudao.module.system.mq.producer.permission.MenuProducer; | |
| 12 | 11 | import cn.iocoder.yudao.module.system.service.tenant.TenantService; |
| 13 | -import com.google.common.collect.LinkedListMultimap; | |
| 14 | -import com.google.common.collect.Multimap; | |
| 15 | 12 | import org.junit.jupiter.api.Test; |
| 16 | 13 | import org.springframework.boot.test.mock.mockito.MockBean; |
| 17 | 14 | import org.springframework.context.annotation.Import; |
| ... | ... | @@ -26,8 +23,6 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServic |
| 26 | 23 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; |
| 27 | 24 | import static cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO.ID_ROOT; |
| 28 | 25 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; |
| 29 | -import static java.util.Arrays.asList; | |
| 30 | -import static java.util.Collections.singletonList; | |
| 31 | 26 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| 32 | 27 | import static org.junit.jupiter.api.Assertions.assertNull; |
| 33 | 28 | import static org.mockito.ArgumentMatchers.argThat; |
| ... | ... | @@ -46,35 +41,12 @@ public class MenuServiceImplTest extends BaseDbUnitTest { |
| 46 | 41 | @MockBean |
| 47 | 42 | private PermissionService permissionService; |
| 48 | 43 | @MockBean |
| 49 | - private MenuProducer menuProducer; | |
| 50 | - @MockBean | |
| 51 | 44 | private TenantService tenantService; |
| 52 | 45 | |
| 53 | 46 | @Test |
| 54 | - public void testInitLocalCache_success() { | |
| 55 | - MenuDO menuDO1 = randomPojo(MenuDO.class); | |
| 56 | - menuMapper.insert(menuDO1); | |
| 57 | - MenuDO menuDO2 = randomPojo(MenuDO.class); | |
| 58 | - menuMapper.insert(menuDO2); | |
| 59 | - | |
| 60 | - // 调用 | |
| 61 | - menuService.initLocalCache(); | |
| 62 | - // 校验 menuCache 缓存 | |
| 63 | - Map<Long, MenuDO> menuCache = menuService.getMenuCache(); | |
| 64 | - assertEquals(2, menuCache.size()); | |
| 65 | - assertPojoEquals(menuDO1, menuCache.get(menuDO1.getId())); | |
| 66 | - assertPojoEquals(menuDO2, menuCache.get(menuDO2.getId())); | |
| 67 | - // 校验 permissionMenuCache 缓存 | |
| 68 | - Multimap<String, MenuDO> permissionMenuCache = menuService.getPermissionMenuCache(); | |
| 69 | - assertEquals(2, permissionMenuCache.size()); | |
| 70 | - assertPojoEquals(menuDO1, permissionMenuCache.get(menuDO1.getPermission())); | |
| 71 | - assertPojoEquals(menuDO2, permissionMenuCache.get(menuDO2.getPermission())); | |
| 72 | - } | |
| 73 | - | |
| 74 | - @Test | |
| 75 | 47 | public void testCreateMenu_success() { |
| 76 | 48 | // mock 数据(构造父菜单) |
| 77 | - MenuDO menuDO = createMenuDO(MenuTypeEnum.MENU, | |
| 49 | + MenuDO menuDO = buildMenuDO(MenuTypeEnum.MENU, | |
| 78 | 50 | "parent", 0L); |
| 79 | 51 | menuMapper.insert(menuDO); |
| 80 | 52 | Long parentId = menuDO.getId(); |
| ... | ... | @@ -89,14 +61,12 @@ public class MenuServiceImplTest extends BaseDbUnitTest { |
| 89 | 61 | // 校验记录的属性是否正确 |
| 90 | 62 | MenuDO dbMenu = menuMapper.selectById(menuId); |
| 91 | 63 | assertPojoEquals(reqVO, dbMenu); |
| 92 | - // 校验调用 | |
| 93 | - verify(menuProducer).sendMenuRefreshMessage(); | |
| 94 | 64 | } |
| 95 | 65 | |
| 96 | 66 | @Test |
| 97 | 67 | public void testUpdateMenu_success() { |
| 98 | 68 | // mock 数据(构造父子菜单) |
| 99 | - MenuDO sonMenuDO = initParentAndSonMenu(); | |
| 69 | + MenuDO sonMenuDO = createParentAndSonMenu(); | |
| 100 | 70 | Long sonId = sonMenuDO.getId(); |
| 101 | 71 | // 准备参数 |
| 102 | 72 | MenuUpdateReqVO reqVO = randomPojo(MenuUpdateReqVO.class, o -> { |
| ... | ... | @@ -111,8 +81,6 @@ public class MenuServiceImplTest extends BaseDbUnitTest { |
| 111 | 81 | // 校验记录的属性是否正确 |
| 112 | 82 | MenuDO dbMenu = menuMapper.selectById(sonId); |
| 113 | 83 | assertPojoEquals(reqVO, dbMenu); |
| 114 | - // 校验调用 | |
| 115 | - verify(menuProducer).sendMenuRefreshMessage(); | |
| 116 | 84 | } |
| 117 | 85 | |
| 118 | 86 | @Test |
| ... | ... | @@ -137,7 +105,6 @@ public class MenuServiceImplTest extends BaseDbUnitTest { |
| 137 | 105 | MenuDO dbMenuDO = menuMapper.selectById(id); |
| 138 | 106 | assertNull(dbMenuDO); |
| 139 | 107 | verify(permissionService).processMenuDeleted(id); |
| 140 | - verify(menuProducer).sendMenuRefreshMessage(); | |
| 141 | 108 | } |
| 142 | 109 | |
| 143 | 110 | @Test |
| ... | ... | @@ -149,7 +116,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest { |
| 149 | 116 | @Test |
| 150 | 117 | public void testDeleteMenu_existChildren() { |
| 151 | 118 | // mock 数据(构造父子菜单) |
| 152 | - MenuDO sonMenu = initParentAndSonMenu(); | |
| 119 | + MenuDO sonMenu = createParentAndSonMenu(); | |
| 153 | 120 | // 准备参数 |
| 154 | 121 | Long parentId = sonMenu.getParentId(); |
| 155 | 122 | |
| ... | ... | @@ -219,85 +186,6 @@ public class MenuServiceImplTest extends BaseDbUnitTest { |
| 219 | 186 | } |
| 220 | 187 | |
| 221 | 188 | @Test |
| 222 | - public void testListMenusFromCache_withoutId() { | |
| 223 | - // mock 缓存 | |
| 224 | - Map<Long, MenuDO> menuCache = new HashMap<>(); | |
| 225 | - // 可被匹配 | |
| 226 | - MenuDO menuDO = randomPojo(MenuDO.class, o -> o.setId(1L) | |
| 227 | - .setType(MenuTypeEnum.MENU.getType()).setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 228 | - menuCache.put(menuDO.getId(), menuDO); | |
| 229 | - // 测试 type 不匹配 | |
| 230 | - menuCache.put(3L, randomPojo(MenuDO.class, o -> o.setId(3L) | |
| 231 | - .setType(MenuTypeEnum.BUTTON.getType()).setStatus(CommonStatusEnum.ENABLE.getStatus()))); | |
| 232 | - // 测试 status 不匹配 | |
| 233 | - menuCache.put(4L, randomPojo(MenuDO.class, o -> o.setId(4L) | |
| 234 | - .setType(MenuTypeEnum.MENU.getType()).setStatus(CommonStatusEnum.DISABLE.getStatus()))); | |
| 235 | - menuService.setMenuCache(menuCache); | |
| 236 | - // 准备参数 | |
| 237 | - Collection<Integer> menuTypes = singletonList(MenuTypeEnum.MENU.getType()); | |
| 238 | - Collection<Integer> menusStatuses = singletonList(CommonStatusEnum.ENABLE.getStatus()); | |
| 239 | - | |
| 240 | - // 调用 | |
| 241 | - List<MenuDO> list = menuService.getMenuListFromCache(menuTypes, menusStatuses); | |
| 242 | - // 断言 | |
| 243 | - assertEquals(1, list.size()); | |
| 244 | - assertPojoEquals(menuDO, list.get(0)); | |
| 245 | - } | |
| 246 | - | |
| 247 | - @Test | |
| 248 | - public void testListMenusFromCache_withId() { | |
| 249 | - // mock 缓存 | |
| 250 | - Map<Long, MenuDO> menuCache = new HashMap<>(); | |
| 251 | - // 可被匹配 | |
| 252 | - MenuDO menuDO = randomPojo(MenuDO.class, o -> o.setId(1L) | |
| 253 | - .setType(MenuTypeEnum.MENU.getType()).setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 254 | - menuCache.put(menuDO.getId(), menuDO); | |
| 255 | - // 测试 id 不匹配 | |
| 256 | - menuCache.put(2L, randomPojo(MenuDO.class, o -> o.setId(2L) | |
| 257 | - .setType(MenuTypeEnum.MENU.getType()).setStatus(CommonStatusEnum.ENABLE.getStatus()))); | |
| 258 | - // 测试 type 不匹配 | |
| 259 | - menuCache.put(3L, randomPojo(MenuDO.class, o -> o.setId(3L) | |
| 260 | - .setType(MenuTypeEnum.BUTTON.getType()).setStatus(CommonStatusEnum.ENABLE.getStatus()))); | |
| 261 | - // 测试 status 不匹配 | |
| 262 | - menuCache.put(4L, randomPojo(MenuDO.class, o -> o.setId(4L) | |
| 263 | - .setType(MenuTypeEnum.MENU.getType()).setStatus(CommonStatusEnum.DISABLE.getStatus()))); | |
| 264 | - menuService.setMenuCache(menuCache); | |
| 265 | - // 准备参数 | |
| 266 | - Collection<Long> menuIds = asList(1L, 3L, 4L); | |
| 267 | - Collection<Integer> menuTypes = singletonList(MenuTypeEnum.MENU.getType()); | |
| 268 | - Collection<Integer> menusStatuses = singletonList(CommonStatusEnum.ENABLE.getStatus()); | |
| 269 | - | |
| 270 | - // 调用 | |
| 271 | - List<MenuDO> list = menuService.getMenuListFromCache(menuIds, menuTypes, menusStatuses); | |
| 272 | - // 断言 | |
| 273 | - assertEquals(1, list.size()); | |
| 274 | - assertPojoEquals(menuDO, list.get(0)); | |
| 275 | - } | |
| 276 | - | |
| 277 | - @Test | |
| 278 | - public void testGetMenuListByPermissionFromCache() { | |
| 279 | - // mock 缓存 | |
| 280 | - Multimap<String, MenuDO> permissionMenuCache = LinkedListMultimap.create(); | |
| 281 | - // 可被匹配 | |
| 282 | - MenuDO menuDO01 = randomPojo(MenuDO.class, o -> o.setId(1L).setPermission("123")); | |
| 283 | - permissionMenuCache.put(menuDO01.getPermission(), menuDO01); | |
| 284 | - MenuDO menuDO02 = randomPojo(MenuDO.class, o -> o.setId(2L).setPermission("123")); | |
| 285 | - permissionMenuCache.put(menuDO02.getPermission(), menuDO02); | |
| 286 | - // 不可匹配 | |
| 287 | - permissionMenuCache.put("456", randomPojo(MenuDO.class, o -> o.setId(3L).setPermission("456"))); | |
| 288 | - menuService.setPermissionMenuCache(permissionMenuCache); | |
| 289 | - // 准备参数 | |
| 290 | - String permission = "123"; | |
| 291 | - | |
| 292 | - // 调用 | |
| 293 | - List<MenuDO> list = menuService.getMenuListByPermissionFromCache(permission); | |
| 294 | - // 断言 | |
| 295 | - assertEquals(2, list.size()); | |
| 296 | - assertPojoEquals(menuDO01, list.get(0)); | |
| 297 | - assertPojoEquals(menuDO02, list.get(1)); | |
| 298 | - } | |
| 299 | - | |
| 300 | - @Test | |
| 301 | 189 | public void testGetMenu() { |
| 302 | 190 | // mock 数据 |
| 303 | 191 | MenuDO menu = randomPojo(MenuDO.class); |
| ... | ... | @@ -314,7 +202,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest { |
| 314 | 202 | @Test |
| 315 | 203 | public void testValidateParentMenu_success() { |
| 316 | 204 | // mock 数据 |
| 317 | - MenuDO menuDO = createMenuDO(MenuTypeEnum.MENU, "parent", 0L); | |
| 205 | + MenuDO menuDO = buildMenuDO(MenuTypeEnum.MENU, "parent", 0L); | |
| 318 | 206 | menuMapper.insert(menuDO); |
| 319 | 207 | // 准备参数 |
| 320 | 208 | Long parentId = menuDO.getId(); |
| ... | ... | @@ -340,7 +228,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest { |
| 340 | 228 | @Test |
| 341 | 229 | public void testValidateParentMenu_parentTypeError() { |
| 342 | 230 | // mock 数据 |
| 343 | - MenuDO menuDO = createMenuDO(MenuTypeEnum.BUTTON, "parent", 0L); | |
| 231 | + MenuDO menuDO = buildMenuDO(MenuTypeEnum.BUTTON, "parent", 0L); | |
| 344 | 232 | menuMapper.insert(menuDO); |
| 345 | 233 | // 准备参数 |
| 346 | 234 | Long parentId = menuDO.getId(); |
| ... | ... | @@ -353,7 +241,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest { |
| 353 | 241 | @Test |
| 354 | 242 | public void testValidateMenu_success() { |
| 355 | 243 | // mock 父子菜单 |
| 356 | - MenuDO sonMenu = initParentAndSonMenu(); | |
| 244 | + MenuDO sonMenu = createParentAndSonMenu(); | |
| 357 | 245 | // 准备参数 |
| 358 | 246 | Long parentId = sonMenu.getParentId(); |
| 359 | 247 | Long otherSonMenuId = randomLongId(); |
| ... | ... | @@ -366,7 +254,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest { |
| 366 | 254 | @Test |
| 367 | 255 | public void testValidateMenu_sonMenuNameDuplicate() { |
| 368 | 256 | // mock 父子菜单 |
| 369 | - MenuDO sonMenu = initParentAndSonMenu(); | |
| 257 | + MenuDO sonMenu = createParentAndSonMenu(); | |
| 370 | 258 | // 准备参数 |
| 371 | 259 | Long parentId = sonMenu.getParentId(); |
| 372 | 260 | Long otherSonMenuId = randomLongId(); |
| ... | ... | @@ -380,26 +268,26 @@ public class MenuServiceImplTest extends BaseDbUnitTest { |
| 380 | 268 | // ====================== 初始化方法 ====================== |
| 381 | 269 | |
| 382 | 270 | /** |
| 383 | - * 构造父子菜单,返回子菜单 | |
| 271 | + * 插入父子菜单,返回子菜单 | |
| 384 | 272 | * |
| 385 | 273 | * @return 子菜单 |
| 386 | 274 | */ |
| 387 | - private MenuDO initParentAndSonMenu() { | |
| 275 | + private MenuDO createParentAndSonMenu() { | |
| 388 | 276 | // 构造父子菜单 |
| 389 | - MenuDO parentMenuDO = createMenuDO(MenuTypeEnum.MENU, "parent", ID_ROOT); | |
| 277 | + MenuDO parentMenuDO = buildMenuDO(MenuTypeEnum.MENU, "parent", ID_ROOT); | |
| 390 | 278 | menuMapper.insert(parentMenuDO); |
| 391 | 279 | // 构建子菜单 |
| 392 | - MenuDO sonMenuDO = createMenuDO(MenuTypeEnum.MENU, "testSonName", | |
| 280 | + MenuDO sonMenuDO = buildMenuDO(MenuTypeEnum.MENU, "testSonName", | |
| 393 | 281 | parentMenuDO.getParentId()); |
| 394 | 282 | menuMapper.insert(sonMenuDO); |
| 395 | 283 | return sonMenuDO; |
| 396 | 284 | } |
| 397 | 285 | |
| 398 | - private MenuDO createMenuDO(MenuTypeEnum type, String name, Long parentId) { | |
| 399 | - return createMenuDO(type, name, parentId, randomCommonStatus()); | |
| 286 | + private MenuDO buildMenuDO(MenuTypeEnum type, String name, Long parentId) { | |
| 287 | + return buildMenuDO(type, name, parentId, randomCommonStatus()); | |
| 400 | 288 | } |
| 401 | 289 | |
| 402 | - private MenuDO createMenuDO(MenuTypeEnum type, String name, Long parentId, Integer status) { | |
| 290 | + private MenuDO buildMenuDO(MenuTypeEnum type, String name, Long parentId, Integer status) { | |
| 403 | 291 | return randomPojo(MenuDO.class, o -> o.setId(null).setName(name).setParentId(parentId) |
| 404 | 292 | .setType(type.getType()).setStatus(status)); |
| 405 | 293 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java
| 1 | 1 | package cn.iocoder.yudao.module.system.service.permission; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | -import cn.hutool.core.map.MapUtil; | |
| 4 | +import cn.hutool.extra.spring.SpringUtil; | |
| 5 | 5 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 6 | 6 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 7 | 7 | import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; |
| ... | ... | @@ -14,32 +14,28 @@ import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; |
| 14 | 14 | import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper; |
| 15 | 15 | import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper; |
| 16 | 16 | import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; |
| 17 | -import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer; | |
| 18 | 17 | import cn.iocoder.yudao.module.system.service.dept.DeptService; |
| 19 | 18 | import cn.iocoder.yudao.module.system.service.user.AdminUserService; |
| 20 | -import com.google.common.collect.ImmutableMultimap; | |
| 21 | -import com.google.common.collect.Multimap; | |
| 22 | 19 | import org.junit.jupiter.api.Test; |
| 20 | +import org.mockito.MockedStatic; | |
| 23 | 21 | import org.springframework.boot.test.mock.mockito.MockBean; |
| 24 | 22 | import org.springframework.context.annotation.Import; |
| 25 | 23 | |
| 26 | 24 | import javax.annotation.Resource; |
| 27 | 25 | import java.util.Collection; |
| 28 | 26 | import java.util.List; |
| 29 | -import java.util.Map; | |
| 30 | 27 | import java.util.Set; |
| 31 | 28 | |
| 29 | +import static cn.hutool.core.collection.ListUtil.toList; | |
| 32 | 30 | import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; |
| 33 | 31 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; |
| 34 | -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; | |
| 35 | -import static java.util.Arrays.asList; | |
| 32 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; | |
| 33 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | |
| 36 | 34 | import static java.util.Collections.singleton; |
| 37 | 35 | import static java.util.Collections.singletonList; |
| 38 | 36 | import static org.junit.jupiter.api.Assertions.*; |
| 39 | 37 | import static org.mockito.ArgumentMatchers.eq; |
| 40 | -import static org.mockito.ArgumentMatchers.same; | |
| 41 | -import static org.mockito.Mockito.verify; | |
| 42 | -import static org.mockito.Mockito.when; | |
| 38 | +import static org.mockito.Mockito.*; | |
| 43 | 39 | |
| 44 | 40 | @Import({PermissionServiceImpl.class}) |
| 45 | 41 | public class PermissionServiceTest extends BaseDbUnitTest { |
| ... | ... | @@ -61,99 +57,140 @@ public class PermissionServiceTest extends BaseDbUnitTest { |
| 61 | 57 | @MockBean |
| 62 | 58 | private AdminUserService userService; |
| 63 | 59 | |
| 64 | - @MockBean | |
| 65 | - private PermissionProducer permissionProducer; | |
| 66 | - | |
| 67 | 60 | @Test |
| 68 | - public void testInitLocalCacheForRoleMenu() { | |
| 69 | - // mock 数据 | |
| 70 | - RoleMenuDO roleMenuDO01 = randomPojo(RoleMenuDO.class, o -> o.setRoleId(1L).setMenuId(10L)); | |
| 71 | - roleMenuMapper.insert(roleMenuDO01); | |
| 72 | - RoleMenuDO roleMenuDO02 = randomPojo(RoleMenuDO.class, o -> o.setRoleId(1L).setMenuId(20L)); | |
| 73 | - roleMenuMapper.insert(roleMenuDO02); | |
| 74 | - | |
| 75 | - // 调用 | |
| 76 | - permissionService.initLocalCacheForRoleMenu(); | |
| 77 | - // 断言 roleMenuCache 缓存 | |
| 78 | - assertEquals(1, permissionService.getRoleMenuCache().keySet().size()); | |
| 79 | - assertEquals(asList(10L, 20L), permissionService.getRoleMenuCache().get(1L)); | |
| 80 | - // 断言 menuRoleCache 缓存 | |
| 81 | - assertEquals(2, permissionService.getMenuRoleCache().size()); | |
| 82 | - assertEquals(singletonList(1L), permissionService.getMenuRoleCache().get(10L)); | |
| 83 | - assertEquals(singletonList(1L), permissionService.getMenuRoleCache().get(20L)); | |
| 61 | + public void testHasAnyPermissions_superAdmin() { | |
| 62 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | |
| 63 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) | |
| 64 | + .thenReturn(permissionService); | |
| 65 | + | |
| 66 | + // 准备参数 | |
| 67 | + Long userId = 1L; | |
| 68 | + String[] roles = new String[]{"system:user:query", "system:user:create"}; | |
| 69 | + // mock 用户登录的角色 | |
| 70 | + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(100L)); | |
| 71 | + RoleDO role = randomPojo(RoleDO.class, o -> o.setId(100L) | |
| 72 | + .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 73 | + when(roleService.getRoleListFromCache(eq(singleton(100L)))).thenReturn(toList(role)); | |
| 74 | + // mock 其它方法 | |
| 75 | + when(roleService.hasAnySuperAdmin(eq(asSet(100L)))).thenReturn(true); | |
| 76 | + | |
| 77 | + // 调用,并断言 | |
| 78 | + assertTrue(permissionService.hasAnyPermissions(userId, roles)); | |
| 79 | + } | |
| 84 | 80 | } |
| 85 | 81 | |
| 86 | 82 | @Test |
| 87 | - public void testInitLocalCacheForUserRole() { | |
| 88 | - // mock 数据 | |
| 89 | - UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); | |
| 90 | - userRoleMapper.insert(userRoleDO01); | |
| 91 | - UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(20L)); | |
| 92 | - userRoleMapper.insert(roleMenuDO02); | |
| 83 | + public void testHasAnyPermissions_normal() { | |
| 84 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | |
| 85 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) | |
| 86 | + .thenReturn(permissionService); | |
| 87 | + | |
| 88 | + // 准备参数 | |
| 89 | + Long userId = 1L; | |
| 90 | + String[] roles = new String[]{"system:user:query", "system:user:create"}; | |
| 91 | + // mock 用户登录的角色 | |
| 92 | + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(100L)); | |
| 93 | + RoleDO role = randomPojo(RoleDO.class, o -> o.setId(100L) | |
| 94 | + .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 95 | + when(roleService.getRoleListFromCache(eq(singleton(100L)))).thenReturn(toList(role)); | |
| 96 | + // mock 菜单 | |
| 97 | + Long menuId = 1000L; | |
| 98 | + when(menuService.getMenuIdListByPermissionFromCache( | |
| 99 | + eq("system:user:create"))).thenReturn(singletonList(menuId)); | |
| 100 | + roleMenuMapper.insert(randomPojo(RoleMenuDO.class).setRoleId(100L).setMenuId(1000L)); | |
| 101 | + | |
| 102 | + // 调用,并断言 | |
| 103 | + assertTrue(permissionService.hasAnyPermissions(userId, roles)); | |
| 104 | + } | |
| 105 | + } | |
| 93 | 106 | |
| 94 | - // 调用 | |
| 95 | - permissionService.initLocalCacheForUserRole(); | |
| 96 | - // 断言 roleMenuCache 缓存 | |
| 97 | - assertEquals(1, permissionService.getUserRoleCache().size()); | |
| 98 | - assertEquals(asSet(10L, 20L), permissionService.getUserRoleCache().get(1L)); | |
| 107 | + @Test | |
| 108 | + public void testHasAnyRoles() { | |
| 109 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | |
| 110 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) | |
| 111 | + .thenReturn(permissionService); | |
| 112 | + | |
| 113 | + // 准备参数 | |
| 114 | + Long userId = 1L; | |
| 115 | + String[] roles = new String[]{"yunai", "tudou"}; | |
| 116 | + // mock 用户与角色的缓存 | |
| 117 | + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(100L)); | |
| 118 | + RoleDO role = randomPojo(RoleDO.class, o -> o.setId(100L).setCode("tudou") | |
| 119 | + .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 120 | + when(roleService.getRoleListFromCache(eq(singleton(100L)))).thenReturn(toList(role)); | |
| 121 | + | |
| 122 | + // 调用,并断言 | |
| 123 | + assertTrue(permissionService.hasAnyRoles(userId, roles)); | |
| 124 | + } | |
| 99 | 125 | } |
| 100 | 126 | |
| 127 | + // ========== 角色-菜单的相关方法 ========== | |
| 128 | + | |
| 101 | 129 | @Test |
| 102 | - public void testGetRoleMenuListFromCache_superAdmin() { | |
| 130 | + public void testAssignRoleMenu() { | |
| 103 | 131 | // 准备参数 |
| 104 | - Collection<Long> roleIds = singletonList(100L); | |
| 105 | - Collection<Integer> menuTypes = asList(2, 3); | |
| 106 | - Collection<Integer> menusStatuses = asList(0, 1); | |
| 107 | - // mock 方法 | |
| 108 | - List<RoleDO> roleList = singletonList(randomPojo(RoleDO.class, o -> o.setId(100L))); | |
| 109 | - when(roleService.getRoleListFromCache(eq(roleIds))).thenReturn(roleList); | |
| 110 | - when(roleService.hasAnySuperAdmin(same(roleList))).thenReturn(true); | |
| 111 | - List<MenuDO> menuList = randomPojoList(MenuDO.class); | |
| 112 | - when(menuService.getMenuListFromCache(eq(menuTypes), eq(menusStatuses))).thenReturn(menuList); | |
| 132 | + Long roleId = 1L; | |
| 133 | + Set<Long> menuIds = asSet(200L, 300L); | |
| 134 | + // mock 数据 | |
| 135 | + RoleMenuDO roleMenu01 = randomPojo(RoleMenuDO.class).setRoleId(1L).setMenuId(100L); | |
| 136 | + roleMenuMapper.insert(roleMenu01); | |
| 137 | + RoleMenuDO roleMenu02 = randomPojo(RoleMenuDO.class).setRoleId(1L).setMenuId(200L); | |
| 138 | + roleMenuMapper.insert(roleMenu02); | |
| 113 | 139 | |
| 114 | 140 | // 调用 |
| 115 | - List<MenuDO> result = permissionService.getRoleMenuListFromCache(roleIds, menuTypes, menusStatuses); | |
| 141 | + permissionService.assignRoleMenu(roleId, menuIds); | |
| 116 | 142 | // 断言 |
| 117 | - assertSame(menuList, result); | |
| 143 | + List<RoleMenuDO> roleMenuList = roleMenuMapper.selectList(); | |
| 144 | + assertEquals(2, roleMenuList.size()); | |
| 145 | + assertEquals(1L, roleMenuList.get(0).getRoleId()); | |
| 146 | + assertEquals(200L, roleMenuList.get(0).getMenuId()); | |
| 147 | + assertEquals(1L, roleMenuList.get(1).getRoleId()); | |
| 148 | + assertEquals(300L, roleMenuList.get(1).getMenuId()); | |
| 118 | 149 | } |
| 119 | 150 | |
| 120 | 151 | @Test |
| 121 | - public void testGetRoleMenuListFromCache_normal() { | |
| 152 | + public void testProcessRoleDeleted() { | |
| 122 | 153 | // 准备参数 |
| 123 | - Collection<Long> roleIds = asSet(100L, 200L); | |
| 124 | - Collection<Integer> menuTypes = asList(2, 3); | |
| 125 | - Collection<Integer> menusStatuses = asList(0, 1); | |
| 126 | - // mock 方法 | |
| 127 | - Multimap<Long, Long> roleMenuCache = ImmutableMultimap.<Long, Long>builder().put(100L, 1000L) | |
| 128 | - .put(200L, 2000L).put(200L, 2001L).build(); | |
| 129 | - permissionService.setRoleMenuCache(roleMenuCache); | |
| 130 | - List<MenuDO> menuList = randomPojoList(MenuDO.class); | |
| 131 | - when(menuService.getMenuListFromCache(eq(asList(1000L, 2000L, 2001L)), eq(menuTypes), eq(menusStatuses))).thenReturn(menuList); | |
| 154 | + Long roleId = randomLongId(); | |
| 155 | + // mock 数据 UserRole | |
| 156 | + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setRoleId(roleId)); // 被删除 | |
| 157 | + userRoleMapper.insert(userRoleDO01); | |
| 158 | + UserRoleDO userRoleDO02 = randomPojo(UserRoleDO.class); // 不被删除 | |
| 159 | + userRoleMapper.insert(userRoleDO02); | |
| 160 | + // mock 数据 RoleMenu | |
| 161 | + RoleMenuDO roleMenuDO01 = randomPojo(RoleMenuDO.class, o -> o.setRoleId(roleId)); // 被删除 | |
| 162 | + roleMenuMapper.insert(roleMenuDO01); | |
| 163 | + RoleMenuDO roleMenuDO02 = randomPojo(RoleMenuDO.class); // 不被删除 | |
| 164 | + roleMenuMapper.insert(roleMenuDO02); | |
| 132 | 165 | |
| 133 | 166 | // 调用 |
| 134 | - List<MenuDO> result = permissionService.getRoleMenuListFromCache(roleIds, menuTypes, menusStatuses); | |
| 135 | - // 断言 | |
| 136 | - assertSame(menuList, result); | |
| 167 | + permissionService.processRoleDeleted(roleId); | |
| 168 | + // 断言数据 RoleMenuDO | |
| 169 | + List<RoleMenuDO> dbRoleMenus = roleMenuMapper.selectList(); | |
| 170 | + assertEquals(1, dbRoleMenus.size()); | |
| 171 | + assertPojoEquals(dbRoleMenus.get(0), roleMenuDO02); | |
| 172 | + // 断言数据 UserRoleDO | |
| 173 | + List<UserRoleDO> dbUserRoles = userRoleMapper.selectList(); | |
| 174 | + assertEquals(1, dbUserRoles.size()); | |
| 175 | + assertPojoEquals(dbUserRoles.get(0), userRoleDO02); | |
| 137 | 176 | } |
| 138 | 177 | |
| 139 | 178 | @Test |
| 140 | - public void testGetUserRoleIdsFromCache() { | |
| 179 | + public void testProcessMenuDeleted() { | |
| 141 | 180 | // 准备参数 |
| 142 | - Long userId = 1L; | |
| 143 | - Collection<Integer> roleStatuses = singleton(CommonStatusEnum.ENABLE.getStatus()); | |
| 144 | - // mock 方法 | |
| 145 | - Map<Long, Set<Long>> userRoleCache = MapUtil.<Long, Set<Long>>builder() | |
| 146 | - .put(1L, asSet(10L, 20L)).build(); | |
| 147 | - permissionService.setUserRoleCache(userRoleCache); | |
| 148 | - RoleDO roleDO01 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 149 | - when(roleService.getRoleFromCache(eq(10L))).thenReturn(roleDO01); | |
| 150 | - RoleDO roleDO02 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())); | |
| 151 | - when(roleService.getRoleFromCache(eq(20L))).thenReturn(roleDO02); | |
| 181 | + Long menuId = randomLongId(); | |
| 182 | + // mock 数据 | |
| 183 | + RoleMenuDO roleMenuDO01 = randomPojo(RoleMenuDO.class, o -> o.setMenuId(menuId)); // 被删除 | |
| 184 | + roleMenuMapper.insert(roleMenuDO01); | |
| 185 | + RoleMenuDO roleMenuDO02 = randomPojo(RoleMenuDO.class); // 不被删除 | |
| 186 | + roleMenuMapper.insert(roleMenuDO02); | |
| 152 | 187 | |
| 153 | 188 | // 调用 |
| 154 | - Set<Long> roleIds = permissionService.getUserRoleIdsFromCache(userId, roleStatuses); | |
| 155 | - // 断言 | |
| 156 | - assertEquals(asSet(10L), roleIds); | |
| 189 | + permissionService.processMenuDeleted(menuId); | |
| 190 | + // 断言数据 | |
| 191 | + List<RoleMenuDO> dbRoleMenus = roleMenuMapper.selectList(); | |
| 192 | + assertEquals(1, dbRoleMenus.size()); | |
| 193 | + assertPojoEquals(dbRoleMenus.get(0), roleMenuDO02); | |
| 157 | 194 | } |
| 158 | 195 | |
| 159 | 196 | @Test |
| ... | ... | @@ -166,7 +203,7 @@ public class PermissionServiceTest extends BaseDbUnitTest { |
| 166 | 203 | when(menuService.getMenuList()).thenReturn(menuList); |
| 167 | 204 | |
| 168 | 205 | // 调用 |
| 169 | - Set<Long> menuIds = permissionService.getRoleMenuIds(roleId); | |
| 206 | + Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(roleId); | |
| 170 | 207 | // 断言 |
| 171 | 208 | assertEquals(singleton(1L), menuIds); |
| 172 | 209 | } |
| ... | ... | @@ -182,34 +219,29 @@ public class PermissionServiceTest extends BaseDbUnitTest { |
| 182 | 219 | roleMenuMapper.insert(roleMenu02); |
| 183 | 220 | |
| 184 | 221 | // 调用 |
| 185 | - Set<Long> menuIds = permissionService.getRoleMenuIds(roleId); | |
| 222 | + Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(roleId); | |
| 186 | 223 | // 断言 |
| 187 | 224 | assertEquals(asSet(1L, 2L), menuIds); |
| 188 | 225 | } |
| 189 | 226 | |
| 190 | 227 | @Test |
| 191 | - public void testAssignRoleMenu() { | |
| 228 | + public void testGetMenuRoleIdListByMenuIdFromCache() { | |
| 192 | 229 | // 准备参数 |
| 193 | - Long roleId = 1L; | |
| 194 | - Set<Long> menuIds = asSet(200L, 300L); | |
| 230 | + Long menuId = 1L; | |
| 195 | 231 | // mock 数据 |
| 196 | - RoleMenuDO roleMenu01 = randomPojo(RoleMenuDO.class).setRoleId(1L).setMenuId(100L); | |
| 232 | + RoleMenuDO roleMenu01 = randomPojo(RoleMenuDO.class).setRoleId(100L).setMenuId(1L); | |
| 197 | 233 | roleMenuMapper.insert(roleMenu01); |
| 198 | - RoleMenuDO roleMenu02 = randomPojo(RoleMenuDO.class).setRoleId(1L).setMenuId(200L); | |
| 234 | + RoleMenuDO roleMenu02 = randomPojo(RoleMenuDO.class).setRoleId(200L).setMenuId(1L); | |
| 199 | 235 | roleMenuMapper.insert(roleMenu02); |
| 200 | 236 | |
| 201 | 237 | // 调用 |
| 202 | - permissionService.assignRoleMenu(roleId, menuIds); | |
| 238 | + Set<Long> roleIds = permissionService.getMenuRoleIdListByMenuIdFromCache(menuId); | |
| 203 | 239 | // 断言 |
| 204 | - List<RoleMenuDO> roleMenuList = roleMenuMapper.selectList(); | |
| 205 | - assertEquals(2, roleMenuList.size()); | |
| 206 | - assertEquals(1L, roleMenuList.get(0).getRoleId()); | |
| 207 | - assertEquals(200L, roleMenuList.get(0).getMenuId()); | |
| 208 | - assertEquals(1L, roleMenuList.get(1).getRoleId()); | |
| 209 | - assertEquals(300L, roleMenuList.get(1).getMenuId()); | |
| 210 | - verify(permissionProducer).sendRoleMenuRefreshMessage(); | |
| 240 | + assertEquals(asSet(100L, 200L), roleIds); | |
| 211 | 241 | } |
| 212 | 242 | |
| 243 | + // ========== 用户-角色的相关方法 ========== | |
| 244 | + | |
| 213 | 245 | @Test |
| 214 | 246 | public void testAssignUserRole() { |
| 215 | 247 | // 准备参数 |
| ... | ... | @@ -230,7 +262,24 @@ public class PermissionServiceTest extends BaseDbUnitTest { |
| 230 | 262 | assertEquals(200L, userRoleDOList.get(0).getRoleId()); |
| 231 | 263 | assertEquals(1L, userRoleDOList.get(1).getUserId()); |
| 232 | 264 | assertEquals(300L, userRoleDOList.get(1).getRoleId()); |
| 233 | - verify(permissionProducer).sendUserRoleRefreshMessage(); | |
| 265 | + } | |
| 266 | + | |
| 267 | + @Test | |
| 268 | + public void testProcessUserDeleted() { | |
| 269 | + // 准备参数 | |
| 270 | + Long userId = randomLongId(); | |
| 271 | + // mock 数据 | |
| 272 | + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(userId)); // 被删除 | |
| 273 | + userRoleMapper.insert(userRoleDO01); | |
| 274 | + UserRoleDO userRoleDO02 = randomPojo(UserRoleDO.class); // 不被删除 | |
| 275 | + userRoleMapper.insert(userRoleDO02); | |
| 276 | + | |
| 277 | + // 调用 | |
| 278 | + permissionService.processUserDeleted(userId); | |
| 279 | + // 断言数据 | |
| 280 | + List<UserRoleDO> dbUserRoles = userRoleMapper.selectList(); | |
| 281 | + assertEquals(1, dbUserRoles.size()); | |
| 282 | + assertPojoEquals(dbUserRoles.get(0), userRoleDO02); | |
| 234 | 283 | } |
| 235 | 284 | |
| 236 | 285 | @Test |
| ... | ... | @@ -250,296 +299,229 @@ public class PermissionServiceTest extends BaseDbUnitTest { |
| 250 | 299 | } |
| 251 | 300 | |
| 252 | 301 | @Test |
| 253 | - public void testGetUserRoleIdListByRoleIds() { | |
| 302 | + public void testGetUserRoleIdListByUserIdFromCache() { | |
| 254 | 303 | // 准备参数 |
| 255 | - Collection<Long> roleIds = asSet(10L, 20L); | |
| 304 | + Long userId = 1L; | |
| 256 | 305 | // mock 数据 |
| 257 | 306 | UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); |
| 258 | 307 | userRoleMapper.insert(userRoleDO01); |
| 259 | - UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(2L).setRoleId(20L)); | |
| 308 | + UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(20L)); | |
| 260 | 309 | userRoleMapper.insert(roleMenuDO02); |
| 261 | 310 | |
| 262 | 311 | // 调用 |
| 263 | - Set<Long> result = permissionService.getUserRoleIdListByRoleIds(roleIds); | |
| 312 | + Set<Long> result = permissionService.getUserRoleIdListByUserIdFromCache(userId); | |
| 264 | 313 | // 断言 |
| 265 | - assertEquals(asSet(1L, 2L), result); | |
| 266 | - } | |
| 267 | - | |
| 268 | - @Test | |
| 269 | - public void testAssignRoleDataScope() { | |
| 270 | - // 准备参数 | |
| 271 | - Long roleId = 1L; | |
| 272 | - Integer dataScope = 2; | |
| 273 | - Set<Long> dataScopeDeptIds = asSet(10L, 20L); | |
| 274 | - | |
| 275 | - // 调用 | |
| 276 | - permissionService.assignRoleDataScope(roleId, dataScope, dataScopeDeptIds); | |
| 277 | - // 断言 | |
| 278 | - verify(roleService).updateRoleDataScope(eq(roleId), eq(dataScope), eq(dataScopeDeptIds)); | |
| 279 | - } | |
| 280 | - | |
| 281 | - @Test | |
| 282 | - public void testProcessRoleDeleted() { | |
| 283 | - // 准备参数 | |
| 284 | - Long roleId = randomLongId(); | |
| 285 | - // mock 数据 UserRole | |
| 286 | - UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setRoleId(roleId)); // 被删除 | |
| 287 | - userRoleMapper.insert(userRoleDO01); | |
| 288 | - UserRoleDO userRoleDO02 = randomPojo(UserRoleDO.class); // 不被删除 | |
| 289 | - userRoleMapper.insert(userRoleDO02); | |
| 290 | - // mock 数据 RoleMenu | |
| 291 | - RoleMenuDO roleMenuDO01 = randomPojo(RoleMenuDO.class, o -> o.setRoleId(roleId)); // 被删除 | |
| 292 | - roleMenuMapper.insert(roleMenuDO01); | |
| 293 | - RoleMenuDO roleMenuDO02 = randomPojo(RoleMenuDO.class); // 不被删除 | |
| 294 | - roleMenuMapper.insert(roleMenuDO02); | |
| 295 | - | |
| 296 | - // 调用 | |
| 297 | - permissionService.processRoleDeleted(roleId); | |
| 298 | - // 断言数据 RoleMenuDO | |
| 299 | - List<RoleMenuDO> dbRoleMenus = roleMenuMapper.selectList(); | |
| 300 | - assertEquals(1, dbRoleMenus.size()); | |
| 301 | - assertPojoEquals(dbRoleMenus.get(0), roleMenuDO02); | |
| 302 | - // 断言数据 UserRoleDO | |
| 303 | - List<UserRoleDO> dbUserRoles = userRoleMapper.selectList(); | |
| 304 | - assertEquals(1, dbUserRoles.size()); | |
| 305 | - assertPojoEquals(dbUserRoles.get(0), userRoleDO02); | |
| 306 | - // 断言调用 | |
| 307 | - verify(permissionProducer).sendRoleMenuRefreshMessage(); | |
| 308 | - verify(permissionProducer).sendUserRoleRefreshMessage(); | |
| 314 | + assertEquals(asSet(10L, 20L), result); | |
| 309 | 315 | } |
| 310 | 316 | |
| 311 | 317 | @Test |
| 312 | - public void testProcessMenuDeleted() { | |
| 318 | + public void testGetUserRoleIdsFromCache() { | |
| 313 | 319 | // 准备参数 |
| 314 | - Long menuId = randomLongId(); | |
| 320 | + Long userId = 1L; | |
| 315 | 321 | // mock 数据 |
| 316 | - RoleMenuDO roleMenuDO01 = randomPojo(RoleMenuDO.class, o -> o.setMenuId(menuId)); // 被删除 | |
| 317 | - roleMenuMapper.insert(roleMenuDO01); | |
| 318 | - RoleMenuDO roleMenuDO02 = randomPojo(RoleMenuDO.class); // 不被删除 | |
| 319 | - roleMenuMapper.insert(roleMenuDO02); | |
| 322 | + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); | |
| 323 | + userRoleMapper.insert(userRoleDO01); | |
| 324 | + UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(20L)); | |
| 325 | + userRoleMapper.insert(roleMenuDO02); | |
| 320 | 326 | |
| 321 | 327 | // 调用 |
| 322 | - permissionService.processMenuDeleted(menuId); | |
| 323 | - // 断言数据 | |
| 324 | - List<RoleMenuDO> dbRoleMenus = roleMenuMapper.selectList(); | |
| 325 | - assertEquals(1, dbRoleMenus.size()); | |
| 326 | - assertPojoEquals(dbRoleMenus.get(0), roleMenuDO02); | |
| 327 | - // 断言调用 | |
| 328 | - verify(permissionProducer).sendRoleMenuRefreshMessage(); | |
| 328 | + Set<Long> result = permissionService.getUserRoleIdListByUserIdFromCache(userId); | |
| 329 | + // 断言 | |
| 330 | + assertEquals(asSet(10L, 20L), result); | |
| 329 | 331 | } |
| 330 | 332 | |
| 331 | 333 | @Test |
| 332 | - public void testProcessUserDeleted() { | |
| 334 | + public void testGetUserRoleIdListByRoleId() { | |
| 333 | 335 | // 准备参数 |
| 334 | - Long userId = randomLongId(); | |
| 336 | + Collection<Long> roleIds = asSet(10L, 20L); | |
| 335 | 337 | // mock 数据 |
| 336 | - UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(userId)); // 被删除 | |
| 338 | + UserRoleDO userRoleDO01 = randomPojo(UserRoleDO.class, o -> o.setUserId(1L).setRoleId(10L)); | |
| 337 | 339 | userRoleMapper.insert(userRoleDO01); |
| 338 | - UserRoleDO userRoleDO02 = randomPojo(UserRoleDO.class); // 不被删除 | |
| 339 | - userRoleMapper.insert(userRoleDO02); | |
| 340 | - | |
| 341 | - // 调用 | |
| 342 | - permissionService.processUserDeleted(userId); | |
| 343 | - // 断言数据 | |
| 344 | - List<UserRoleDO> dbUserRoles = userRoleMapper.selectList(); | |
| 345 | - assertEquals(1, dbUserRoles.size()); | |
| 346 | - assertPojoEquals(dbUserRoles.get(0), userRoleDO02); | |
| 347 | - // 断言调用 | |
| 348 | - verify(permissionProducer).sendUserRoleRefreshMessage(); | |
| 349 | - } | |
| 350 | - | |
| 351 | - @Test | |
| 352 | - public void testHasAnyPermissions_superAdmin() { | |
| 353 | - // 准备参数 | |
| 354 | - Long userId = 1L; | |
| 355 | - String[] roles = new String[]{"system:user:query", "system:user:create"}; | |
| 356 | - // mock 用户与角色的缓存 | |
| 357 | - permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(100L)).build()); | |
| 358 | - RoleDO role = randomPojo(RoleDO.class, o -> o.setId(100L) | |
| 359 | - .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 360 | - when(roleService.getRoleFromCache(eq(100L))).thenReturn(role); | |
| 361 | - // mock 其它方法 | |
| 362 | - when(roleService.hasAnySuperAdmin(eq(asSet(100L)))).thenReturn(true); | |
| 340 | + UserRoleDO roleMenuDO02 = randomPojo(UserRoleDO.class, o -> o.setUserId(2L).setRoleId(20L)); | |
| 341 | + userRoleMapper.insert(roleMenuDO02); | |
| 363 | 342 | |
| 364 | 343 | // 调用 |
| 365 | - boolean has = permissionService.hasAnyPermissions(userId, roles); | |
| 344 | + Set<Long> result = permissionService.getUserRoleIdListByRoleId(roleIds); | |
| 366 | 345 | // 断言 |
| 367 | - assertTrue(has); | |
| 346 | + assertEquals(asSet(1L, 2L), result); | |
| 368 | 347 | } |
| 369 | 348 | |
| 370 | 349 | @Test |
| 371 | - public void testHasAnyPermissions_normal() { | |
| 372 | - // 准备参数 | |
| 373 | - Long userId = 1L; | |
| 374 | - String[] roles = new String[]{"system:user:query", "system:user:create"}; | |
| 375 | - // mock 用户与角色的缓存 | |
| 376 | - permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(100L)).build()); | |
| 377 | - RoleDO role = randomPojo(RoleDO.class, o -> o.setId(100L) | |
| 378 | - .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 379 | - when(roleService.getRoleFromCache(eq(100L))).thenReturn(role); | |
| 380 | - // mock 其它方法 | |
| 381 | - MenuDO menu = randomPojo(MenuDO.class, o -> o.setId(1000L)); | |
| 382 | - when(menuService.getMenuListByPermissionFromCache(eq("system:user:create"))).thenReturn(singletonList(menu)); | |
| 383 | - permissionService.setMenuRoleCache(ImmutableMultimap.<Long, Long>builder().put(1000L, 100L).build()); | |
| 384 | - | |
| 385 | - | |
| 386 | - // 调用 | |
| 387 | - boolean has = permissionService.hasAnyPermissions(userId, roles); | |
| 388 | - // 断言 | |
| 389 | - assertTrue(has); | |
| 350 | + public void testGetEnableUserRoleListByUserIdFromCache() { | |
| 351 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | |
| 352 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) | |
| 353 | + .thenReturn(permissionService); | |
| 354 | + | |
| 355 | + // 准备参数 | |
| 356 | + Long userId = 1L; | |
| 357 | + // mock 用户登录的角色 | |
| 358 | + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(100L)); | |
| 359 | + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(200L)); | |
| 360 | + RoleDO role01 = randomPojo(RoleDO.class, o -> o.setId(100L) | |
| 361 | + .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 362 | + RoleDO role02 = randomPojo(RoleDO.class, o -> o.setId(200L) | |
| 363 | + .setStatus(CommonStatusEnum.DISABLE.getStatus())); | |
| 364 | + when(roleService.getRoleListFromCache(eq(asSet(100L, 200L)))) | |
| 365 | + .thenReturn(toList(role01, role02)); | |
| 366 | + | |
| 367 | + // 调用 | |
| 368 | + List<RoleDO> result = permissionService.getEnableUserRoleListByUserIdFromCache(userId); | |
| 369 | + // 断言 | |
| 370 | + assertEquals(1, result.size()); | |
| 371 | + assertPojoEquals(role01, result.get(0)); | |
| 372 | + } | |
| 390 | 373 | } |
| 391 | 374 | |
| 392 | - @Test | |
| 393 | - public void testHasAnyRoles_superAdmin() { | |
| 394 | - // 准备参数 | |
| 395 | - Long userId = 1L; | |
| 396 | - String[] roles = new String[]{"yunai", "tudou"}; | |
| 397 | - // mock 用户与角色的缓存 | |
| 398 | - permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(100L)).build()); | |
| 399 | - RoleDO role = randomPojo(RoleDO.class, o -> o.setId(100L) | |
| 400 | - .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 401 | - when(roleService.getRoleFromCache(eq(100L))).thenReturn(role); | |
| 402 | - // mock 其它方法 | |
| 403 | - when(roleService.hasAnySuperAdmin(eq(asSet(100L)))).thenReturn(true); | |
| 404 | - | |
| 405 | - // 调用 | |
| 406 | - boolean has = permissionService.hasAnyRoles(userId, roles); | |
| 407 | - // 断言 | |
| 408 | - assertTrue(has); | |
| 409 | - } | |
| 375 | + // ========== 用户-部门的相关方法 ========== | |
| 410 | 376 | |
| 411 | 377 | @Test |
| 412 | - public void testHasAnyRoles_normal() { | |
| 378 | + public void testAssignRoleDataScope() { | |
| 413 | 379 | // 准备参数 |
| 414 | - Long userId = 1L; | |
| 415 | - String[] roles = new String[]{"yunai", "tudou"}; | |
| 416 | - // mock 用户与角色的缓存 | |
| 417 | - permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(100L)).build()); | |
| 418 | - RoleDO role = randomPojo(RoleDO.class, o -> o.setId(100L).setCode("yunai") | |
| 419 | - .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 420 | - when(roleService.getRoleFromCache(eq(100L))).thenReturn(role); | |
| 421 | - // mock 其它方法 | |
| 422 | - when(roleService.getRoleListFromCache(eq(asSet(100L)))).thenReturn(singletonList(role)); | |
| 380 | + Long roleId = 1L; | |
| 381 | + Integer dataScope = 2; | |
| 382 | + Set<Long> dataScopeDeptIds = asSet(10L, 20L); | |
| 423 | 383 | |
| 424 | 384 | // 调用 |
| 425 | - boolean has = permissionService.hasAnyRoles(userId, roles); | |
| 385 | + permissionService.assignRoleDataScope(roleId, dataScope, dataScopeDeptIds); | |
| 426 | 386 | // 断言 |
| 427 | - assertTrue(has); | |
| 387 | + verify(roleService).updateRoleDataScope(eq(roleId), eq(dataScope), eq(dataScopeDeptIds)); | |
| 428 | 388 | } |
| 429 | 389 | |
| 430 | 390 | @Test |
| 431 | 391 | public void testGetDeptDataPermission_All() { |
| 432 | - // 准备参数 | |
| 433 | - Long userId = 1L; | |
| 434 | - // mock 用户的角色编号 | |
| 435 | - permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(2L)).build()); | |
| 436 | - // mock 获得用户的角色 | |
| 437 | - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.ALL.getScope()) | |
| 438 | - .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 439 | - when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO)); | |
| 440 | - when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO); | |
| 441 | - | |
| 442 | - // 调用 | |
| 443 | - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); | |
| 444 | - // 断言 | |
| 445 | - assertTrue(result.getAll()); | |
| 446 | - assertFalse(result.getSelf()); | |
| 447 | - assertTrue(CollUtil.isEmpty(result.getDeptIds())); | |
| 392 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | |
| 393 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) | |
| 394 | + .thenReturn(permissionService); | |
| 395 | + | |
| 396 | + // 准备参数 | |
| 397 | + Long userId = 1L; | |
| 398 | + // mock 用户的角色编号 | |
| 399 | + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(2L)); | |
| 400 | + // mock 获得用户的角色 | |
| 401 | + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.ALL.getScope()) | |
| 402 | + .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 403 | + when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(toList(roleDO)); | |
| 404 | + | |
| 405 | + // 调用 | |
| 406 | + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); | |
| 407 | + // 断言 | |
| 408 | + assertTrue(result.getAll()); | |
| 409 | + assertFalse(result.getSelf()); | |
| 410 | + assertTrue(CollUtil.isEmpty(result.getDeptIds())); | |
| 411 | + } | |
| 448 | 412 | } |
| 449 | 413 | |
| 450 | 414 | @Test |
| 451 | 415 | public void testGetDeptDataPermission_DeptCustom() { |
| 452 | - // 准备参数 | |
| 453 | - Long userId = 1L; | |
| 454 | - // mock 用户的角色编号 | |
| 455 | - permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(2L)).build()); | |
| 456 | - // mock 获得用户的角色 | |
| 457 | - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_CUSTOM.getScope()) | |
| 458 | - .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 459 | - when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO)); | |
| 460 | - when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO); | |
| 461 | - // mock 部门的返回 | |
| 462 | - when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用 | |
| 463 | - | |
| 464 | - // 调用 | |
| 465 | - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); | |
| 466 | - // 断言 | |
| 467 | - assertFalse(result.getAll()); | |
| 468 | - assertFalse(result.getSelf()); | |
| 469 | - assertEquals(roleDO.getDataScopeDeptIds().size() + 1, result.getDeptIds().size()); | |
| 470 | - assertTrue(CollUtil.containsAll(result.getDeptIds(), roleDO.getDataScopeDeptIds())); | |
| 471 | - assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); | |
| 416 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | |
| 417 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) | |
| 418 | + .thenReturn(permissionService); | |
| 419 | + | |
| 420 | + // 准备参数 | |
| 421 | + Long userId = 1L; | |
| 422 | + // mock 用户的角色编号 | |
| 423 | + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(2L)); | |
| 424 | + // mock 获得用户的角色 | |
| 425 | + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_CUSTOM.getScope()) | |
| 426 | + .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 427 | + when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(toList(roleDO)); | |
| 428 | + // mock 部门的返回 | |
| 429 | + when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), | |
| 430 | + null, null); // 最后返回 null 的目的,看看会不会重复调用 | |
| 431 | + | |
| 432 | + // 调用 | |
| 433 | + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); | |
| 434 | + // 断言 | |
| 435 | + assertFalse(result.getAll()); | |
| 436 | + assertFalse(result.getSelf()); | |
| 437 | + assertEquals(roleDO.getDataScopeDeptIds().size() + 1, result.getDeptIds().size()); | |
| 438 | + assertTrue(CollUtil.containsAll(result.getDeptIds(), roleDO.getDataScopeDeptIds())); | |
| 439 | + assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); | |
| 440 | + } | |
| 472 | 441 | } |
| 473 | 442 | |
| 474 | 443 | @Test |
| 475 | 444 | public void testGetDeptDataPermission_DeptOnly() { |
| 476 | - // 准备参数 | |
| 477 | - Long userId = 1L; | |
| 478 | - // mock 用户的角色编号 | |
| 479 | - permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(2L)).build()); | |
| 480 | - // mock 获得用户的角色 | |
| 481 | - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_ONLY.getScope()) | |
| 482 | - .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 483 | - when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO)); | |
| 484 | - when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO); | |
| 485 | - // mock 部门的返回 | |
| 486 | - when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用 | |
| 487 | - | |
| 488 | - // 调用 | |
| 489 | - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); | |
| 490 | - // 断言 | |
| 491 | - assertFalse(result.getAll()); | |
| 492 | - assertFalse(result.getSelf()); | |
| 493 | - assertEquals(1, result.getDeptIds().size()); | |
| 494 | - assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); | |
| 445 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | |
| 446 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) | |
| 447 | + .thenReturn(permissionService); | |
| 448 | + | |
| 449 | + // 准备参数 | |
| 450 | + Long userId = 1L; | |
| 451 | + // mock 用户的角色编号 | |
| 452 | + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(2L)); | |
| 453 | + // mock 获得用户的角色 | |
| 454 | + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_ONLY.getScope()) | |
| 455 | + .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 456 | + when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(toList(roleDO)); | |
| 457 | + // mock 部门的返回 | |
| 458 | + when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), | |
| 459 | + null, null); // 最后返回 null 的目的,看看会不会重复调用 | |
| 460 | + | |
| 461 | + // 调用 | |
| 462 | + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); | |
| 463 | + // 断言 | |
| 464 | + assertFalse(result.getAll()); | |
| 465 | + assertFalse(result.getSelf()); | |
| 466 | + assertEquals(1, result.getDeptIds().size()); | |
| 467 | + assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); | |
| 468 | + } | |
| 495 | 469 | } |
| 496 | 470 | |
| 497 | 471 | @Test |
| 498 | 472 | public void testGetDeptDataPermission_DeptAndChild() { |
| 499 | - // 准备参数 | |
| 500 | - Long userId = 1L; | |
| 501 | - // mock 用户的角色编号 | |
| 502 | - permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(2L)).build()); | |
| 503 | - // mock 获得用户的角色 | |
| 504 | - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_AND_CHILD.getScope()) | |
| 505 | - .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 506 | - when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO)); | |
| 507 | - when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO); | |
| 508 | - // mock 部门的返回 | |
| 509 | - when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用 | |
| 510 | - // mock 方法(部门) | |
| 511 | - DeptDO deptDO = randomPojo(DeptDO.class); | |
| 512 | - when(deptService.getDeptListByParentIdFromCache(eq(3L), eq(true))) | |
| 513 | - .thenReturn(singletonList(deptDO)); | |
| 514 | - | |
| 515 | - // 调用 | |
| 516 | - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); | |
| 517 | - // 断言 | |
| 518 | - assertFalse(result.getAll()); | |
| 519 | - assertFalse(result.getSelf()); | |
| 520 | - assertEquals(2, result.getDeptIds().size()); | |
| 521 | - assertTrue(CollUtil.contains(result.getDeptIds(), deptDO.getId())); | |
| 522 | - assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); | |
| 473 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | |
| 474 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) | |
| 475 | + .thenReturn(permissionService); | |
| 476 | + | |
| 477 | + // 准备参数 | |
| 478 | + Long userId = 1L; | |
| 479 | + // mock 用户的角色编号 | |
| 480 | + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(2L)); | |
| 481 | + // mock 获得用户的角色 | |
| 482 | + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_AND_CHILD.getScope()) | |
| 483 | + .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 484 | + when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(toList(roleDO)); | |
| 485 | + // mock 部门的返回 | |
| 486 | + when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), | |
| 487 | + null, null); // 最后返回 null 的目的,看看会不会重复调用 | |
| 488 | + // mock 方法(部门) | |
| 489 | + DeptDO deptDO = randomPojo(DeptDO.class); | |
| 490 | + when(deptService.getChildDeptIdListFromCache(eq(3L))).thenReturn(singleton(deptDO.getId())); | |
| 491 | + | |
| 492 | + // 调用 | |
| 493 | + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); | |
| 494 | + // 断言 | |
| 495 | + assertFalse(result.getAll()); | |
| 496 | + assertFalse(result.getSelf()); | |
| 497 | + assertEquals(2, result.getDeptIds().size()); | |
| 498 | + assertTrue(CollUtil.contains(result.getDeptIds(), deptDO.getId())); | |
| 499 | + assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); | |
| 500 | + } | |
| 523 | 501 | } |
| 524 | 502 | |
| 525 | 503 | @Test |
| 526 | 504 | public void testGetDeptDataPermission_Self() { |
| 527 | - // 准备参数 | |
| 528 | - Long userId = 1L; | |
| 529 | - // mock 用户的角色编号 | |
| 530 | - permissionService.setUserRoleCache(MapUtil.<Long, Set<Long>>builder().put(1L, asSet(2L)).build()); | |
| 531 | - // mock 获得用户的角色 | |
| 532 | - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.SELF.getScope()) | |
| 533 | - .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 534 | - when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO)); | |
| 535 | - when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO); | |
| 536 | - | |
| 537 | - // 调用 | |
| 538 | - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); | |
| 539 | - // 断言 | |
| 540 | - assertFalse(result.getAll()); | |
| 541 | - assertTrue(result.getSelf()); | |
| 542 | - assertTrue(CollUtil.isEmpty(result.getDeptIds())); | |
| 505 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | |
| 506 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PermissionServiceImpl.class))) | |
| 507 | + .thenReturn(permissionService); | |
| 508 | + | |
| 509 | + // 准备参数 | |
| 510 | + Long userId = 1L; | |
| 511 | + // mock 用户的角色编号 | |
| 512 | + userRoleMapper.insert(randomPojo(UserRoleDO.class).setUserId(userId).setRoleId(2L)); | |
| 513 | + // mock 获得用户的角色 | |
| 514 | + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.SELF.getScope()) | |
| 515 | + .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 516 | + when(roleService.getRoleListFromCache(eq(singleton(2L)))).thenReturn(toList(roleDO)); | |
| 517 | + | |
| 518 | + // 调用 | |
| 519 | + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); | |
| 520 | + // 断言 | |
| 521 | + assertFalse(result.getAll()); | |
| 522 | + assertTrue(result.getSelf()); | |
| 523 | + assertTrue(CollUtil.isEmpty(result.getDeptIds())); | |
| 524 | + } | |
| 543 | 525 | } |
| 544 | 526 | |
| 545 | 527 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImplTest.java
| 1 | 1 | package cn.iocoder.yudao.module.system.service.permission; |
| 2 | 2 | |
| 3 | +import cn.hutool.extra.spring.SpringUtil; | |
| 3 | 4 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 4 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | 6 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| ... | ... | @@ -11,15 +12,14 @@ import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; |
| 11 | 12 | import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMapper; |
| 12 | 13 | import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; |
| 13 | 14 | import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; |
| 14 | -import cn.iocoder.yudao.module.system.mq.producer.permission.RoleProducer; | |
| 15 | 15 | import org.junit.jupiter.api.Test; |
| 16 | +import org.mockito.MockedStatic; | |
| 16 | 17 | import org.springframework.boot.test.mock.mockito.MockBean; |
| 17 | 18 | import org.springframework.context.annotation.Import; |
| 18 | 19 | |
| 19 | 20 | import javax.annotation.Resource; |
| 20 | 21 | import java.util.Collection; |
| 21 | 22 | import java.util.List; |
| 22 | -import java.util.Map; | |
| 23 | 23 | import java.util.Set; |
| 24 | 24 | |
| 25 | 25 | import static cn.hutool.core.util.RandomUtil.randomEle; |
| ... | ... | @@ -33,6 +33,8 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; |
| 33 | 33 | import static java.util.Collections.singleton; |
| 34 | 34 | import static java.util.Collections.singletonList; |
| 35 | 35 | import static org.junit.jupiter.api.Assertions.*; |
| 36 | +import static org.mockito.ArgumentMatchers.eq; | |
| 37 | +import static org.mockito.Mockito.mockStatic; | |
| 36 | 38 | import static org.mockito.Mockito.verify; |
| 37 | 39 | |
| 38 | 40 | @Import(RoleServiceImpl.class) |
| ... | ... | @@ -46,26 +48,9 @@ public class RoleServiceImplTest extends BaseDbUnitTest { |
| 46 | 48 | |
| 47 | 49 | @MockBean |
| 48 | 50 | private PermissionService permissionService; |
| 49 | - @MockBean | |
| 50 | - private RoleProducer roleProducer; | |
| 51 | 51 | |
| 52 | 52 | @Test |
| 53 | - public void testInitLocalCache() { | |
| 54 | - RoleDO roleDO1 = randomPojo(RoleDO.class); | |
| 55 | - roleMapper.insert(roleDO1); | |
| 56 | - RoleDO roleDO2 = randomPojo(RoleDO.class); | |
| 57 | - roleMapper.insert(roleDO2); | |
| 58 | - | |
| 59 | - // 调用 | |
| 60 | - roleService.initLocalCache(); | |
| 61 | - // 断言 roleCache 缓存 | |
| 62 | - Map<Long, RoleDO> roleCache = roleService.getRoleCache(); | |
| 63 | - assertPojoEquals(roleDO1, roleCache.get(roleDO1.getId())); | |
| 64 | - assertPojoEquals(roleDO2, roleCache.get(roleDO2.getId())); | |
| 65 | - } | |
| 66 | - | |
| 67 | - @Test | |
| 68 | - public void testCreateRole_success() { | |
| 53 | + public void testCreateRole() { | |
| 69 | 54 | // 准备参数 |
| 70 | 55 | RoleCreateReqVO reqVO = randomPojo(RoleCreateReqVO.class); |
| 71 | 56 | |
| ... | ... | @@ -77,12 +62,10 @@ public class RoleServiceImplTest extends BaseDbUnitTest { |
| 77 | 62 | assertEquals(RoleTypeEnum.CUSTOM.getType(), roleDO.getType()); |
| 78 | 63 | assertEquals(CommonStatusEnum.ENABLE.getStatus(), roleDO.getStatus()); |
| 79 | 64 | assertEquals(DataScopeEnum.ALL.getScope(), roleDO.getDataScope()); |
| 80 | - // verify 发送刷新消息 | |
| 81 | - verify(roleProducer).sendRoleRefreshMessage(); | |
| 82 | 65 | } |
| 83 | 66 | |
| 84 | 67 | @Test |
| 85 | - public void testUpdateRole_success() { | |
| 68 | + public void testUpdateRole() { | |
| 86 | 69 | // mock 数据 |
| 87 | 70 | RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setType(RoleTypeEnum.CUSTOM.getType())); |
| 88 | 71 | roleMapper.insert(roleDO); |
| ... | ... | @@ -95,12 +78,10 @@ public class RoleServiceImplTest extends BaseDbUnitTest { |
| 95 | 78 | // 断言 |
| 96 | 79 | RoleDO newRoleDO = roleMapper.selectById(id); |
| 97 | 80 | assertPojoEquals(reqVO, newRoleDO); |
| 98 | - // verify 发送刷新消息 | |
| 99 | - verify(roleProducer).sendRoleRefreshMessage(); | |
| 100 | 81 | } |
| 101 | 82 | |
| 102 | 83 | @Test |
| 103 | - public void testUpdateRoleStatus_success() { | |
| 84 | + public void testUpdateRoleStatus() { | |
| 104 | 85 | // mock 数据 |
| 105 | 86 | RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()) |
| 106 | 87 | .setType(RoleTypeEnum.CUSTOM.getType())); |
| ... | ... | @@ -114,12 +95,10 @@ public class RoleServiceImplTest extends BaseDbUnitTest { |
| 114 | 95 | // 断言 |
| 115 | 96 | RoleDO dbRoleDO = roleMapper.selectById(roleId); |
| 116 | 97 | assertEquals(CommonStatusEnum.DISABLE.getStatus(), dbRoleDO.getStatus()); |
| 117 | - // verify 发送刷新消息 | |
| 118 | - verify(roleProducer).sendRoleRefreshMessage(); | |
| 119 | 98 | } |
| 120 | 99 | |
| 121 | 100 | @Test |
| 122 | - public void testUpdateRoleDataScope_success() { | |
| 101 | + public void testUpdateRoleDataScope() { | |
| 123 | 102 | // mock 数据 |
| 124 | 103 | RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setType(RoleTypeEnum.CUSTOM.getType())); |
| 125 | 104 | roleMapper.insert(roleDO); |
| ... | ... | @@ -134,12 +113,10 @@ public class RoleServiceImplTest extends BaseDbUnitTest { |
| 134 | 113 | RoleDO dbRoleDO = roleMapper.selectById(id); |
| 135 | 114 | assertEquals(dataScope, dbRoleDO.getDataScope()); |
| 136 | 115 | assertEquals(dataScopeRoleIds, dbRoleDO.getDataScopeDeptIds()); |
| 137 | - // verify 发送刷新消息 | |
| 138 | - verify(roleProducer).sendRoleRefreshMessage(); | |
| 139 | 116 | } |
| 140 | 117 | |
| 141 | 118 | @Test |
| 142 | - public void testDeleteRole_success() { | |
| 119 | + public void testDeleteRole() { | |
| 143 | 120 | // mock 数据 |
| 144 | 121 | RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setType(RoleTypeEnum.CUSTOM.getType())); |
| 145 | 122 | roleMapper.insert(roleDO); |
| ... | ... | @@ -152,23 +129,65 @@ public class RoleServiceImplTest extends BaseDbUnitTest { |
| 152 | 129 | assertNull(roleMapper.selectById(id)); |
| 153 | 130 | // verify 删除相关数据 |
| 154 | 131 | verify(permissionService).processRoleDeleted(id); |
| 155 | - // verify 发送刷新消息 | |
| 156 | - verify(roleProducer).sendRoleRefreshMessage(); | |
| 157 | 132 | } |
| 158 | 133 | |
| 159 | 134 | @Test |
| 160 | - public void testGetRoleFromCache() { | |
| 161 | - // mock 数据(缓存) | |
| 135 | + public void testValidateRoleDuplicate_success() { | |
| 136 | + // 调用,不会抛异常 | |
| 137 | + roleService.validateRoleDuplicate(randomString(), randomString(), null); | |
| 138 | + } | |
| 139 | + | |
| 140 | + @Test | |
| 141 | + public void testValidateRoleDuplicate_nameDuplicate() { | |
| 142 | + // mock 数据 | |
| 143 | + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setName("role_name")); | |
| 144 | + roleMapper.insert(roleDO); | |
| 145 | + // 准备参数 | |
| 146 | + String name = "role_name"; | |
| 147 | + | |
| 148 | + // 调用,并断言异常 | |
| 149 | + assertServiceException(() -> roleService.validateRoleDuplicate(name, randomString(), null), | |
| 150 | + ROLE_NAME_DUPLICATE, name); | |
| 151 | + } | |
| 152 | + | |
| 153 | + @Test | |
| 154 | + public void testValidateRoleDuplicate_codeDuplicate() { | |
| 155 | + // mock 数据 | |
| 156 | + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setCode("code")); | |
| 157 | + roleMapper.insert(roleDO); | |
| 158 | + // 准备参数 | |
| 159 | + String code = "code"; | |
| 160 | + | |
| 161 | + // 调用,并断言异常 | |
| 162 | + assertServiceException(() -> roleService.validateRoleDuplicate(randomString(), code, null), | |
| 163 | + ROLE_CODE_DUPLICATE, code); | |
| 164 | + } | |
| 165 | + | |
| 166 | + @Test | |
| 167 | + public void testValidateUpdateRole_success() { | |
| 162 | 168 | RoleDO roleDO = randomPojo(RoleDO.class); |
| 163 | 169 | roleMapper.insert(roleDO); |
| 164 | - roleService.initLocalCache(); | |
| 165 | - // 参数准备 | |
| 170 | + // 准备参数 | |
| 166 | 171 | Long id = roleDO.getId(); |
| 167 | 172 | |
| 168 | - // 调用 | |
| 169 | - RoleDO dbRoleDO = roleService.getRoleFromCache(id); | |
| 170 | - // 断言 | |
| 171 | - assertPojoEquals(roleDO, dbRoleDO); | |
| 173 | + // 调用,无异常 | |
| 174 | + roleService.validateRoleForUpdate(id); | |
| 175 | + } | |
| 176 | + | |
| 177 | + @Test | |
| 178 | + public void testValidateUpdateRole_roleIdNotExist() { | |
| 179 | + assertServiceException(() -> roleService.validateRoleForUpdate(randomLongId()), ROLE_NOT_EXISTS); | |
| 180 | + } | |
| 181 | + | |
| 182 | + @Test | |
| 183 | + public void testValidateUpdateRole_systemRoleCanNotBeUpdate() { | |
| 184 | + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setType(RoleTypeEnum.SYSTEM.getType())); | |
| 185 | + roleMapper.insert(roleDO); | |
| 186 | + // 准备参数 | |
| 187 | + Long id = roleDO.getId(); | |
| 188 | + | |
| 189 | + assertServiceException(() -> roleService.validateRoleForUpdate(id), | |
| 190 | + ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE); | |
| 172 | 191 | } |
| 173 | 192 | |
| 174 | 193 | @Test |
| ... | ... | @@ -186,22 +205,21 @@ public class RoleServiceImplTest extends BaseDbUnitTest { |
| 186 | 205 | } |
| 187 | 206 | |
| 188 | 207 | @Test |
| 189 | - public void testGetRoleListByStatus_statusNotEmpty() { | |
| 190 | - // mock 数据 | |
| 191 | - RoleDO dbRole = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 192 | - roleMapper.insert(dbRole); | |
| 193 | - // 测试 status 不匹配 | |
| 194 | - roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); | |
| 208 | + public void testGetRoleFromCache() { | |
| 209 | + // mock 数据(缓存) | |
| 210 | + RoleDO roleDO = randomPojo(RoleDO.class); | |
| 211 | + roleMapper.insert(roleDO); | |
| 212 | + // 参数准备 | |
| 213 | + Long id = roleDO.getId(); | |
| 195 | 214 | |
| 196 | 215 | // 调用 |
| 197 | - List<RoleDO> list = roleService.getRoleListByStatus(singleton(CommonStatusEnum.ENABLE.getStatus())); | |
| 216 | + RoleDO dbRoleDO = roleService.getRoleFromCache(id); | |
| 198 | 217 | // 断言 |
| 199 | - assertEquals(1, list.size()); | |
| 200 | - assertPojoEquals(dbRole, list.get(0)); | |
| 218 | + assertPojoEquals(roleDO, dbRoleDO); | |
| 201 | 219 | } |
| 202 | 220 | |
| 203 | 221 | @Test |
| 204 | - public void testGetRoleListByStatus_statusEmpty() { | |
| 222 | + public void testGetRoleListByStatus() { | |
| 205 | 223 | // mock 数据 |
| 206 | 224 | RoleDO dbRole01 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); |
| 207 | 225 | roleMapper.insert(dbRole01); |
| ... | ... | @@ -209,29 +227,33 @@ public class RoleServiceImplTest extends BaseDbUnitTest { |
| 209 | 227 | roleMapper.insert(dbRole02); |
| 210 | 228 | |
| 211 | 229 | // 调用 |
| 212 | - List<RoleDO> list = roleService.getRoleListByStatus(null); | |
| 230 | + List<RoleDO> list = roleService.getRoleListByStatus( | |
| 231 | + singleton(CommonStatusEnum.ENABLE.getStatus())); | |
| 213 | 232 | // 断言 |
| 214 | - assertEquals(2, list.size()); | |
| 233 | + assertEquals(1, list.size()); | |
| 215 | 234 | assertPojoEquals(dbRole01, list.get(0)); |
| 216 | - assertPojoEquals(dbRole02, list.get(1)); | |
| 217 | 235 | } |
| 218 | 236 | |
| 219 | 237 | @Test |
| 220 | 238 | public void testGetRoleListFromCache() { |
| 221 | - // mock 数据 | |
| 222 | - RoleDO dbRole = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 223 | - roleMapper.insert(dbRole); | |
| 224 | - // 测试 id 不匹配 | |
| 225 | - roleMapper.insert(cloneIgnoreId(dbRole, o -> {})); | |
| 226 | - roleService.initLocalCache(); | |
| 227 | - // 准备参数 | |
| 228 | - Collection<Long> ids = singleton(dbRole.getId()); | |
| 229 | - | |
| 230 | - // 调用 | |
| 231 | - List<RoleDO> list = roleService.getRoleListFromCache(ids); | |
| 232 | - // 断言 | |
| 233 | - assertEquals(1, list.size()); | |
| 234 | - assertPojoEquals(dbRole, list.get(0)); | |
| 239 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | |
| 240 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(RoleServiceImpl.class))) | |
| 241 | + .thenReturn(roleService); | |
| 242 | + | |
| 243 | + // mock 数据 | |
| 244 | + RoleDO dbRole = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 245 | + roleMapper.insert(dbRole); | |
| 246 | + // 测试 id 不匹配 | |
| 247 | + roleMapper.insert(cloneIgnoreId(dbRole, o -> {})); | |
| 248 | + // 准备参数 | |
| 249 | + Collection<Long> ids = singleton(dbRole.getId()); | |
| 250 | + | |
| 251 | + // 调用 | |
| 252 | + List<RoleDO> list = roleService.getRoleListFromCache(ids); | |
| 253 | + // 断言 | |
| 254 | + assertEquals(1, list.size()); | |
| 255 | + assertPojoEquals(dbRole, list.get(0)); | |
| 256 | + } | |
| 235 | 257 | } |
| 236 | 258 | |
| 237 | 259 | @Test |
| ... | ... | @@ -296,72 +318,37 @@ public class RoleServiceImplTest extends BaseDbUnitTest { |
| 296 | 318 | } |
| 297 | 319 | |
| 298 | 320 | @Test |
| 299 | - public void testHasAnySuperAdmin() { | |
| 300 | - // 是超级 | |
| 301 | - assertTrue(roleService.hasAnySuperAdmin(singletonList(randomPojo(RoleDO.class, | |
| 302 | - o -> o.setCode("super_admin"))))); | |
| 303 | - // 非超级 | |
| 304 | - assertFalse(roleService.hasAnySuperAdmin(singletonList(randomPojo(RoleDO.class, | |
| 305 | - o -> o.setCode("tenant_admin"))))); | |
| 306 | - } | |
| 307 | - | |
| 308 | - @Test | |
| 309 | - public void testValidateRoleDuplicate_success() { | |
| 310 | - // 调用,不会抛异常 | |
| 311 | - roleService.validateRoleDuplicate(randomString(), randomString(), null); | |
| 312 | - } | |
| 313 | - | |
| 314 | - @Test | |
| 315 | - public void testValidateRoleDuplicate_nameDuplicate() { | |
| 316 | - // mock 数据 | |
| 317 | - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setName("role_name")); | |
| 318 | - roleMapper.insert(roleDO); | |
| 319 | - // 准备参数 | |
| 320 | - String name = "role_name"; | |
| 321 | - | |
| 322 | - // 调用,并断言异常 | |
| 323 | - assertServiceException(() -> roleService.validateRoleDuplicate(name, randomString(), null), | |
| 324 | - ROLE_NAME_DUPLICATE, name); | |
| 321 | + public void testHasAnySuperAdmin_true() { | |
| 322 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | |
| 323 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(RoleServiceImpl.class))) | |
| 324 | + .thenReturn(roleService); | |
| 325 | + | |
| 326 | + // mock 数据 | |
| 327 | + RoleDO dbRole = randomPojo(RoleDO.class).setCode("super_admin"); | |
| 328 | + roleMapper.insert(dbRole); | |
| 329 | + // 准备参数 | |
| 330 | + Long id = dbRole.getId(); | |
| 331 | + | |
| 332 | + // 调用,并调用 | |
| 333 | + assertTrue(roleService.hasAnySuperAdmin(singletonList(id))); | |
| 334 | + } | |
| 325 | 335 | } |
| 326 | 336 | |
| 327 | 337 | @Test |
| 328 | - public void testValidateRoleDuplicate_codeDuplicate() { | |
| 329 | - // mock 数据 | |
| 330 | - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setCode("code")); | |
| 331 | - roleMapper.insert(roleDO); | |
| 332 | - // 准备参数 | |
| 333 | - String code = "code"; | |
| 334 | - | |
| 335 | - // 调用,并断言异常 | |
| 336 | - assertServiceException(() -> roleService.validateRoleDuplicate(randomString(), code, null), | |
| 337 | - ROLE_CODE_DUPLICATE, code); | |
| 338 | - } | |
| 339 | - | |
| 340 | - @Test | |
| 341 | - public void testValidateUpdateRole_success() { | |
| 342 | - RoleDO roleDO = randomPojo(RoleDO.class); | |
| 343 | - roleMapper.insert(roleDO); | |
| 344 | - // 准备参数 | |
| 345 | - Long id = roleDO.getId(); | |
| 346 | - | |
| 347 | - // 调用,无异常 | |
| 348 | - roleService.validateRoleForUpdate(id); | |
| 349 | - } | |
| 350 | - | |
| 351 | - @Test | |
| 352 | - public void testValidateUpdateRole_roleIdNotExist() { | |
| 353 | - assertServiceException(() -> roleService.validateRoleForUpdate(randomLongId()), ROLE_NOT_EXISTS); | |
| 354 | - } | |
| 355 | - | |
| 356 | - @Test | |
| 357 | - public void testValidateUpdateRole_systemRoleCanNotBeUpdate() { | |
| 358 | - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setType(RoleTypeEnum.SYSTEM.getType())); | |
| 359 | - roleMapper.insert(roleDO); | |
| 360 | - // 准备参数 | |
| 361 | - Long id = roleDO.getId(); | |
| 362 | - | |
| 363 | - assertServiceException(() -> roleService.validateRoleForUpdate(id), | |
| 364 | - ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE); | |
| 338 | + public void testHasAnySuperAdmin_false() { | |
| 339 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | |
| 340 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(RoleServiceImpl.class))) | |
| 341 | + .thenReturn(roleService); | |
| 342 | + | |
| 343 | + // mock 数据 | |
| 344 | + RoleDO dbRole = randomPojo(RoleDO.class).setCode("tenant_admin"); | |
| 345 | + roleMapper.insert(dbRole); | |
| 346 | + // 准备参数 | |
| 347 | + Long id = dbRole.getId(); | |
| 348 | + | |
| 349 | + // 调用,并调用 | |
| 350 | + assertFalse(roleService.hasAnySuperAdmin(singletonList(id))); | |
| 351 | + } | |
| 365 | 352 | } |
| 366 | 353 | |
| 367 | 354 | @Test | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImplTest.java
| ... | ... | @@ -10,9 +10,7 @@ import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.Sensitiv |
| 10 | 10 | import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordUpdateReqVO; |
| 11 | 11 | import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO; |
| 12 | 12 | import cn.iocoder.yudao.module.system.dal.mysql.sensitiveword.SensitiveWordMapper; |
| 13 | -import cn.iocoder.yudao.module.system.mq.producer.sensitiveword.SensitiveWordProducer; | |
| 14 | 13 | import org.junit.jupiter.api.Test; |
| 15 | -import org.springframework.boot.test.mock.mockito.MockBean; | |
| 16 | 14 | import org.springframework.context.annotation.Import; |
| 17 | 15 | |
| 18 | 16 | import javax.annotation.Resource; |
| ... | ... | @@ -29,7 +27,6 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
| 29 | 27 | import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SENSITIVE_WORD_NOT_EXISTS; |
| 30 | 28 | import static java.util.Collections.singletonList; |
| 31 | 29 | import static org.junit.jupiter.api.Assertions.*; |
| 32 | -import static org.mockito.Mockito.verify; | |
| 33 | 30 | |
| 34 | 31 | /** |
| 35 | 32 | * {@link SensitiveWordServiceImpl} 的单元测试类 |
| ... | ... | @@ -45,9 +42,6 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest { |
| 45 | 42 | @Resource |
| 46 | 43 | private SensitiveWordMapper sensitiveWordMapper; |
| 47 | 44 | |
| 48 | - @MockBean | |
| 49 | - private SensitiveWordProducer sensitiveWordProducer; | |
| 50 | - | |
| 51 | 45 | @Test |
| 52 | 46 | public void testInitLocalCache() { |
| 53 | 47 | SensitiveWordDO wordDO1 = randomPojo(SensitiveWordDO.class, o -> o.setName("傻瓜") |
| ... | ... | @@ -61,6 +55,10 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest { |
| 61 | 55 | sensitiveWordService.initLocalCache(); |
| 62 | 56 | // 断言 sensitiveWordTagsCache 缓存 |
| 63 | 57 | assertEquals(SetUtils.asSet("论坛", "蔬菜"), sensitiveWordService.getSensitiveWordTagSet()); |
| 58 | + // 断言 sensitiveWordCache | |
| 59 | + assertEquals(2, sensitiveWordService.getSensitiveWordCache().size()); | |
| 60 | + assertPojoEquals(wordDO1, sensitiveWordService.getSensitiveWordCache().get(0)); | |
| 61 | + assertPojoEquals(wordDO2, sensitiveWordService.getSensitiveWordCache().get(1)); | |
| 64 | 62 | // 断言 tagSensitiveWordTries 缓存 |
| 65 | 63 | assertNotNull(sensitiveWordService.getDefaultSensitiveWordTrie()); |
| 66 | 64 | assertEquals(2, sensitiveWordService.getTagSensitiveWordTries().size()); |
| ... | ... | @@ -80,7 +78,6 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest { |
| 80 | 78 | // 校验记录的属性是否正确 |
| 81 | 79 | SensitiveWordDO sensitiveWord = sensitiveWordMapper.selectById(sensitiveWordId); |
| 82 | 80 | assertPojoEquals(reqVO, sensitiveWord); |
| 83 | - verify(sensitiveWordProducer).sendSensitiveWordRefreshMessage(); | |
| 84 | 81 | } |
| 85 | 82 | |
| 86 | 83 | @Test |
| ... | ... | @@ -98,7 +95,6 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest { |
| 98 | 95 | // 校验是否更新正确 |
| 99 | 96 | SensitiveWordDO sensitiveWord = sensitiveWordMapper.selectById(reqVO.getId()); // 获取最新的 |
| 100 | 97 | assertPojoEquals(reqVO, sensitiveWord); |
| 101 | - verify(sensitiveWordProducer).sendSensitiveWordRefreshMessage(); | |
| 102 | 98 | } |
| 103 | 99 | |
| 104 | 100 | @Test |
| ... | ... | @@ -122,7 +118,6 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest { |
| 122 | 118 | sensitiveWordService.deleteSensitiveWord(id); |
| 123 | 119 | // 校验数据不存在了 |
| 124 | 120 | assertNull(sensitiveWordMapper.selectById(id)); |
| 125 | - verify(sensitiveWordProducer).sendSensitiveWordRefreshMessage(); | |
| 126 | 121 | } |
| 127 | 122 | |
| 128 | 123 | @Test | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceTest.java
| ... | ... | @@ -9,13 +9,11 @@ import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannel |
| 9 | 9 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelUpdateReqVO; |
| 10 | 10 | import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; |
| 11 | 11 | import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper; |
| 12 | -import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer; | |
| 13 | 12 | import org.junit.jupiter.api.Test; |
| 14 | 13 | import org.springframework.boot.test.mock.mockito.MockBean; |
| 15 | 14 | import org.springframework.context.annotation.Import; |
| 16 | 15 | |
| 17 | 16 | import javax.annotation.Resource; |
| 18 | - | |
| 19 | 17 | import java.util.List; |
| 20 | 18 | |
| 21 | 19 | import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; |
| ... | ... | @@ -42,8 +40,6 @@ public class SmsChannelServiceTest extends BaseDbUnitTest { |
| 42 | 40 | private SmsClientFactory smsClientFactory; |
| 43 | 41 | @MockBean |
| 44 | 42 | private SmsTemplateService smsTemplateService; |
| 45 | - @MockBean | |
| 46 | - private SmsProducer smsProducer; | |
| 47 | 43 | |
| 48 | 44 | @Test |
| 49 | 45 | public void testInitLocalCache_success() { |
| ... | ... | @@ -60,6 +56,10 @@ public class SmsChannelServiceTest extends BaseDbUnitTest { |
| 60 | 56 | argThat(properties -> isPojoEquals(smsChannelDO01, properties))); |
| 61 | 57 | verify(smsClientFactory, times(1)).createOrUpdateSmsClient( |
| 62 | 58 | argThat(properties -> isPojoEquals(smsChannelDO02, properties))); |
| 59 | + // 断言 channelCache 缓存 | |
| 60 | + assertEquals(2, smsChannelService.getChannelCache().size()); | |
| 61 | + assertPojoEquals(smsChannelDO01, smsChannelService.getChannelCache().get(0)); | |
| 62 | + assertPojoEquals(smsChannelDO02, smsChannelService.getChannelCache().get(1)); | |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | 65 | @Test |
| ... | ... | @@ -74,8 +74,6 @@ public class SmsChannelServiceTest extends BaseDbUnitTest { |
| 74 | 74 | // 校验记录的属性是否正确 |
| 75 | 75 | SmsChannelDO smsChannel = smsChannelMapper.selectById(smsChannelId); |
| 76 | 76 | assertPojoEquals(reqVO, smsChannel); |
| 77 | - // 校验调用 | |
| 78 | - verify(smsProducer, times(1)).sendSmsChannelRefreshMessage(); | |
| 79 | 77 | } |
| 80 | 78 | |
| 81 | 79 | @Test |
| ... | ... | @@ -95,8 +93,6 @@ public class SmsChannelServiceTest extends BaseDbUnitTest { |
| 95 | 93 | // 校验是否更新正确 |
| 96 | 94 | SmsChannelDO smsChannel = smsChannelMapper.selectById(reqVO.getId()); // 获取最新的 |
| 97 | 95 | assertPojoEquals(reqVO, smsChannel); |
| 98 | - // 校验调用 | |
| 99 | - verify(smsProducer, times(1)).sendSmsChannelRefreshMessage(); | |
| 100 | 96 | } |
| 101 | 97 | |
| 102 | 98 | @Test |
| ... | ... | @@ -118,10 +114,8 @@ public class SmsChannelServiceTest extends BaseDbUnitTest { |
| 118 | 114 | |
| 119 | 115 | // 调用 |
| 120 | 116 | smsChannelService.deleteSmsChannel(id); |
| 121 | - // 校验数据不存在了 | |
| 122 | - assertNull(smsChannelMapper.selectById(id)); | |
| 123 | - // 校验调用 | |
| 124 | - verify(smsProducer, times(1)).sendSmsChannelRefreshMessage(); | |
| 117 | + // 校验数据不存在了 | |
| 118 | + assertNull(smsChannelMapper.selectById(id)); | |
| 125 | 119 | } |
| 126 | 120 | |
| 127 | 121 | @Test | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java
| ... | ... | @@ -18,7 +18,6 @@ import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; |
| 18 | 18 | import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; |
| 19 | 19 | import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsTemplateMapper; |
| 20 | 20 | import cn.iocoder.yudao.module.system.enums.sms.SmsTemplateTypeEnum; |
| 21 | -import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer; | |
| 22 | 21 | import com.google.common.collect.Lists; |
| 23 | 22 | import org.junit.jupiter.api.Test; |
| 24 | 23 | import org.springframework.boot.test.mock.mockito.MockBean; |
| ... | ... | @@ -26,7 +25,6 @@ import org.springframework.context.annotation.Import; |
| 26 | 25 | |
| 27 | 26 | import javax.annotation.Resource; |
| 28 | 27 | import java.util.List; |
| 29 | -import java.util.Map; | |
| 30 | 28 | import java.util.function.Consumer; |
| 31 | 29 | |
| 32 | 30 | import static cn.hutool.core.util.RandomUtil.randomEle; |
| ... | ... | @@ -55,25 +53,6 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { |
| 55 | 53 | private SmsClientFactory smsClientFactory; |
| 56 | 54 | @MockBean |
| 57 | 55 | private SmsClient smsClient; |
| 58 | - @MockBean | |
| 59 | - private SmsProducer smsProducer; | |
| 60 | - | |
| 61 | - @Test | |
| 62 | - void testInitLocalCache() { | |
| 63 | - // mock 数据 | |
| 64 | - SmsTemplateDO smsTemplate01 = randomSmsTemplateDO(); | |
| 65 | - smsTemplateMapper.insert(smsTemplate01); | |
| 66 | - SmsTemplateDO smsTemplate02 = randomSmsTemplateDO(); | |
| 67 | - smsTemplateMapper.insert(smsTemplate02); | |
| 68 | - | |
| 69 | - // 调用 | |
| 70 | - smsTemplateService.initLocalCache(); | |
| 71 | - // 断言 deptCache 缓存 | |
| 72 | - Map<String, SmsTemplateDO> smsTemplateCache = smsTemplateService.getSmsTemplateCache(); | |
| 73 | - assertEquals(2, smsTemplateCache.size()); | |
| 74 | - assertPojoEquals(smsTemplate01, smsTemplateCache.get(smsTemplate01.getCode())); | |
| 75 | - assertPojoEquals(smsTemplate02, smsTemplateCache.get(smsTemplate02.getCode())); | |
| 76 | - } | |
| 77 | 56 | |
| 78 | 57 | @Test |
| 79 | 58 | public void testParseTemplateContentParams() { |
| ... | ... | @@ -116,8 +95,6 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { |
| 116 | 95 | assertPojoEquals(reqVO, smsTemplate); |
| 117 | 96 | assertEquals(Lists.newArrayList("operation", "code"), smsTemplate.getParams()); |
| 118 | 97 | assertEquals(channelDO.getCode(), smsTemplate.getChannelCode()); |
| 119 | - // 校验调用 | |
| 120 | - verify(smsProducer, times(1)).sendSmsTemplateRefreshMessage(); | |
| 121 | 98 | } |
| 122 | 99 | |
| 123 | 100 | @Test |
| ... | ... | @@ -151,8 +128,6 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { |
| 151 | 128 | assertPojoEquals(reqVO, smsTemplate); |
| 152 | 129 | assertEquals(Lists.newArrayList("operation", "code"), smsTemplate.getParams()); |
| 153 | 130 | assertEquals(channelDO.getCode(), smsTemplate.getChannelCode()); |
| 154 | - // 校验调用 | |
| 155 | - verify(smsProducer, times(1)).sendSmsTemplateRefreshMessage(); | |
| 156 | 131 | } |
| 157 | 132 | |
| 158 | 133 | @Test |
| ... | ... | @@ -174,10 +149,8 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { |
| 174 | 149 | |
| 175 | 150 | // 调用 |
| 176 | 151 | smsTemplateService.deleteSmsTemplate(id); |
| 177 | - // 校验数据不存在了 | |
| 178 | - assertNull(smsTemplateMapper.selectById(id)); | |
| 179 | - // 校验调用 | |
| 180 | - verify(smsProducer, times(1)).sendSmsTemplateRefreshMessage(); | |
| 152 | + // 校验数据不存在了 | |
| 153 | + assertNull(smsTemplateMapper.selectById(id)); | |
| 181 | 154 | } |
| 182 | 155 | |
| 183 | 156 | @Test |
| ... | ... | @@ -191,47 +164,47 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { |
| 191 | 164 | |
| 192 | 165 | @Test |
| 193 | 166 | public void testGetSmsTemplatePage() { |
| 194 | - // mock 数据 | |
| 195 | - SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> { // 等会查询到 | |
| 196 | - o.setType(SmsTemplateTypeEnum.PROMOTION.getType()); | |
| 197 | - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 198 | - o.setCode("tudou"); | |
| 199 | - o.setContent("芋道源码"); | |
| 200 | - o.setApiTemplateId("yunai"); | |
| 201 | - o.setChannelId(1L); | |
| 202 | - o.setCreateTime(buildTime(2021, 11, 11)); | |
| 203 | - }); | |
| 204 | - smsTemplateMapper.insert(dbSmsTemplate); | |
| 205 | - // 测试 type 不匹配 | |
| 206 | - smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setType(SmsTemplateTypeEnum.VERIFICATION_CODE.getType()))); | |
| 207 | - // 测试 status 不匹配 | |
| 208 | - smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); | |
| 209 | - // 测试 code 不匹配 | |
| 210 | - smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCode("yuanma"))); | |
| 211 | - // 测试 content 不匹配 | |
| 212 | - smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setContent("源码"))); | |
| 213 | - // 测试 apiTemplateId 不匹配 | |
| 214 | - smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setApiTemplateId("nai"))); | |
| 215 | - // 测试 channelId 不匹配 | |
| 216 | - smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L))); | |
| 217 | - // 测试 createTime 不匹配 | |
| 218 | - smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12)))); | |
| 219 | - // 准备参数 | |
| 220 | - SmsTemplatePageReqVO reqVO = new SmsTemplatePageReqVO(); | |
| 221 | - reqVO.setType(SmsTemplateTypeEnum.PROMOTION.getType()); | |
| 222 | - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 223 | - reqVO.setCode("tu"); | |
| 224 | - reqVO.setContent("芋道"); | |
| 225 | - reqVO.setApiTemplateId("yu"); | |
| 226 | - reqVO.setChannelId(1L); | |
| 227 | - reqVO.setCreateTime(buildBetweenTime(2021, 11, 1, 2021, 12, 1)); | |
| 228 | - | |
| 229 | - // 调用 | |
| 230 | - PageResult<SmsTemplateDO> pageResult = smsTemplateService.getSmsTemplatePage(reqVO); | |
| 231 | - // 断言 | |
| 232 | - assertEquals(1, pageResult.getTotal()); | |
| 233 | - assertEquals(1, pageResult.getList().size()); | |
| 234 | - assertPojoEquals(dbSmsTemplate, pageResult.getList().get(0)); | |
| 167 | + // mock 数据 | |
| 168 | + SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> { // 等会查询到 | |
| 169 | + o.setType(SmsTemplateTypeEnum.PROMOTION.getType()); | |
| 170 | + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 171 | + o.setCode("tudou"); | |
| 172 | + o.setContent("芋道源码"); | |
| 173 | + o.setApiTemplateId("yunai"); | |
| 174 | + o.setChannelId(1L); | |
| 175 | + o.setCreateTime(buildTime(2021, 11, 11)); | |
| 176 | + }); | |
| 177 | + smsTemplateMapper.insert(dbSmsTemplate); | |
| 178 | + // 测试 type 不匹配 | |
| 179 | + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setType(SmsTemplateTypeEnum.VERIFICATION_CODE.getType()))); | |
| 180 | + // 测试 status 不匹配 | |
| 181 | + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); | |
| 182 | + // 测试 code 不匹配 | |
| 183 | + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCode("yuanma"))); | |
| 184 | + // 测试 content 不匹配 | |
| 185 | + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setContent("源码"))); | |
| 186 | + // 测试 apiTemplateId 不匹配 | |
| 187 | + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setApiTemplateId("nai"))); | |
| 188 | + // 测试 channelId 不匹配 | |
| 189 | + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L))); | |
| 190 | + // 测试 createTime 不匹配 | |
| 191 | + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12)))); | |
| 192 | + // 准备参数 | |
| 193 | + SmsTemplatePageReqVO reqVO = new SmsTemplatePageReqVO(); | |
| 194 | + reqVO.setType(SmsTemplateTypeEnum.PROMOTION.getType()); | |
| 195 | + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 196 | + reqVO.setCode("tu"); | |
| 197 | + reqVO.setContent("芋道"); | |
| 198 | + reqVO.setApiTemplateId("yu"); | |
| 199 | + reqVO.setChannelId(1L); | |
| 200 | + reqVO.setCreateTime(buildBetweenTime(2021, 11, 1, 2021, 12, 1)); | |
| 201 | + | |
| 202 | + // 调用 | |
| 203 | + PageResult<SmsTemplateDO> pageResult = smsTemplateService.getSmsTemplatePage(reqVO); | |
| 204 | + // 断言 | |
| 205 | + assertEquals(1, pageResult.getTotal()); | |
| 206 | + assertEquals(1, pageResult.getList().size()); | |
| 207 | + assertPojoEquals(dbSmsTemplate, pageResult.getList().get(0)); | |
| 235 | 208 | } |
| 236 | 209 | |
| 237 | 210 | @Test |
| ... | ... | @@ -271,11 +244,11 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { |
| 271 | 244 | reqVO.setChannelId(1L); |
| 272 | 245 | reqVO.setCreateTime(buildBetweenTime(2021, 11, 1, 2021, 12, 1)); |
| 273 | 246 | |
| 274 | - // 调用 | |
| 275 | - List<SmsTemplateDO> list = smsTemplateService.getSmsTemplateList(reqVO); | |
| 276 | - // 断言 | |
| 277 | - assertEquals(1, list.size()); | |
| 278 | - assertPojoEquals(dbSmsTemplate, list.get(0)); | |
| 247 | + // 调用 | |
| 248 | + List<SmsTemplateDO> list = smsTemplateService.getSmsTemplateList(reqVO); | |
| 249 | + // 断言 | |
| 250 | + assertEquals(1, list.size()); | |
| 251 | + assertPojoEquals(dbSmsTemplate, list.get(0)); | |
| 279 | 252 | } |
| 280 | 253 | |
| 281 | 254 | @Test | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java
| ... | ... | @@ -199,7 +199,7 @@ public class TenantServiceImplTest extends BaseDbUnitTest { |
| 199 | 199 | role101.setTenantId(dbTenant.getId()); |
| 200 | 200 | when(roleService.getRoleListByStatus(isNull())).thenReturn(asList(role100, role101)); |
| 201 | 201 | // mock 每个角色的权限 |
| 202 | - when(permissionService.getRoleMenuIds(eq(101L))).thenReturn(asSet(201L, 202L)); | |
| 202 | + when(permissionService.getRoleMenuListByRoleId(eq(101L))).thenReturn(asSet(201L, 202L)); | |
| 203 | 203 | |
| 204 | 204 | // 调用 |
| 205 | 205 | tenantService.updateTenant(reqVO); |
| ... | ... | @@ -454,7 +454,7 @@ public class TenantServiceImplTest extends BaseDbUnitTest { |
| 454 | 454 | TenantContextHolder.setTenantId(dbTenant.getId()); |
| 455 | 455 | // mock 菜单 |
| 456 | 456 | when(menuService.getMenuList()).thenReturn(Arrays.asList(randomPojo(MenuDO.class, o -> o.setId(100L)), |
| 457 | - randomPojo(MenuDO.class, o -> o.setId(101L)))); | |
| 457 | + randomPojo(MenuDO.class, o -> o.setId(101L)))); | |
| 458 | 458 | |
| 459 | 459 | // 调用 |
| 460 | 460 | tenantService.handleTenantMenu(handler); | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java
| ... | ... | @@ -345,7 +345,7 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { |
| 345 | 345 | reqVO.setDeptId(1L); // 其中,1L 是 2L 的父部门 |
| 346 | 346 | // mock 方法 |
| 347 | 347 | List<DeptDO> deptList = newArrayList(randomPojo(DeptDO.class, o -> o.setId(2L))); |
| 348 | - when(deptService.getDeptListByParentIdFromCache(eq(reqVO.getDeptId()), eq(true))).thenReturn(deptList); | |
| 348 | + when(deptService.getChildDeptList(eq(reqVO.getDeptId()))).thenReturn(deptList); | |
| 349 | 349 | |
| 350 | 350 | // 调用 |
| 351 | 351 | PageResult<AdminUserDO> pageResult = userService.getUserPage(reqVO); |
| ... | ... | @@ -368,7 +368,7 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { |
| 368 | 368 | reqVO.setDeptId(1L); // 其中,1L 是 2L 的父部门 |
| 369 | 369 | // mock 方法 |
| 370 | 370 | List<DeptDO> deptList = newArrayList(randomPojo(DeptDO.class, o -> o.setId(2L))); |
| 371 | - when(deptService.getDeptListByParentIdFromCache(eq(reqVO.getDeptId()), eq(true))).thenReturn(deptList); | |
| 371 | + when(deptService.getChildDeptList(eq(reqVO.getDeptId()))).thenReturn(deptList); | |
| 372 | 372 | |
| 373 | 373 | // 调用 |
| 374 | 374 | List<AdminUserDO> list = userService.getUserList(reqVO); | ... | ... |
yudao-server/src/main/resources/application-dev.yaml
| ... | ... | @@ -147,14 +147,14 @@ wx: # 参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-sta |
| 147 | 147 | # 存储配置,解决 AccessToken 的跨节点的共享 |
| 148 | 148 | config-storage: |
| 149 | 149 | type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 |
| 150 | - key-prefix: wx # Redis Key 的前缀 TODO 芋艿:解决下 Redis key 管理的配置 | |
| 150 | + key-prefix: wx # Redis Key 的前缀 | |
| 151 | 151 | http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 |
| 152 | 152 | miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档 |
| 153 | 153 | appid: wx63c280fe3248a3e7 |
| 154 | 154 | secret: 6f270509224a7ae1296bbf1c8cb97aed |
| 155 | 155 | config-storage: |
| 156 | 156 | type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 |
| 157 | - key-prefix: wa # Redis Key 的前缀 TODO 芋艿:解决下 Redis key 管理的配置 | |
| 157 | + key-prefix: wa # Redis Key 的前缀 | |
| 158 | 158 | http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 |
| 159 | 159 | |
| 160 | 160 | --- #################### 芋道相关配置 #################### |
| ... | ... | @@ -167,7 +167,8 @@ yudao: |
| 167 | 167 | - ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求 |
| 168 | 168 | - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求 |
| 169 | 169 | pay: |
| 170 | - callback-url: http://yunai.natapp1.cc/admin-api/pay/notify/callback | |
| 170 | + order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址 | |
| 171 | + refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址 | |
| 171 | 172 | demo: true # 开启演示模式 |
| 172 | 173 | |
| 173 | 174 | justauth: | ... | ... |
yudao-server/src/main/resources/application-local.yaml
| ... | ... | @@ -170,14 +170,14 @@ wx: |
| 170 | 170 | # 存储配置,解决 AccessToken 的跨节点的共享 |
| 171 | 171 | config-storage: |
| 172 | 172 | type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 |
| 173 | - key-prefix: wx # Redis Key 的前缀 TODO 芋艿:解决下 Redis key 管理的配置 | |
| 173 | + key-prefix: wx # Redis Key 的前缀 | |
| 174 | 174 | http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 |
| 175 | 175 | miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档 |
| 176 | 176 | appid: wx62056c0d5e8db250 |
| 177 | 177 | secret: 333ae72f41552af1e998fe1f54e1584a |
| 178 | 178 | config-storage: |
| 179 | 179 | type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 |
| 180 | - key-prefix: wa # Redis Key 的前缀 TODO 芋艿:解决下 Redis key 管理的配置 | |
| 180 | + key-prefix: wa # Redis Key 的前缀 | |
| 181 | 181 | http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台 |
| 182 | 182 | |
| 183 | 183 | --- #################### 芋道相关配置 #################### | ... | ... |
yudao-ui-admin/package.json
yudao-ui-admin/src/api/menu.js deleted
yudao-ui-admin/src/api/system/permission.js
| ... | ... | @@ -3,7 +3,7 @@ import request from '@/utils/request' |
| 3 | 3 | // 查询角色拥有的菜单数组 |
| 4 | 4 | export function listRoleMenus(roleId) { |
| 5 | 5 | return request({ |
| 6 | - url: '/system/permission/list-role-resources?roleId=' + roleId, | |
| 6 | + url: '/system/permission/list-role-menus?roleId=' + roleId, | |
| 7 | 7 | method: 'get' |
| 8 | 8 | }) |
| 9 | 9 | } | ... | ... |
yudao-ui-admin/src/components/Crontab/week.vue
| ... | ... | @@ -185,7 +185,7 @@ export default { |
| 185 | 185 | averageTotal: function () { |
| 186 | 186 | this.average01 = this.checkNum(this.average01, 1, 4) |
| 187 | 187 | this.average02 = this.checkNum(this.average02, 1, 7) |
| 188 | - return this.average02 + '#' + this.average01; | |
| 188 | + return this.average01 + '#' + this.average02; | |
| 189 | 189 | }, |
| 190 | 190 | // 最近的工作日(格式) |
| 191 | 191 | weekdayCheck: function () { | ... | ... |
yudao-ui-admin/src/permission.js
| ... | ... | @@ -25,9 +25,10 @@ router.beforeEach((to, from, next) => { |
| 25 | 25 | // 获取字典数据 add by 芋艿 |
| 26 | 26 | store.dispatch('dict/loadDictDatas') |
| 27 | 27 | // 判断当前用户是否已拉取完 user_info 信息 |
| 28 | - store.dispatch('GetInfo').then(() => { | |
| 28 | + store.dispatch('GetInfo').then(userInfo => { | |
| 29 | 29 | isRelogin.show = false |
| 30 | - store.dispatch('GenerateRoutes').then(accessRoutes => { | |
| 30 | + // 触发 GenerateRoutes 事件时,将 menus 菜单树传递进去 | |
| 31 | + store.dispatch('GenerateRoutes', userInfo.menus).then(accessRoutes => { | |
| 31 | 32 | // 根据 roles 权限生成可访问的路由表 |
| 32 | 33 | router.addRoutes(accessRoutes) // 动态添加可访问路由表 |
| 33 | 34 | next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 | ... | ... |
yudao-ui-admin/src/store/modules/permission.js
| 1 | 1 | import {constantRoutes} from '@/router' |
| 2 | -import {getRouters} from '@/api/menu' | |
| 3 | 2 | import Layout from '@/layout/index' |
| 4 | 3 | import ParentView from '@/components/ParentView'; |
| 5 | 4 | import {toCamelCase} from "@/utils"; |
| ... | ... | @@ -27,22 +26,25 @@ const permission = { |
| 27 | 26 | }, |
| 28 | 27 | }, |
| 29 | 28 | actions: { |
| 30 | - // 生成路由 | |
| 31 | - GenerateRoutes({commit}) { | |
| 29 | + /** | |
| 30 | + * 生成路由 | |
| 31 | + * | |
| 32 | + * @param commit commit 函数 | |
| 33 | + * @param menus 路由参数 | |
| 34 | + */ | |
| 35 | + GenerateRoutes({commit}, menus) { | |
| 32 | 36 | return new Promise(resolve => { |
| 33 | - // 向后端请求路由数据(菜单) | |
| 34 | - getRouters().then(res => { | |
| 35 | - const sdata = JSON.parse(JSON.stringify(res.data)) // 【重要】用于菜单中的数据 | |
| 36 | - const rdata = JSON.parse(JSON.stringify(res.data)) // 用于最后添加到 Router 中的数据 | |
| 37 | - const sidebarRoutes = filterAsyncRouter(sdata) | |
| 38 | - const rewriteRoutes = filterAsyncRouter(rdata, false, true) | |
| 39 | - rewriteRoutes.push({path: '*', redirect: '/404', hidden: true}) | |
| 40 | - commit('SET_ROUTES', rewriteRoutes) | |
| 41 | - commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes)) | |
| 42 | - commit('SET_DEFAULT_ROUTES', sidebarRoutes) | |
| 43 | - commit('SET_TOPBAR_ROUTES', sidebarRoutes) | |
| 44 | - resolve(rewriteRoutes) | |
| 45 | - }) | |
| 37 | + // 将 menus 菜单,转换为 route 路由数组 | |
| 38 | + const sdata = JSON.parse(JSON.stringify(menus)) // 【重要】用于菜单中的数据 | |
| 39 | + const rdata = JSON.parse(JSON.stringify(menus)) // 用于最后添加到 Router 中的数据 | |
| 40 | + const sidebarRoutes = filterAsyncRouter(sdata) | |
| 41 | + const rewriteRoutes = filterAsyncRouter(rdata, false, true) | |
| 42 | + rewriteRoutes.push({path: '*', redirect: '/404', hidden: true}) | |
| 43 | + commit('SET_ROUTES', rewriteRoutes) | |
| 44 | + commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes)) | |
| 45 | + commit('SET_DEFAULT_ROUTES', sidebarRoutes) | |
| 46 | + commit('SET_TOPBAR_ROUTES', sidebarRoutes) | |
| 47 | + resolve(rewriteRoutes) | |
| 46 | 48 | }) |
| 47 | 49 | } |
| 48 | 50 | } | ... | ... |