Commit e4be51b14adfeba6d31424a30976d8729d441b9e

Authored by YunaiV
1 parent 4d539447

1. 新建租户、修改租户、修改租户套餐时,自动修改角色的权限

2. 租户的本地缓存,提升访问性能
3. 精简本地缓存的实现逻辑
Showing 33 changed files with 405 additions and 139 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.common.util.collection; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.common.util.collection;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.collection.CollectionUtil; 4 import cn.hutool.core.collection.CollectionUtil;
  5 +import com.google.common.collect.ImmutableMap;
5 6
6 import java.util.*; 7 import java.util.*;
7 import java.util.function.BinaryOperator; 8 import java.util.function.BinaryOperator;
@@ -125,6 +126,15 @@ public class CollectionUtils { @@ -125,6 +126,15 @@ public class CollectionUtils {
125 return from.stream().collect(Collectors.groupingBy(keyFunc, Collectors.mapping(valueFunc, Collectors.toSet()))); 126 return from.stream().collect(Collectors.groupingBy(keyFunc, Collectors.mapping(valueFunc, Collectors.toSet())));
126 } 127 }
127 128
  129 + public static <T, K> Map<K, T> convertImmutableMap(Collection<T> from, Function<T, K> keyFunc) {
  130 + if (CollUtil.isEmpty(from)) {
  131 + return Collections.emptyMap();
  132 + }
  133 + ImmutableMap.Builder<K, T> builder = ImmutableMap.builder();
  134 + from.forEach(item -> builder.put(keyFunc.apply(item), item));
  135 + return builder.build();
  136 + }
  137 +
128 public static boolean containsAny(Collection<?> source, Collection<?> candidates) { 138 public static boolean containsAny(Collection<?> source, Collection<?> candidates) {
129 return org.springframework.util.CollectionUtils.containsAny(source, candidates); 139 return org.springframework.util.CollectionUtils.containsAny(source, candidates);
130 } 140 }
@@ -140,6 +150,15 @@ public class CollectionUtils { @@ -140,6 +150,15 @@ public class CollectionUtils {
140 return from.stream().filter(predicate).findFirst().orElse(null); 150 return from.stream().filter(predicate).findFirst().orElse(null);
141 } 151 }
142 152
  153 + public static <T, V extends Comparable<? super V>> V getMaxValue(List<T> from, Function<T, V> valueFunc) {
  154 + if (CollUtil.isEmpty(from)) {
  155 + return null;
  156 + }
  157 + assert from.size() > 0; // 断言,避免告警
  158 + T t = from.stream().max(Comparator.comparing(valueFunc)).get();
  159 + return valueFunc.apply(t);
  160 + }
  161 +
143 public static <T> void addIfNotNull(Collection<T> coll, T item) { 162 public static <T> void addIfNotNull(Collection<T> coll, T item) {
144 if (item == null) { 163 if (item == null) {
145 return; 164 return;
yudao-module-pay/yudao-module-pay-impl/pom.xml
@@ -33,6 +33,10 @@ @@ -33,6 +33,10 @@
33 <groupId>cn.iocoder.boot</groupId> 33 <groupId>cn.iocoder.boot</groupId>
34 <artifactId>yudao-spring-boot-starter-biz-pay</artifactId> 34 <artifactId>yudao-spring-boot-starter-biz-pay</artifactId>
35 </dependency> 35 </dependency>
  36 + <dependency>
  37 + <groupId>cn.iocoder.boot</groupId>
  38 + <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
  39 + </dependency>
36 40
37 <!-- Web 相关 --> 41 <!-- Web 相关 -->
38 <dependency> 42 <dependency>
yudao-module-pay/yudao-module-pay-impl/src/main/java/cn/iocoder/yudao/module/pay/service/merchant/PayChannelServiceImpl.java
@@ -6,15 +6,16 @@ import cn.hutool.json.JSONUtil; @@ -6,15 +6,16 @@ import cn.hutool.json.JSONUtil;
6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
7 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; 7 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
8 import cn.iocoder.yudao.framework.common.pojo.PageResult; 8 import cn.iocoder.yudao.framework.common.pojo.PageResult;
9 -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 9 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  10 +import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
10 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; 11 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
  12 +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
  13 +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
11 import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelCreateReqVO; 14 import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelCreateReqVO;
12 import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelExportReqVO; 15 import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelExportReqVO;
13 import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelPageReqVO; 16 import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelPageReqVO;
14 import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelUpdateReqVO; 17 import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelUpdateReqVO;
15 import cn.iocoder.yudao.module.pay.convert.channel.PayChannelConvert; 18 import cn.iocoder.yudao.module.pay.convert.channel.PayChannelConvert;
16 -import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;  
17 -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;  
18 import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayChannelDO; 19 import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayChannelDO;
19 import cn.iocoder.yudao.module.pay.dal.mysql.merchant.PayChannelMapper; 20 import cn.iocoder.yudao.module.pay.dal.mysql.merchant.PayChannelMapper;
20 import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants; 21 import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
@@ -27,12 +28,12 @@ import javax.annotation.PostConstruct; @@ -27,12 +28,12 @@ import javax.annotation.PostConstruct;
27 import javax.annotation.Resource; 28 import javax.annotation.Resource;
28 import javax.validation.Validator; 29 import javax.validation.Validator;
29 import java.util.Collection; 30 import java.util.Collection;
30 -import java.util.Comparator;  
31 import java.util.Date; 31 import java.util.Date;
32 import java.util.List; 32 import java.util.List;
33 33
34 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 34 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
35 -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; 35 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_EXIST_SAME_CHANNEL_ERROR;
  36 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_EXISTS;
36 37
37 /** 38 /**
38 * 支付渠道 Service 实现类 39 * 支付渠道 Service 实现类
@@ -66,9 +67,10 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -66,9 +67,10 @@ public class PayChannelServiceImpl implements PayChannelService {
66 67
67 @Override 68 @Override
68 @PostConstruct 69 @PostConstruct
  70 + @TenantIgnore // 忽略自动化租户,全局初始化本地缓存
69 public void initPayClients() { 71 public void initPayClients() {
70 // 获取支付渠道,如果有更新 72 // 获取支付渠道,如果有更新
71 - List<PayChannelDO> payChannels = this.loadPayChannelIfUpdate(maxUpdateTime); 73 + List<PayChannelDO> payChannels = loadPayChannelIfUpdate(maxUpdateTime);
72 if (CollUtil.isEmpty(payChannels)) { 74 if (CollUtil.isEmpty(payChannels)) {
73 return; 75 return;
74 } 76 }
@@ -78,8 +80,7 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -78,8 +80,7 @@ public class PayChannelServiceImpl implements PayChannelService {
78 payChannel.getCode(), payChannel.getConfig())); 80 payChannel.getCode(), payChannel.getConfig()));
79 81
80 // 写入缓存 82 // 写入缓存
81 - assert payChannels.size() > 0; // 断言,避免告警  
82 - maxUpdateTime = payChannels.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); 83 + maxUpdateTime = CollectionUtils.getMaxValue(payChannels, PayChannelDO::getUpdateTime);
83 log.info("[initPayClients][初始化 PayChannel 数量为 {}]", payChannels.size()); 84 log.info("[initPayClients][初始化 PayChannel 数量为 {}]", payChannels.size());
84 } 85 }
85 86
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java
@@ -72,7 +72,7 @@ public class AuthController { @@ -72,7 +72,7 @@ public class AuthController {
72 // 获得角色列表 72 // 获得角色列表
73 List<RoleDO> roleList = roleService.getRolesFromCache(getLoginUserRoleIds()); 73 List<RoleDO> roleList = roleService.getRolesFromCache(getLoginUserRoleIds());
74 // 获得菜单列表 74 // 获得菜单列表
75 - List<MenuDO> menuList = permissionService.getRoleMenusFromCache( 75 + List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(
76 getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它 76 getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它
77 SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType(), MenuTypeEnum.BUTTON.getType()), 77 SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType(), MenuTypeEnum.BUTTON.getType()),
78 SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); 78 SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus()));
@@ -84,7 +84,7 @@ public class AuthController { @@ -84,7 +84,7 @@ public class AuthController {
84 @ApiOperation("获得登录用户的菜单列表") 84 @ApiOperation("获得登录用户的菜单列表")
85 public CommonResult<List<AuthMenuRespVO>> getMenus() { 85 public CommonResult<List<AuthMenuRespVO>> getMenus() {
86 // 获得用户拥有的菜单列表 86 // 获得用户拥有的菜单列表
87 - List<MenuDO> menuList = permissionService.getRoleMenusFromCache( 87 + List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(
88 getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它 88 getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它
89 SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型 89 SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型
90 SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的 90 SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/MenuController.java
@@ -55,7 +55,7 @@ public class MenuController { @@ -55,7 +55,7 @@ public class MenuController {
55 } 55 }
56 56
57 @GetMapping("/list") 57 @GetMapping("/list")
58 - @ApiOperation("获取菜单列表") 58 + @ApiOperation(value = "获取菜单列表", notes = "用于【菜单管理】界面")
59 @PreAuthorize("@ss.hasPermission('system:menu:query')") 59 @PreAuthorize("@ss.hasPermission('system:menu:query')")
60 public CommonResult<List<MenuRespVO>> getMenus(MenuListReqVO reqVO) { 60 public CommonResult<List<MenuRespVO>> getMenus(MenuListReqVO reqVO) {
61 List<MenuDO> list = menuService.getMenus(reqVO); 61 List<MenuDO> list = menuService.getMenus(reqVO);
@@ -64,13 +64,13 @@ public class MenuController { @@ -64,13 +64,13 @@ public class MenuController {
64 } 64 }
65 65
66 @GetMapping("/list-all-simple") 66 @GetMapping("/list-all-simple")
67 - @ApiOperation(value = "获取菜单精简信息列表", notes = "只包含被开启的菜单,主要用于前端的下拉选项") 67 + @ApiOperation(value = "获取菜单精简信息列表", notes = "只包含被开启的菜单,用于【角色分配菜单】功能的选项")
68 public CommonResult<List<MenuSimpleRespVO>> getSimpleMenus() { 68 public CommonResult<List<MenuSimpleRespVO>> getSimpleMenus() {
69 // 获得菜单列表,只要开启状态的 69 // 获得菜单列表,只要开启状态的
70 MenuListReqVO reqVO = new MenuListReqVO(); 70 MenuListReqVO reqVO = new MenuListReqVO();
71 reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); 71 reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
72 List<MenuDO> list = menuService.getMenus(reqVO); 72 List<MenuDO> list = menuService.getMenus(reqVO);
73 - // 排序后,返回个诶前端 73 + // 排序后,返回给前端
74 list.sort(Comparator.comparing(MenuDO::getSort)); 74 list.sort(Comparator.comparing(MenuDO::getSort));
75 return success(MenuConvert.INSTANCE.convertList02(list)); 75 return success(MenuConvert.INSTANCE.convertList02(list));
76 } 76 }
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java
@@ -37,7 +37,7 @@ public class PermissionController { @@ -37,7 +37,7 @@ public class PermissionController {
37 @GetMapping("/list-role-resources") 37 @GetMapping("/list-role-resources")
38 // @RequiresPermissions("system:permission:assign-role-menu") 38 // @RequiresPermissions("system:permission:assign-role-menu")
39 public CommonResult<Set<Long>> listRoleMenus(Long roleId) { 39 public CommonResult<Set<Long>> listRoleMenus(Long roleId) {
40 - return success(permissionService.listRoleMenuIds(roleId)); 40 + return success(permissionService.getRoleMenuIds(roleId));
41 } 41 }
42 42
43 @PostMapping("/assign-role-menu") 43 @PostMapping("/assign-role-menu")
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageBaseVO.java
@@ -4,7 +4,7 @@ import io.swagger.annotations.ApiModelProperty; @@ -4,7 +4,7 @@ import io.swagger.annotations.ApiModelProperty;
4 import lombok.Data; 4 import lombok.Data;
5 5
6 import javax.validation.constraints.NotNull; 6 import javax.validation.constraints.NotNull;
7 -import java.util.List; 7 +import java.util.Set;
8 8
9 /** 9 /**
10 * 租户套餐 Base VO,提供给添加、修改、详细的子 VO 使用 10 * 租户套餐 Base VO,提供给添加、修改、详细的子 VO 使用
@@ -26,6 +26,6 @@ public class TenantPackageBaseVO { @@ -26,6 +26,6 @@ public class TenantPackageBaseVO {
26 26
27 @ApiModelProperty(value = "关联的菜单编号", required = true) 27 @ApiModelProperty(value = "关联的菜单编号", required = true)
28 @NotNull(message = "关联的菜单编号不能为空") 28 @NotNull(message = "关联的菜单编号不能为空")
29 - private List<Long> menuIds; 29 + private Set<Long> menuIds;
30 30
31 } 31 }
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleDO.java
1 package cn.iocoder.yudao.module.system.dal.dataobject.permission; 1 package cn.iocoder.yudao.module.system.dal.dataobject.permission;
2 2
3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;  
5 import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; 4 import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
6 import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum; 5 import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum;
  6 +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
7 import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; 7 import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
8 import com.baomidou.mybatisplus.annotation.TableField; 8 import com.baomidou.mybatisplus.annotation.TableField;
9 import com.baomidou.mybatisplus.annotation.TableId; 9 import com.baomidou.mybatisplus.annotation.TableId;
@@ -21,7 +21,7 @@ import java.util.Set; @@ -21,7 +21,7 @@ import java.util.Set;
21 @TableName(value = "system_role", autoResultMap = true) 21 @TableName(value = "system_role", autoResultMap = true)
22 @Data 22 @Data
23 @EqualsAndHashCode(callSuper = true) 23 @EqualsAndHashCode(callSuper = true)
24 -public class RoleDO extends BaseDO { 24 +public class RoleDO extends TenantBaseDO {
25 25
26 /** 26 /**
27 * 角色ID 27 * 角色ID
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleMenuDO.java
1 package cn.iocoder.yudao.module.system.dal.dataobject.permission; 1 package cn.iocoder.yudao.module.system.dal.dataobject.permission;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
4 import com.baomidou.mybatisplus.annotation.TableId; 5 import com.baomidou.mybatisplus.annotation.TableId;
5 import com.baomidou.mybatisplus.annotation.TableName; 6 import com.baomidou.mybatisplus.annotation.TableName;
6 import lombok.Data; 7 import lombok.Data;
@@ -14,7 +15,7 @@ import lombok.EqualsAndHashCode; @@ -14,7 +15,7 @@ import lombok.EqualsAndHashCode;
14 @TableName("system_role_menu") 15 @TableName("system_role_menu")
15 @Data 16 @Data
16 @EqualsAndHashCode(callSuper = true) 17 @EqualsAndHashCode(callSuper = true)
17 -public class RoleMenuDO extends BaseDO { 18 +public class RoleMenuDO extends TenantBaseDO {
18 19
19 /** 20 /**
20 * 自增主键 21 * 自增主键
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.mysql.permission; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.mysql.permission;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; 6 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
6 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO; 7 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO;
7 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO; 8 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO;
@@ -41,7 +42,7 @@ public interface RoleMapper extends BaseMapperX&lt;RoleDO&gt; { @@ -41,7 +42,7 @@ public interface RoleMapper extends BaseMapperX&lt;RoleDO&gt; {
41 } 42 }
42 43
43 default List<RoleDO> selectListByStatus(@Nullable Collection<Integer> statuses) { 44 default List<RoleDO> selectListByStatus(@Nullable Collection<Integer> statuses) {
44 - return selectList(new QueryWrapperX<RoleDO>().in("status", statuses)); 45 + return selectList(new LambdaQueryWrapperX<RoleDO>().inIfPresent(RoleDO::getStatus, statuses));
45 } 46 }
46 47
47 @InterceptorIgnore(tenantLine = "true") // 该方法忽略多租户。原因:该方法被异步 task 调用,此时获取不到租户编号 48 @InterceptorIgnore(tenantLine = "true") // 该方法忽略多租户。原因:该方法被异步 task 调用,此时获取不到租户编号
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java
@@ -7,7 +7,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -7,7 +7,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 7 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
8 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 8 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
9 import org.apache.ibatis.annotations.Mapper; 9 import org.apache.ibatis.annotations.Mapper;
  10 +import org.apache.ibatis.annotations.Select;
10 11
  12 +import java.util.Date;
11 import java.util.List; 13 import java.util.List;
12 14
13 /** 15 /**
@@ -43,7 +45,14 @@ public interface TenantMapper extends BaseMapperX&lt;TenantDO&gt; { @@ -43,7 +45,14 @@ public interface TenantMapper extends BaseMapperX&lt;TenantDO&gt; {
43 } 45 }
44 46
45 default Integer selectCountByPackageId(Long packageId) { 47 default Integer selectCountByPackageId(Long packageId) {
46 - return selectCount("package_id", packageId); 48 + return selectCount(TenantDO::getPackageId, packageId);
47 } 49 }
48 50
  51 + default List<TenantDO> selectListByPackageId(Long packageId) {
  52 + return selectList(TenantDO::getPackageId, packageId);
  53 + }
  54 +
  55 + @Select("SELECT id FROM system_tenant WHERE update_time > #{maxUpdateTime} LIMIT 1")
  56 + Long selectExistsByUpdateTimeAfter(Date maxUpdateTime);
  57 +
49 } 58 }
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/enums/permission/RoleCodeEnum.java
@@ -10,12 +10,17 @@ import lombok.Getter; @@ -10,12 +10,17 @@ import lombok.Getter;
10 @AllArgsConstructor 10 @AllArgsConstructor
11 public enum RoleCodeEnum { 11 public enum RoleCodeEnum {
12 12
13 - ADMIN("admin"), // 超级管理员 13 + SUPER_ADMIN("super_admin", "超级管理员"),
  14 + TENANT_ADMIN("tenant_admin", "租户管理员"),
14 ; 15 ;
15 16
16 /** 17 /**
17 * 角色编码 18 * 角色编码
18 */ 19 */
19 - private final String key; 20 + private final String code;
  21 + /**
  22 + * 名字
  23 + */
  24 + private final String name;
20 25
21 } 26 }
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsSendConsumer.java
@@ -12,7 +12,6 @@ import javax.annotation.Resource; @@ -12,7 +12,6 @@ import javax.annotation.Resource;
12 * 针对 {@link SmsSendMessage} 的消费者 12 * 针对 {@link SmsSendMessage} 的消费者
13 * 13 *
14 * @author zzf 14 * @author zzf
15 - * @date 2021/3/9 16:35  
16 */ 15 */
17 @Component 16 @Component
18 @Slf4j 17 @Slf4j
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/tenant/TenantRefreshConsumer.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.mq.consumer.tenant;
  2 +
  3 +import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
  4 +import cn.iocoder.yudao.module.system.mq.message.tenant.TenantRefreshMessage;
  5 +import cn.iocoder.yudao.module.system.service.tenant.TenantService;
  6 +import lombok.extern.slf4j.Slf4j;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +import javax.annotation.Resource;
  10 +
  11 +/**
  12 + * 针对 {@link cn.iocoder.yudao.module.system.mq.message.tenant.TenantRefreshMessage} 的消费者
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Component
  17 +@Slf4j
  18 +public class TenantRefreshConsumer extends AbstractChannelMessageListener<TenantRefreshMessage> {
  19 +
  20 + @Resource
  21 + private TenantService tenantService;
  22 +
  23 + @Override
  24 + public void onMessage(TenantRefreshMessage message) {
  25 + log.info("[onMessage][收到 Tenant 刷新消息]");
  26 + tenantService.initLocalCache();
  27 + }
  28 +
  29 +}
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/message/tenant/TenantRefreshMessage.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.mq.message.tenant;
  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 TenantRefreshMessage extends AbstractChannelMessage {
  15 +
  16 + @Override
  17 + public String getChannel() {
  18 + return "system.tenant.refresh";
  19 + }
  20 +
  21 +}
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/producer/tenant/TenantProducer.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.mq.producer.tenant;
  2 +
  3 +import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
  4 +import cn.iocoder.yudao.module.system.mq.message.permission.RoleRefreshMessage;
  5 +import cn.iocoder.yudao.module.system.mq.message.tenant.TenantRefreshMessage;
  6 +import org.springframework.stereotype.Component;
  7 +
  8 +import javax.annotation.Resource;
  9 +
  10 +/**
  11 + * Tenant 租户相关消息的 Producer
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Component
  16 +public class TenantProducer {
  17 +
  18 + @Resource
  19 + private RedisMQTemplate redisMQTemplate;
  20 +
  21 + /**
  22 + * 发送 {@link RoleRefreshMessage} 消息
  23 + */
  24 + public void sendTenantRefreshMessage() {
  25 + TenantRefreshMessage message = new TenantRefreshMessage();
  26 + redisMQTemplate.send(message);
  27 + }
  28 +
  29 +}
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java
@@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil; @@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil;
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; 5 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
7 -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 7 +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
8 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptCreateReqVO; 8 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptCreateReqVO;
9 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO; 9 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
10 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO; 10 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO;
@@ -73,9 +73,10 @@ public class DeptServiceImpl implements DeptService { @@ -73,9 +73,10 @@ public class DeptServiceImpl implements DeptService {
73 73
74 @Override 74 @Override
75 @PostConstruct 75 @PostConstruct
  76 + @TenantIgnore // 初始化缓存,无需租户过滤
76 public synchronized void initLocalCache() { 77 public synchronized void initLocalCache() {
77 // 获取部门列表,如果有更新 78 // 获取部门列表,如果有更新
78 - List<DeptDO> deptList = this.loadDeptIfUpdate(maxUpdateTime); 79 + List<DeptDO> deptList = loadDeptIfUpdate(maxUpdateTime);
79 if (CollUtil.isEmpty(deptList)) { 80 if (CollUtil.isEmpty(deptList)) {
80 return; 81 return;
81 } 82 }
@@ -90,8 +91,7 @@ public class DeptServiceImpl implements DeptService { @@ -90,8 +91,7 @@ public class DeptServiceImpl implements DeptService {
90 // 设置缓存 91 // 设置缓存
91 deptCache = builder.build(); 92 deptCache = builder.build();
92 parentDeptCache = parentBuilder.build(); 93 parentDeptCache = parentBuilder.build();
93 - assert deptList.size() > 0; // 断言,避免告警  
94 - maxUpdateTime = deptList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); 94 + maxUpdateTime = CollectionUtils.getMaxValue(deptList, DeptDO::getUpdateTime);
95 log.info("[initLocalCache][初始化 Dept 数量为 {}]", deptList.size()); 95 log.info("[initLocalCache][初始化 Dept 数量为 {}]", deptList.size());
96 } 96 }
97 97
@@ -107,7 +107,7 @@ public class DeptServiceImpl implements DeptService { @@ -107,7 +107,7 @@ public class DeptServiceImpl implements DeptService {
107 * @param maxUpdateTime 当前部门的最大更新时间 107 * @param maxUpdateTime 当前部门的最大更新时间
108 * @return 部门列表 108 * @return 部门列表
109 */ 109 */
110 - private List<DeptDO> loadDeptIfUpdate(Date maxUpdateTime) { 110 + protected List<DeptDO> loadDeptIfUpdate(Date maxUpdateTime) {
111 // 第一步,判断是否要更新。 111 // 第一步,判断是否要更新。
112 if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 112 if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据
113 log.info("[loadMenuIfUpdate][首次加载全量部门]"); 113 log.info("[loadMenuIfUpdate][首次加载全量部门]");
@@ -118,7 +118,7 @@ public class DeptServiceImpl implements DeptService { @@ -118,7 +118,7 @@ public class DeptServiceImpl implements DeptService {
118 log.info("[loadMenuIfUpdate][增量加载全量部门]"); 118 log.info("[loadMenuIfUpdate][增量加载全量部门]");
119 } 119 }
120 // 第二步,如果有更新,则从数据库加载所有部门 120 // 第二步,如果有更新,则从数据库加载所有部门
121 - return deptMapper.selectListIgnoreTenant(); 121 + return deptMapper.selectList();
122 } 122 }
123 123
124 @Override 124 @Override
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImpl.java
@@ -3,8 +3,8 @@ package cn.iocoder.yudao.module.system.service.dict; @@ -3,8 +3,8 @@ package cn.iocoder.yudao.module.system.service.dict;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO; 7 import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;
7 -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;  
8 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataCreateReqVO; 8 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataCreateReqVO;
9 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataExportReqVO; 9 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataExportReqVO;
10 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO; 10 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO;
@@ -99,8 +99,7 @@ public class DictDataServiceImpl implements DictDataService { @@ -99,8 +99,7 @@ public class DictDataServiceImpl implements DictDataService {
99 }); 99 });
100 labelDictDataCache = labelDictDataBuilder.build(); 100 labelDictDataCache = labelDictDataBuilder.build();
101 valueDictDataCache = valueDictDataBuilder.build(); 101 valueDictDataCache = valueDictDataBuilder.build();
102 - assert dataList.size() > 0; // 断言,避免告警  
103 - maxUpdateTime = dataList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); 102 + maxUpdateTime = CollectionUtils.getMaxValue(dataList, DictDataDO::getUpdateTime);
104 log.info("[initLocalCache][缓存字典数据,数量为:{}]", dataList.size()); 103 log.info("[initLocalCache][缓存字典数据,数量为:{}]", dataList.size());
105 } 104 }
106 105
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuService.java
@@ -66,7 +66,7 @@ public interface MenuService { @@ -66,7 +66,7 @@ public interface MenuService {
66 * @param menusStatuses 菜单状态数组 66 * @param menusStatuses 菜单状态数组
67 * @return 菜单列表 67 * @return 菜单列表
68 */ 68 */
69 - List<MenuDO> listMenusFromCache(Collection<Integer> menuTypes, Collection<Integer> menusStatuses); 69 + List<MenuDO> getMenuListFromCache(Collection<Integer> menuTypes, Collection<Integer> menusStatuses);
70 70
71 /** 71 /**
72 * 获得指定编号的菜单数组,从缓存中 72 * 获得指定编号的菜单数组,从缓存中
@@ -78,8 +78,8 @@ public interface MenuService { @@ -78,8 +78,8 @@ public interface MenuService {
78 * @param menusStatuses 菜单状态数组 78 * @param menusStatuses 菜单状态数组
79 * @return 菜单数组 79 * @return 菜单数组
80 */ 80 */
81 - List<MenuDO> listMenusFromCache(Collection<Long> menuIds, Collection<Integer> menuTypes,  
82 - Collection<Integer> menusStatuses); 81 + List<MenuDO> getMenuListFromCache(Collection<Long> menuIds, Collection<Integer> menuTypes,
  82 + Collection<Integer> menusStatuses);
83 83
84 /** 84 /**
85 * 获得权限对应的菜单数组 85 * 获得权限对应的菜单数组
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java
@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.system.service.permission; @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.system.service.permission;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; 4 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
5 -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuCreateReqVO; 6 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuCreateReqVO;
7 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuListReqVO; 7 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuListReqVO;
8 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuUpdateReqVO; 8 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuUpdateReqVO;
@@ -12,7 +12,6 @@ import cn.iocoder.yudao.module.system.dal.mysql.permission.MenuMapper; @@ -12,7 +12,6 @@ import cn.iocoder.yudao.module.system.dal.mysql.permission.MenuMapper;
12 import cn.iocoder.yudao.module.system.enums.permission.MenuIdEnum; 12 import cn.iocoder.yudao.module.system.enums.permission.MenuIdEnum;
13 import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum; 13 import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
14 import cn.iocoder.yudao.module.system.mq.producer.permission.MenuProducer; 14 import cn.iocoder.yudao.module.system.mq.producer.permission.MenuProducer;
15 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
16 import com.google.common.annotations.VisibleForTesting; 15 import com.google.common.annotations.VisibleForTesting;
17 import com.google.common.collect.ImmutableMap; 16 import com.google.common.collect.ImmutableMap;
18 import com.google.common.collect.ImmutableMultimap; 17 import com.google.common.collect.ImmutableMultimap;
@@ -95,8 +94,7 @@ public class MenuServiceImpl implements MenuService { @@ -95,8 +94,7 @@ public class MenuServiceImpl implements MenuService {
95 }); 94 });
96 menuCache = menuCacheBuilder.build(); 95 menuCache = menuCacheBuilder.build();
97 permissionMenuCache = permMenuCacheBuilder.build(); 96 permissionMenuCache = permMenuCacheBuilder.build();
98 - assert menuList.size() > 0; // 断言,避免告警  
99 - maxUpdateTime = menuList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); 97 + maxUpdateTime = CollectionUtils.getMaxValue(menuList, MenuDO::getUpdateTime);
100 log.info("[initLocalCache][缓存菜单,数量为:{}]", menuList.size()); 98 log.info("[initLocalCache][缓存菜单,数量为:{}]", menuList.size());
101 } 99 }
102 100
@@ -201,7 +199,7 @@ public class MenuServiceImpl implements MenuService { @@ -201,7 +199,7 @@ public class MenuServiceImpl implements MenuService {
201 } 199 }
202 200
203 @Override 201 @Override
204 - public List<MenuDO> listMenusFromCache(Collection<Integer> menuTypes, Collection<Integer> menusStatuses) { 202 + public List<MenuDO> getMenuListFromCache(Collection<Integer> menuTypes, Collection<Integer> menusStatuses) {
205 // 任一一个参数为空,则返回空 203 // 任一一个参数为空,则返回空
206 if (CollectionUtils.isAnyEmpty(menuTypes, menusStatuses)) { 204 if (CollectionUtils.isAnyEmpty(menuTypes, menusStatuses)) {
207 return Collections.emptyList(); 205 return Collections.emptyList();
@@ -213,8 +211,8 @@ public class MenuServiceImpl implements MenuService { @@ -213,8 +211,8 @@ public class MenuServiceImpl implements MenuService {
213 } 211 }
214 212
215 @Override 213 @Override
216 - public List<MenuDO> listMenusFromCache(Collection<Long> menuIds, Collection<Integer> menuTypes,  
217 - Collection<Integer> menusStatuses) { 214 + public List<MenuDO> getMenuListFromCache(Collection<Long> menuIds, Collection<Integer> menuTypes,
  215 + Collection<Integer> menusStatuses) {
218 // 任一一个参数为空,则返回空 216 // 任一一个参数为空,则返回空
219 if (CollectionUtils.isAnyEmpty(menuIds, menuTypes, menusStatuses)) { 217 if (CollectionUtils.isAnyEmpty(menuIds, menuTypes, menusStatuses)) {
220 return Collections.emptyList(); 218 return Collections.emptyList();
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionService.java
@@ -33,8 +33,8 @@ public interface PermissionService extends SecurityPermissionFrameworkService, D @@ -33,8 +33,8 @@ public interface PermissionService extends SecurityPermissionFrameworkService, D
33 * @param menusStatuses 菜单状态数组 33 * @param menusStatuses 菜单状态数组
34 * @return 菜单列表 34 * @return 菜单列表
35 */ 35 */
36 - List<MenuDO> getRoleMenusFromCache(Collection<Long> roleIds, Collection<Integer> menuTypes,  
37 - Collection<Integer> menusStatuses); 36 + List<MenuDO> getRoleMenuListFromCache(Collection<Long> roleIds, Collection<Integer> menuTypes,
  37 + Collection<Integer> menusStatuses);
38 38
39 /** 39 /**
40 * 获得用户拥有的角色编号集合 40 * 获得用户拥有的角色编号集合
@@ -51,7 +51,7 @@ public interface PermissionService extends SecurityPermissionFrameworkService, D @@ -51,7 +51,7 @@ public interface PermissionService extends SecurityPermissionFrameworkService, D
51 * @param roleId 角色编号 51 * @param roleId 角色编号
52 * @return 菜单编号集合 52 * @return 菜单编号集合
53 */ 53 */
54 - Set<Long> listRoleMenuIds(Long roleId); 54 + Set<Long> getRoleMenuIds(Long roleId);
55 55
56 /** 56 /**
57 * 设置角色菜单 57 * 设置角色菜单
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java
@@ -3,6 +3,14 @@ package cn.iocoder.yudao.module.system.service.permission; @@ -3,6 +3,14 @@ package cn.iocoder.yudao.module.system.service.permission;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.collection.CollectionUtil; 4 import cn.hutool.core.collection.CollectionUtil;
5 import cn.hutool.core.util.ArrayUtil; 5 import cn.hutool.core.util.ArrayUtil;
  6 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  7 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  8 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  9 +import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
  10 +import cn.iocoder.yudao.framework.security.core.LoginUser;
  11 +import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum;
  12 +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
  13 +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
6 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; 14 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
7 import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; 15 import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
8 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; 16 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
@@ -12,13 +20,6 @@ import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper; @@ -12,13 +20,6 @@ import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper;
12 import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper; 20 import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper;
13 import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer; 21 import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer;
14 import cn.iocoder.yudao.module.system.service.dept.DeptService; 22 import cn.iocoder.yudao.module.system.service.dept.DeptService;
15 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
16 -import cn.iocoder.yudao.framework.common.util.collection.MapUtils;  
17 -import cn.iocoder.yudao.framework.common.util.json.JsonUtils;  
18 -import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;  
19 -import cn.iocoder.yudao.framework.security.core.LoginUser;  
20 -import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum;  
21 -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;  
22 import com.google.common.collect.ImmutableMultimap; 23 import com.google.common.collect.ImmutableMultimap;
23 import com.google.common.collect.Multimap; 24 import com.google.common.collect.Multimap;
24 import com.google.common.collect.Sets; 25 import com.google.common.collect.Sets;
@@ -94,10 +95,10 @@ public class PermissionServiceImpl implements PermissionService { @@ -94,10 +95,10 @@ public class PermissionServiceImpl implements PermissionService {
94 */ 95 */
95 @Override 96 @Override
96 @PostConstruct 97 @PostConstruct
  98 + @TenantIgnore // 初始化缓存,无需租户过滤
97 public void initLocalCache() { 99 public void initLocalCache() {
98 - Date now = new Date();  
99 // 获取角色与菜单的关联列表,如果有更新 100 // 获取角色与菜单的关联列表,如果有更新
100 - List<RoleMenuDO> roleMenuList = this.loadRoleMenuIfUpdate(maxUpdateTime); 101 + List<RoleMenuDO> roleMenuList = loadRoleMenuIfUpdate(maxUpdateTime);
101 if (CollUtil.isEmpty(roleMenuList)) { 102 if (CollUtil.isEmpty(roleMenuList)) {
102 return; 103 return;
103 } 104 }
@@ -111,8 +112,7 @@ public class PermissionServiceImpl implements PermissionService { @@ -111,8 +112,7 @@ public class PermissionServiceImpl implements PermissionService {
111 }); 112 });
112 roleMenuCache = roleMenuCacheBuilder.build(); 113 roleMenuCache = roleMenuCacheBuilder.build();
113 menuRoleCache = menuRoleCacheBuilder.build(); 114 menuRoleCache = menuRoleCacheBuilder.build();
114 - assert roleMenuList.size() > 0; // 断言,避免告警  
115 - maxUpdateTime = now; 115 + maxUpdateTime = CollectionUtils.getMaxValue(roleMenuList, RoleMenuDO::getUpdateTime);
116 log.info("[initLocalCache][初始化角色与菜单的关联数量为 {}]", roleMenuList.size()); 116 log.info("[initLocalCache][初始化角色与菜单的关联数量为 {}]", roleMenuList.size());
117 } 117 }
118 118
@@ -128,7 +128,7 @@ public class PermissionServiceImpl implements PermissionService { @@ -128,7 +128,7 @@ public class PermissionServiceImpl implements PermissionService {
128 * @param maxUpdateTime 当前角色与菜单的关联的最大更新时间 128 * @param maxUpdateTime 当前角色与菜单的关联的最大更新时间
129 * @return 角色与菜单的关联列表 129 * @return 角色与菜单的关联列表
130 */ 130 */
131 - private List<RoleMenuDO> loadRoleMenuIfUpdate(Date maxUpdateTime) { 131 + protected List<RoleMenuDO> loadRoleMenuIfUpdate(Date maxUpdateTime) {
132 // 第一步,判断是否要更新。 132 // 第一步,判断是否要更新。
133 if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 133 if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据
134 log.info("[loadRoleMenuIfUpdate][首次加载全量角色与菜单的关联]"); 134 log.info("[loadRoleMenuIfUpdate][首次加载全量角色与菜单的关联]");
@@ -143,21 +143,22 @@ public class PermissionServiceImpl implements PermissionService { @@ -143,21 +143,22 @@ public class PermissionServiceImpl implements PermissionService {
143 } 143 }
144 144
145 @Override 145 @Override
146 - public List<MenuDO> getRoleMenusFromCache(Collection<Long> roleIds, Collection<Integer> menuTypes,  
147 - Collection<Integer> menusStatuses) { 146 + public List<MenuDO> getRoleMenuListFromCache(Collection<Long> roleIds, Collection<Integer> menuTypes,
  147 + Collection<Integer> menusStatuses) {
148 // 任一一个参数为空时,不返回任何菜单 148 // 任一一个参数为空时,不返回任何菜单
149 if (CollectionUtils.isAnyEmpty(roleIds, menuTypes, menusStatuses)) { 149 if (CollectionUtils.isAnyEmpty(roleIds, menuTypes, menusStatuses)) {
150 return Collections.emptyList(); 150 return Collections.emptyList();
151 } 151 }
152 - // 判断角色是否包含管理员 152 +
  153 + // 判断角色是否包含超级管理员。如果是超级管理员,获取到全部
153 List<RoleDO> roleList = roleService.getRolesFromCache(roleIds); 154 List<RoleDO> roleList = roleService.getRolesFromCache(roleIds);
154 - boolean hasAdmin = roleService.hasAnyAdmin(roleList);  
155 - // 获得角色拥有的菜单关联  
156 - if (hasAdmin) { // 管理员,获取到全部  
157 - return menuService.listMenusFromCache(menuTypes, menusStatuses); 155 + if (roleService.hasAnySuperAdmin(roleList)) {
  156 + return menuService.getMenuListFromCache(menuTypes, menusStatuses);
158 } 157 }
  158 +
  159 + // 获得角色拥有的菜单关联
159 List<Long> menuIds = MapUtils.getList(roleMenuCache, roleIds); 160 List<Long> menuIds = MapUtils.getList(roleMenuCache, roleIds);
160 - return menuService.listMenusFromCache(menuIds, menuTypes, menusStatuses); 161 + return menuService.getMenuListFromCache(menuIds, menuTypes, menusStatuses);
161 } 162 }
162 163
163 @Override 164 @Override
@@ -174,10 +175,10 @@ public class PermissionServiceImpl implements PermissionService { @@ -174,10 +175,10 @@ public class PermissionServiceImpl implements PermissionService {
174 } 175 }
175 176
176 @Override 177 @Override
177 - public Set<Long> listRoleMenuIds(Long roleId) { 178 + public Set<Long> getRoleMenuIds(Long roleId) {
178 // 如果是管理员的情况下,获取全部菜单编号 179 // 如果是管理员的情况下,获取全部菜单编号
179 RoleDO role = roleService.getRole(roleId); 180 RoleDO role = roleService.getRole(roleId);
180 - if (roleService.hasAnyAdmin(Collections.singletonList(role))) { 181 + if (roleService.hasAnySuperAdmin(Collections.singletonList(role))) {
181 return CollectionUtils.convertSet(menuService.getMenus(), MenuDO::getId); 182 return CollectionUtils.convertSet(menuService.getMenus(), MenuDO::getId);
182 } 183 }
183 // 如果是非管理员的情况下,获得拥有的菜单编号 184 // 如果是非管理员的情况下,获得拥有的菜单编号
@@ -302,7 +303,7 @@ public class PermissionServiceImpl implements PermissionService { @@ -302,7 +303,7 @@ public class PermissionServiceImpl implements PermissionService {
302 return false; 303 return false;
303 } 304 }
304 // 判断是否是超管。如果是,当然符合条件 305 // 判断是否是超管。如果是,当然符合条件
305 - if (roleService.hasAnyAdmin(roleIds)) { 306 + if (roleService.hasAnySuperAdmin(roleIds)) {
306 return true; 307 return true;
307 } 308 }
308 309
@@ -337,7 +338,7 @@ public class PermissionServiceImpl implements PermissionService { @@ -337,7 +338,7 @@ public class PermissionServiceImpl implements PermissionService {
337 return false; 338 return false;
338 } 339 }
339 // 判断是否是超管。如果是,当然符合条件 340 // 判断是否是超管。如果是,当然符合条件
340 - if (roleService.hasAnyAdmin(roleIds)) { 341 + if (roleService.hasAnySuperAdmin(roleIds)) {
341 return true; 342 return true;
342 } 343 }
343 Set<String> userRoles = CollectionUtils.convertSet(roleService.getRolesFromCache(roleIds), 344 Set<String> userRoles = CollectionUtils.convertSet(roleService.getRolesFromCache(roleIds),
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleService.java
@@ -90,12 +90,12 @@ public interface RoleService { @@ -90,12 +90,12 @@ public interface RoleService {
90 List<RoleDO> getRolesFromCache(Collection<Long> ids); 90 List<RoleDO> getRolesFromCache(Collection<Long> ids);
91 91
92 /** 92 /**
93 - * 判断角色数组中,是否有管理员 93 + * 判断角色数组中,是否有超级管理员
94 * 94 *
95 * @param roleList 角色数组 95 * @param roleList 角色数组
96 * @return 是否有管理员 96 * @return 是否有管理员
97 */ 97 */
98 - boolean hasAnyAdmin(Collection<RoleDO> roleList); 98 + boolean hasAnySuperAdmin(Collection<RoleDO> roleList);
99 99
100 /** 100 /**
101 * 判断角色编号数组中,是否有管理员 101 * 判断角色编号数组中,是否有管理员
@@ -103,8 +103,8 @@ public interface RoleService { @@ -103,8 +103,8 @@ public interface RoleService {
103 * @param ids 角色编号数组 103 * @param ids 角色编号数组
104 * @return 是否有管理员 104 * @return 是否有管理员
105 */ 105 */
106 - default boolean hasAnyAdmin(Set<Long> ids) {  
107 - return hasAnyAdmin(getRolesFromCache(ids)); 106 + default boolean hasAnySuperAdmin(Set<Long> ids) {
  107 + return hasAnySuperAdmin(getRolesFromCache(ids));
108 } 108 }
109 109
110 /** 110 /**
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java
@@ -6,8 +6,8 @@ import cn.hutool.core.util.ObjectUtil; @@ -6,8 +6,8 @@ import cn.hutool.core.util.ObjectUtil;
6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
7 import cn.iocoder.yudao.framework.common.pojo.PageResult; 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
8 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 8 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
9 -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;  
10 import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum; 9 import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum;
  10 +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
11 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO; 11 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO;
12 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO; 12 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO;
13 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO; 13 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO;
@@ -19,7 +19,6 @@ import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; @@ -19,7 +19,6 @@ import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
19 import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; 19 import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
20 import cn.iocoder.yudao.module.system.mq.producer.permission.RoleProducer; 20 import cn.iocoder.yudao.module.system.mq.producer.permission.RoleProducer;
21 import com.google.common.annotations.VisibleForTesting; 21 import com.google.common.annotations.VisibleForTesting;
22 -import com.google.common.collect.ImmutableMap;  
23 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
24 import org.springframework.lang.Nullable; 23 import org.springframework.lang.Nullable;
25 import org.springframework.scheduling.annotation.Scheduled; 24 import org.springframework.scheduling.annotation.Scheduled;
@@ -78,19 +77,17 @@ public class RoleServiceImpl implements RoleService { @@ -78,19 +77,17 @@ public class RoleServiceImpl implements RoleService {
78 */ 77 */
79 @Override 78 @Override
80 @PostConstruct 79 @PostConstruct
  80 + @TenantIgnore // 忽略自动多租户,全局初始化缓存
81 public void initLocalCache() { 81 public void initLocalCache() {
82 // 获取角色列表,如果有更新 82 // 获取角色列表,如果有更新
83 - List<RoleDO> roleList = this.loadRoleIfUpdate(maxUpdateTime); 83 + List<RoleDO> roleList = loadRoleIfUpdate(maxUpdateTime);
84 if (CollUtil.isEmpty(roleList)) { 84 if (CollUtil.isEmpty(roleList)) {
85 return; 85 return;
86 } 86 }
87 87
88 // 写入缓存 88 // 写入缓存
89 - ImmutableMap.Builder<Long, RoleDO> builder = ImmutableMap.builder();  
90 - roleList.forEach(sysRoleDO -> builder.put(sysRoleDO.getId(), sysRoleDO));  
91 - roleCache = builder.build();  
92 - assert roleList.size() > 0; // 断言,避免告警  
93 - maxUpdateTime = roleList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); 89 + roleCache = CollectionUtils.convertMap(roleList, RoleDO::getId);
  90 + maxUpdateTime = CollectionUtils.getMaxValue(roleList, RoleDO::getUpdateTime);
94 log.info("[initLocalCache][初始化 Role 数量为 {}]", roleList.size()); 91 log.info("[initLocalCache][初始化 Role 数量为 {}]", roleList.size());
95 } 92 }
96 93
@@ -216,11 +213,11 @@ public class RoleServiceImpl implements RoleService { @@ -216,11 +213,11 @@ public class RoleServiceImpl implements RoleService {
216 } 213 }
217 214
218 @Override 215 @Override
219 - public boolean hasAnyAdmin(Collection<RoleDO> roleList) { 216 + public boolean hasAnySuperAdmin(Collection<RoleDO> roleList) {
220 if (CollectionUtil.isEmpty(roleList)) { 217 if (CollectionUtil.isEmpty(roleList)) {
221 return false; 218 return false;
222 } 219 }
223 - return roleList.stream().anyMatch(roleDO -> RoleCodeEnum.ADMIN.getKey().equals(roleDO.getCode())); 220 + return roleList.stream().anyMatch(roleDO -> RoleCodeEnum.SUPER_ADMIN.getCode().equals(roleDO.getCode()));
224 } 221 }
225 222
226 @Override 223 @Override
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceImpl.java
1 package cn.iocoder.yudao.module.system.service.sms; 1 package cn.iocoder.yudao.module.system.service.sms;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  6 +import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
  7 +import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
4 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelCreateReqVO; 8 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelCreateReqVO;
5 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; 9 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO;
6 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelUpdateReqVO; 10 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelUpdateReqVO;
@@ -8,10 +12,6 @@ import cn.iocoder.yudao.module.system.convert.sms.SmsChannelConvert; @@ -8,10 +12,6 @@ import cn.iocoder.yudao.module.system.convert.sms.SmsChannelConvert;
8 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; 12 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
9 import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper; 13 import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper;
10 import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer; 14 import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
11 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
12 -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;  
13 -import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;  
14 -import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;  
15 import lombok.extern.slf4j.Slf4j; 15 import lombok.extern.slf4j.Slf4j;
16 import org.springframework.scheduling.annotation.Scheduled; 16 import org.springframework.scheduling.annotation.Scheduled;
17 import org.springframework.stereotype.Service; 17 import org.springframework.stereotype.Service;
@@ -19,13 +19,12 @@ import org.springframework.stereotype.Service; @@ -19,13 +19,12 @@ import org.springframework.stereotype.Service;
19 import javax.annotation.PostConstruct; 19 import javax.annotation.PostConstruct;
20 import javax.annotation.Resource; 20 import javax.annotation.Resource;
21 import java.util.Collection; 21 import java.util.Collection;
22 -import java.util.Comparator;  
23 import java.util.Date; 22 import java.util.Date;
24 import java.util.List; 23 import java.util.List;
25 24
  25 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
26 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN; 26 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN;
27 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS; 27 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS;
28 -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;  
29 28
30 /** 29 /**
31 * 短信渠道Service实现类 30 * 短信渠道Service实现类
@@ -74,8 +73,7 @@ public class SmsChannelServiceImpl implements SmsChannelService { @@ -74,8 +73,7 @@ public class SmsChannelServiceImpl implements SmsChannelService {
74 propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties)); 73 propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties));
75 74
76 // 写入缓存 75 // 写入缓存
77 - assert smsChannels.size() > 0; // 断言,避免告警  
78 - maxUpdateTime = smsChannels.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); 76 + maxUpdateTime = CollectionUtils.getMaxValue(smsChannels, SmsChannelDO::getUpdateTime);
79 log.info("[initSmsClients][初始化 SmsChannel 数量为 {}]", smsChannels.size()); 77 log.info("[initSmsClients][初始化 SmsChannel 数量为 {}]", smsChannels.size());
80 } 78 }
81 79
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java
@@ -3,24 +3,23 @@ package cn.iocoder.yudao.module.system.service.sms; @@ -3,24 +3,23 @@ package cn.iocoder.yudao.module.system.service.sms;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.ReUtil; 4 import cn.hutool.core.util.ReUtil;
5 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
6 -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 6 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  8 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  9 +import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
  10 +import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
  11 +import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
  12 +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
7 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO; 13 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO;
8 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO; 14 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO;
9 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; 15 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO;
10 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateUpdateReqVO; 16 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateUpdateReqVO;
11 import cn.iocoder.yudao.module.system.convert.sms.SmsTemplateConvert; 17 import cn.iocoder.yudao.module.system.convert.sms.SmsTemplateConvert;
  18 +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
12 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; 19 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
13 import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsTemplateMapper; 20 import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsTemplateMapper;
14 import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer; 21 import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
15 -import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;  
16 -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;  
17 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
18 -import cn.iocoder.yudao.framework.sms.core.client.SmsClient;  
19 -import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;  
20 -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;  
21 -import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;  
22 import com.google.common.annotations.VisibleForTesting; 22 import com.google.common.annotations.VisibleForTesting;
23 -import com.google.common.collect.ImmutableMap;  
24 import lombok.extern.slf4j.Slf4j; 23 import lombok.extern.slf4j.Slf4j;
25 import org.springframework.scheduling.annotation.Scheduled; 24 import org.springframework.scheduling.annotation.Scheduled;
26 import org.springframework.stereotype.Service; 25 import org.springframework.stereotype.Service;
@@ -31,8 +30,8 @@ import javax.annotation.Resource; @@ -31,8 +30,8 @@ import javax.annotation.Resource;
31 import java.util.*; 30 import java.util.*;
32 import java.util.regex.Pattern; 31 import java.util.regex.Pattern;
33 32
34 -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;  
35 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 33 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  34 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
36 35
37 /** 36 /**
38 * 短信模板 Service 实现类 37 * 短信模板 Service 实现类
@@ -89,11 +88,8 @@ public class SmsTemplateServiceImpl implements SmsTemplateService { @@ -89,11 +88,8 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
89 } 88 }
90 89
91 // 写入缓存 90 // 写入缓存
92 - ImmutableMap.Builder<String, SmsTemplateDO> builder = ImmutableMap.builder();  
93 - smsTemplateList.forEach(sysSmsTemplateDO -> builder.put(sysSmsTemplateDO.getCode(), sysSmsTemplateDO));  
94 - smsTemplateCache = builder.build();  
95 - assert smsTemplateList.size() > 0; // 断言,避免告警  
96 - maxUpdateTime = smsTemplateList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); 91 + smsTemplateCache = CollectionUtils.convertMap(smsTemplateList, SmsTemplateDO::getCode);
  92 + maxUpdateTime = CollectionUtils.getMaxValue(smsTemplateList, SmsTemplateDO::getUpdateTime);
97 log.info("[initLocalCache][初始化 SmsTemplate 数量为 {}]", smsTemplateList.size()); 93 log.info("[initLocalCache][初始化 SmsTemplate 数量为 {}]", smsTemplateList.size());
98 } 94 }
99 95
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImpl.java
1 package cn.iocoder.yudao.module.system.service.tenant; 1 package cn.iocoder.yudao.module.system.service.tenant;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackageCreateReqVO; 6 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackageCreateReqVO;
6 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO; 7 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO;
7 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackageUpdateReqVO; 8 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackageUpdateReqVO;
8 import cn.iocoder.yudao.module.system.convert.tenant.TenantPackageConvert; 9 import cn.iocoder.yudao.module.system.convert.tenant.TenantPackageConvert;
  10 +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
9 import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; 11 import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO;
10 import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantPackageMapper; 12 import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantPackageMapper;
11 import org.springframework.context.annotation.Lazy; 13 import org.springframework.context.annotation.Lazy;
12 import org.springframework.stereotype.Service; 14 import org.springframework.stereotype.Service;
  15 +import org.springframework.transaction.annotation.Transactional;
13 import org.springframework.validation.annotation.Validated; 16 import org.springframework.validation.annotation.Validated;
14 17
15 import javax.annotation.Resource; 18 import javax.annotation.Resource;
@@ -45,12 +48,18 @@ public class TenantPackageServiceImpl implements TenantPackageService { @@ -45,12 +48,18 @@ public class TenantPackageServiceImpl implements TenantPackageService {
45 } 48 }
46 49
47 @Override 50 @Override
  51 + @Transactional(rollbackFor = Exception.class)
48 public void updateTenantPackage(TenantPackageUpdateReqVO updateReqVO) { 52 public void updateTenantPackage(TenantPackageUpdateReqVO updateReqVO) {
49 // 校验存在 53 // 校验存在
50 - this.validateTenantPackageExists(updateReqVO.getId()); 54 + TenantPackageDO tenantPackage = validateTenantPackageExists(updateReqVO.getId());
51 // 更新 55 // 更新
52 TenantPackageDO updateObj = TenantPackageConvert.INSTANCE.convert(updateReqVO); 56 TenantPackageDO updateObj = TenantPackageConvert.INSTANCE.convert(updateReqVO);
53 tenantPackageMapper.updateById(updateObj); 57 tenantPackageMapper.updateById(updateObj);
  58 + // 如果菜单发生变化,则修改每个租户的菜单
  59 + if (!CollUtil.isEqualList(tenantPackage.getMenuIds(), updateReqVO.getMenuIds())) {
  60 + List<TenantDO> tenants = tenantService.getTenantListByPackageId(tenantPackage.getId());
  61 + tenants.forEach(tenant -> tenantService.updateTenantRoleMenu(tenant.getId(), updateReqVO.getMenuIds()));
  62 + }
54 } 63 }
55 64
56 @Override 65 @Override
@@ -63,10 +72,12 @@ public class TenantPackageServiceImpl implements TenantPackageService { @@ -63,10 +72,12 @@ public class TenantPackageServiceImpl implements TenantPackageService {
63 tenantPackageMapper.deleteById(id); 72 tenantPackageMapper.deleteById(id);
64 } 73 }
65 74
66 - private void validateTenantPackageExists(Long id) {  
67 - if (tenantPackageMapper.selectById(id) == null) { 75 + private TenantPackageDO validateTenantPackageExists(Long id) {
  76 + TenantPackageDO tenantPackage = tenantPackageMapper.selectById(id);
  77 + if (tenantPackage == null) {
68 throw exception(TENANT_PACKAGE_NOT_EXISTS); 78 throw exception(TENANT_PACKAGE_NOT_EXISTS);
69 } 79 }
  80 + return tenantPackage;
70 } 81 }
71 82
72 private void validateTenantUsed(Long id) { 83 private void validateTenantUsed(Long id) {
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java
@@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; @@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
11 import javax.validation.Valid; 11 import javax.validation.Valid;
12 import java.util.Collection; 12 import java.util.Collection;
13 import java.util.List; 13 import java.util.List;
  14 +import java.util.Set;
14 15
15 /** 16 /**
16 * 租户 Service 接口 17 * 租户 Service 接口
@@ -20,6 +21,11 @@ import java.util.List; @@ -20,6 +21,11 @@ import java.util.List;
20 public interface TenantService extends TenantFrameworkService { 21 public interface TenantService extends TenantFrameworkService {
21 22
22 /** 23 /**
  24 + * 初始化租户的本地缓存
  25 + */
  26 + void initLocalCache();
  27 +
  28 + /**
23 * 创建租户 29 * 创建租户
24 * 30 *
25 * @param createReqVO 创建信息 31 * @param createReqVO 创建信息
@@ -35,6 +41,14 @@ public interface TenantService extends TenantFrameworkService { @@ -35,6 +41,14 @@ public interface TenantService extends TenantFrameworkService {
35 void updateTenant(@Valid TenantUpdateReqVO updateReqVO); 41 void updateTenant(@Valid TenantUpdateReqVO updateReqVO);
36 42
37 /** 43 /**
  44 + * 更新租户的角色菜单
  45 + *
  46 + * @param tenantId 租户编号
  47 + * @param menuIds 菜单编号数组
  48 + */
  49 + void updateTenantRoleMenu(Long tenantId, Set<Long> menuIds);
  50 +
  51 + /**
38 * 删除租户 52 * 删除租户
39 * 53 *
40 * @param id 编号 54 * @param id 编号
@@ -89,4 +103,12 @@ public interface TenantService extends TenantFrameworkService { @@ -89,4 +103,12 @@ public interface TenantService extends TenantFrameworkService {
89 */ 103 */
90 Integer getTenantCountByPackageId(Long packageId); 104 Integer getTenantCountByPackageId(Long packageId);
91 105
  106 + /**
  107 + * 获得使用指定套餐的租户数组
  108 + *
  109 + * @param packageId 租户套餐编号
  110 + * @return 租户数组
  111 + */
  112 + List<TenantDO> getTenantListByPackageId(Long packageId);
  113 +
92 } 114 }
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java
1 package cn.iocoder.yudao.module.system.service.tenant; 1 package cn.iocoder.yudao.module.system.service.tenant;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.lang.Assert;
  5 +import cn.hutool.core.util.ObjectUtil;
3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 8 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
@@ -11,21 +14,27 @@ import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantEx @@ -11,21 +14,27 @@ import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantEx
11 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; 14 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO;
12 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantUpdateReqVO; 15 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantUpdateReqVO;
13 import cn.iocoder.yudao.module.system.convert.tenant.TenantConvert; 16 import cn.iocoder.yudao.module.system.convert.tenant.TenantConvert;
  17 +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
14 import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; 18 import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
  19 +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO;
15 import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper; 20 import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper;
16 import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; 21 import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
17 import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; 22 import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
  23 +import cn.iocoder.yudao.module.system.mq.producer.tenant.TenantProducer;
18 import cn.iocoder.yudao.module.system.service.permission.PermissionService; 24 import cn.iocoder.yudao.module.system.service.permission.PermissionService;
19 import cn.iocoder.yudao.module.system.service.permission.RoleService; 25 import cn.iocoder.yudao.module.system.service.permission.RoleService;
20 import cn.iocoder.yudao.module.system.service.user.AdminUserService; 26 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
  27 +import lombok.extern.slf4j.Slf4j;
  28 +import org.springframework.scheduling.annotation.Scheduled;
21 import org.springframework.stereotype.Service; 29 import org.springframework.stereotype.Service;
22 import org.springframework.transaction.annotation.Transactional; 30 import org.springframework.transaction.annotation.Transactional;
  31 +import org.springframework.transaction.support.TransactionSynchronization;
  32 +import org.springframework.transaction.support.TransactionSynchronizationManager;
23 import org.springframework.validation.annotation.Validated; 33 import org.springframework.validation.annotation.Validated;
24 34
  35 +import javax.annotation.PostConstruct;
25 import javax.annotation.Resource; 36 import javax.annotation.Resource;
26 -import java.util.Collection;  
27 -import java.util.Collections;  
28 -import java.util.List; 37 +import java.util.*;
29 38
30 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 39 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
31 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; 40 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
@@ -37,8 +46,27 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; @@ -37,8 +46,27 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
37 */ 46 */
38 @Service 47 @Service
39 @Validated 48 @Validated
  49 +@Slf4j
40 public class TenantServiceImpl implements TenantService { 50 public class TenantServiceImpl implements TenantService {
41 51
  52 + /**
  53 + * 定时执行 {@link #schedulePeriodicRefresh()} 的周期
  54 + * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高
  55 + */
  56 + private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
  57 +
  58 + /**
  59 + * 角色缓存
  60 + * key:角色编号 {@link RoleDO#getId()}
  61 + *
  62 + * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
  63 + */
  64 + private volatile Map<Long, TenantDO> tenantCache;
  65 + /**
  66 + * 缓存角色的最大更新时间,用于后续的增量轮询,判断是否有更新
  67 + */
  68 + private volatile Date maxUpdateTime;
  69 +
42 @Resource 70 @Resource
43 private TenantMapper tenantMapper; 71 private TenantMapper tenantMapper;
44 72
@@ -51,15 +79,61 @@ public class TenantServiceImpl implements TenantService { @@ -51,15 +79,61 @@ public class TenantServiceImpl implements TenantService {
51 @Resource 79 @Resource
52 private PermissionService permissionService; 80 private PermissionService permissionService;
53 81
  82 + @Resource
  83 + private TenantProducer tenantProducer;
  84 +
  85 + /**
  86 + * 初始化 {@link #tenantCache} 缓存
  87 + */
  88 + @Override
  89 + @PostConstruct
  90 + public void initLocalCache() {
  91 + // 获取租户列表,如果有更新
  92 + List<TenantDO> tenantList = loadTenantIfUpdate(maxUpdateTime);
  93 + if (CollUtil.isEmpty(tenantList)) {
  94 + return;
  95 + }
  96 +
  97 + // 写入缓存
  98 + tenantCache = CollectionUtils.convertImmutableMap(tenantList, TenantDO::getId);
  99 + maxUpdateTime = CollectionUtils.getMaxValue(tenantList, TenantDO::getUpdateTime);
  100 + log.info("[initLocalCache][初始化 Tenant 数量为 {}]", tenantList.size());
  101 + }
  102 +
  103 + @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
  104 + public void schedulePeriodicRefresh() {
  105 + initLocalCache();
  106 + }
  107 +
  108 + /**
  109 + * 如果租户发生变化,从数据库中获取最新的全量租户。
  110 + * 如果未发生变化,则返回空
  111 + *
  112 + * @param maxUpdateTime 当前租户的最大更新时间
  113 + * @return 租户列表
  114 + */
  115 + private List<TenantDO> loadTenantIfUpdate(Date maxUpdateTime) {
  116 + // 第一步,判断是否要更新。
  117 + if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据
  118 + log.info("[loadTenantIfUpdate][首次加载全量租户]");
  119 + } else { // 判断数据库中是否有更新的租户
  120 + if (tenantMapper.selectExistsByUpdateTimeAfter(maxUpdateTime) == null) {
  121 + return null;
  122 + }
  123 + log.info("[loadTenantIfUpdate][增量加载全量租户]");
  124 + }
  125 + // 第二步,如果有更新,则从数据库加载所有租户
  126 + return tenantMapper.selectList();
  127 + }
  128 +
54 @Override 129 @Override
55 public List<Long> getTenantIds() { 130 public List<Long> getTenantIds() {
56 - List<TenantDO> tenants = tenantMapper.selectList();  
57 - return CollectionUtils.convertList(tenants, TenantDO::getId); 131 + return new ArrayList<>(tenantCache.keySet());
58 } 132 }
59 133
60 @Override 134 @Override
61 public void validTenant(Long id) { 135 public void validTenant(Long id) {
62 - TenantDO tenant = tenantMapper.selectById(id); 136 + TenantDO tenant = tenantCache.get(id);
63 if (tenant == null) { 137 if (tenant == null) {
64 throw exception(TENANT_NOT_EXISTS); 138 throw exception(TENANT_NOT_EXISTS);
65 } 139 }
@@ -75,7 +149,7 @@ public class TenantServiceImpl implements TenantService { @@ -75,7 +149,7 @@ public class TenantServiceImpl implements TenantService {
75 @Transactional(rollbackFor = Exception.class) 149 @Transactional(rollbackFor = Exception.class)
76 public Long createTenant(TenantCreateReqVO createReqVO) { 150 public Long createTenant(TenantCreateReqVO createReqVO) {
77 // 校验套餐被禁用 151 // 校验套餐被禁用
78 - tenantPackageService.validTenantPackage(createReqVO.getPackageId()); 152 + TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(createReqVO.getPackageId());
79 153
80 // 创建租户 154 // 创建租户
81 TenantDO tenant = TenantConvert.INSTANCE.convert(createReqVO); 155 TenantDO tenant = TenantConvert.INSTANCE.convert(createReqVO);
@@ -83,13 +157,19 @@ public class TenantServiceImpl implements TenantService { @@ -83,13 +157,19 @@ public class TenantServiceImpl implements TenantService {
83 157
84 TenantUtils.execute(tenant.getId(), () -> { 158 TenantUtils.execute(tenant.getId(), () -> {
85 // 创建角色 159 // 创建角色
86 - Long roleId = createRole(); 160 + Long roleId = createRole(tenantPackage);
87 // 创建用户,并分配角色 161 // 创建用户,并分配角色
88 Long userId = createUser(roleId, createReqVO); 162 Long userId = createUser(roleId, createReqVO);
89 // 修改租户的管理员 163 // 修改租户的管理员
90 tenantMapper.updateById(new TenantDO().setId(tenant.getId()).setContactUserId(userId)); 164 tenantMapper.updateById(new TenantDO().setId(tenant.getId()).setContactUserId(userId));
91 }); 165 });
92 - // 返回 166 + // 发送刷新消息
  167 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
  168 + @Override
  169 + public void afterCommit() {
  170 + tenantProducer.sendTenantRefreshMessage();
  171 + }
  172 + });
93 return tenant.getId(); 173 return tenant.getId();
94 } 174 }
95 175
@@ -101,36 +181,80 @@ public class TenantServiceImpl implements TenantService { @@ -101,36 +181,80 @@ public class TenantServiceImpl implements TenantService {
101 return userId; 181 return userId;
102 } 182 }
103 183
104 - private Long createRole() { 184 + private Long createRole(TenantPackageDO tenantPackage) {
  185 + // 创建角色
105 RoleCreateReqVO reqVO = new RoleCreateReqVO(); 186 RoleCreateReqVO reqVO = new RoleCreateReqVO();
106 - reqVO.setName(RoleCodeEnum.ADMIN.name()).setCode(RoleCodeEnum.ADMIN.getKey()).setSort(0);  
107 - return roleService.createRole(reqVO, RoleTypeEnum.SYSTEM.getType()); 187 + reqVO.setName(RoleCodeEnum.TENANT_ADMIN.getName()).setCode(RoleCodeEnum.TENANT_ADMIN.getCode())
  188 + .setSort(0).setRemark("系统自动生成");
  189 + Long roleId = roleService.createRole(reqVO, RoleTypeEnum.SYSTEM.getType());
  190 + // 分配权限
  191 + permissionService.assignRoleMenu(roleId, tenantPackage.getMenuIds());
  192 + return roleId;
108 } 193 }
109 194
110 @Override 195 @Override
  196 + @Transactional(rollbackFor = Exception.class)
111 public void updateTenant(TenantUpdateReqVO updateReqVO) { 197 public void updateTenant(TenantUpdateReqVO updateReqVO) {
112 // 校验存在 198 // 校验存在
113 - this.validateTenantExists(updateReqVO.getId()); 199 + TenantDO tenant = validateTenantExists(updateReqVO.getId());
114 // 校验套餐被禁用 200 // 校验套餐被禁用
115 - tenantPackageService.validTenantPackage(updateReqVO.getPackageId()); 201 + TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(updateReqVO.getPackageId());
116 202
117 - // 更新 203 + // 更新租户
118 TenantDO updateObj = TenantConvert.INSTANCE.convert(updateReqVO); 204 TenantDO updateObj = TenantConvert.INSTANCE.convert(updateReqVO);
119 tenantMapper.updateById(updateObj); 205 tenantMapper.updateById(updateObj);
  206 + // 如果套餐发生变化,则修改其角色的权限
  207 + if (ObjectUtil.notEqual(tenant.getPackageId(), updateReqVO.getPackageId())) {
  208 + updateTenantRoleMenu(tenant.getId(), tenantPackage.getMenuIds());
  209 + }
  210 + // 发送刷新消息
  211 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
  212 + @Override
  213 + public void afterCommit() {
  214 + tenantProducer.sendTenantRefreshMessage();
  215 + }
  216 + });
  217 + }
  218 +
  219 + @Override
  220 + @Transactional(rollbackFor = Exception.class)
  221 + public void updateTenantRoleMenu(Long tenantId, Set<Long> menuIds) {
  222 + TenantUtils.execute(tenantId, () -> {
  223 + // 获得所有角色
  224 + List<RoleDO> roles = roleService.getRoles(null);
  225 + roles.forEach(role -> Assert.isTrue(tenantId.equals(role.getTenantId()), "角色({}/{}) 租户不匹配",
  226 + role.getId(), role.getTenantId(), tenantId)); // 兜底校验
  227 + // 重新分配每个角色的权限
  228 + roles.forEach(role -> {
  229 + // 如果是租户管理员,重新分配其权限为租户套餐的权限
  230 + if (Objects.equals(role.getCode(), RoleCodeEnum.TENANT_ADMIN.getCode())) {
  231 + permissionService.assignRoleMenu(role.getId(), menuIds);
  232 + log.info("[updateTenantRoleMenu][租户管理员({}/{}) 的权限修改为({})]", role.getId(), role.getTenantId(), menuIds);
  233 + return;
  234 + }
  235 + // 如果是其他角色,则去掉超过套餐的权限
  236 + Set<Long> roleMenuIds = permissionService.getRoleMenuIds(role.getId());
  237 + roleMenuIds = CollUtil.intersectionDistinct(roleMenuIds, menuIds);
  238 + permissionService.assignRoleMenu(role.getId(), roleMenuIds);
  239 + log.info("[updateTenantRoleMenu][角色({}/{}) 的权限修改为({})]", role.getId(), role.getTenantId(), roleMenuIds);
  240 + });
  241 + });
120 } 242 }
121 243
122 @Override 244 @Override
123 public void deleteTenant(Long id) { 245 public void deleteTenant(Long id) {
124 // 校验存在 246 // 校验存在
125 - this.validateTenantExists(id); 247 + validateTenantExists(id);
126 // 删除 248 // 删除
127 tenantMapper.deleteById(id); 249 tenantMapper.deleteById(id);
128 } 250 }
129 251
130 - private void validateTenantExists(Long id) {  
131 - if (tenantMapper.selectById(id) == null) { 252 + private TenantDO validateTenantExists(Long id) {
  253 + TenantDO tenant = tenantMapper.selectById(id);
  254 + if (tenant == null) {
132 throw exception(TENANT_NOT_EXISTS); 255 throw exception(TENANT_NOT_EXISTS);
133 } 256 }
  257 + return tenant;
134 } 258 }
135 259
136 @Override 260 @Override
@@ -163,4 +287,9 @@ public class TenantServiceImpl implements TenantService { @@ -163,4 +287,9 @@ public class TenantServiceImpl implements TenantService {
163 return tenantMapper.selectCountByPackageId(packageId); 287 return tenantMapper.selectCountByPackageId(packageId);
164 } 288 }
165 289
  290 + @Override
  291 + public List<TenantDO> getTenantListByPackageId(Long packageId) {
  292 + return tenantMapper.selectListByPackageId(packageId);
  293 + }
  294 +
166 } 295 }
yudao-module-system/yudao-module-system-impl/src/test/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceTest.java
@@ -243,7 +243,7 @@ public class MenuServiceTest extends BaseDbUnitTest { @@ -243,7 +243,7 @@ public class MenuServiceTest extends BaseDbUnitTest {
243 menuDO = createMenuDO(4L, MenuTypeEnum.MENU, "name", 0L, 2); 243 menuDO = createMenuDO(4L, MenuTypeEnum.MENU, "name", 0L, 2);
244 mockCacheMap.put(menuDO.getId(), menuDO); 244 mockCacheMap.put(menuDO.getId(), menuDO);
245 245
246 - List<MenuDO> menuDOS = sysMenuService.listMenusFromCache(Collections.singletonList(MenuTypeEnum.MENU.getType()), 246 + List<MenuDO> menuDOS = sysMenuService.getMenuListFromCache(Collections.singletonList(MenuTypeEnum.MENU.getType()),
247 Collections.singletonList(CommonStatusEnum.DISABLE.getStatus())); 247 Collections.singletonList(CommonStatusEnum.DISABLE.getStatus()));
248 assertEquals(menuDOS.size(), idMenuMap.size()); 248 assertEquals(menuDOS.size(), idMenuMap.size());
249 menuDOS.forEach(m -> assertPojoEquals(idMenuMap.get(m.getId()), m)); 249 menuDOS.forEach(m -> assertPojoEquals(idMenuMap.get(m.getId()), m));
@@ -270,7 +270,7 @@ public class MenuServiceTest extends BaseDbUnitTest { @@ -270,7 +270,7 @@ public class MenuServiceTest extends BaseDbUnitTest {
270 menuDO = createMenuDO(4L, MenuTypeEnum.MENU, "name", 0L, 2); 270 menuDO = createMenuDO(4L, MenuTypeEnum.MENU, "name", 0L, 2);
271 mockCacheMap.put(menuDO.getId(), menuDO); 271 mockCacheMap.put(menuDO.getId(), menuDO);
272 272
273 - List<MenuDO> menuDOS = sysMenuService.listMenusFromCache(Collections.singletonList(1L), 273 + List<MenuDO> menuDOS = sysMenuService.getMenuListFromCache(Collections.singletonList(1L),
274 Collections.singletonList(MenuTypeEnum.MENU.getType()), Collections.singletonList(1)); 274 Collections.singletonList(MenuTypeEnum.MENU.getType()), Collections.singletonList(1));
275 assertEquals(menuDOS.size(), idMenuMap.size()); 275 assertEquals(menuDOS.size(), idMenuMap.size());
276 menuDOS.forEach(menu -> assertPojoEquals(idMenuMap.get(menu.getId()), menu)); 276 menuDOS.forEach(menu -> assertPojoEquals(idMenuMap.get(menu.getId()), menu));
yudao-server/src/main/resources/application.yaml
@@ -79,8 +79,8 @@ yudao: @@ -79,8 +79,8 @@ yudao:
79 - cn.iocoder.yudao.module.tool.enums.ErrorCodeConstants 79 - cn.iocoder.yudao.module.tool.enums.ErrorCodeConstants
80 tenant: # 多租户相关配置项 80 tenant: # 多租户相关配置项
81 enable: true 81 enable: true
82 - ignore-urls: /admin-api/system/captcha/get-image, /admin-api/infra/file/get/*  
83 - ignore-tables: infra_config, infra_file, infra_job, infra_job_log, infra_job_log, system_tenant, system_tenant_package, system_dict_data, system_dict_type, system_error_code, system_menu, system_sms_channel, tool_codegen_column, tool_codegen_table, tool_test_demo, tables, columns 82 + ignore-urls: /admin-api/system/tenant/get-id-by-name, /admin-api/system/captcha/get-image, /admin-api/infra/file/get/*
  83 + ignore-tables: infra_config, infra_file, infra_job, infra_job_log, infra_job_log, system_tenant, system_tenant_package, system_dict_data, system_dict_type, system_error_code, system_menu, system_sms_channel, system_sms_template, tool_codegen_column, tool_codegen_table, tool_test_demo, tables, columns
84 sms-code: # 短信验证码相关的配置项 84 sms-code: # 短信验证码相关的配置项
85 expire-times: 10m 85 expire-times: 10m
86 send-frequency: 1m 86 send-frequency: 1m
yudao-ui-admin/src/views/system/tenantPackage/index.vue
@@ -200,6 +200,8 @@ export default { @@ -200,6 +200,8 @@ export default {
200 this.reset(); 200 this.reset();
201 this.open = true; 201 this.open = true;
202 this.title = "添加租户套餐"; 202 this.title = "添加租户套餐";
  203 + // 设置为非严格,继续使用半选中
  204 + this.menuCheckStrictly = false;
203 }, 205 },
204 /** 修改按钮操作 */ 206 /** 修改按钮操作 */
205 handleUpdate(row) { 207 handleUpdate(row) {
@@ -222,12 +224,6 @@ export default { @@ -222,12 +224,6 @@ export default {
222 /** 获得菜单 */ 224 /** 获得菜单 */
223 getMenus() { 225 getMenus() {
224 listSimpleMenus().then(response => { 226 listSimpleMenus().then(response => {
225 - // 移除 BUTTON 类型,暂支只需要发 DIR、MENU 类型  
226 - for (let i = response.data.length -1; i >= 0 ; i--) {  
227 - if (response.data[i].type === SystemMenuTypeEnum.BUTTON) {  
228 - response.data.splice(i, 1);  
229 - }  
230 - }  
231 // 处理 menuOptions 参数 227 // 处理 menuOptions 参数
232 this.menuOptions = []; 228 this.menuOptions = [];
233 // 只需要配置 229 // 只需要配置
更新日志.md
@@ -29,8 +29,9 @@ TODO @@ -29,8 +29,9 @@ TODO
29 * 【新增】后端 `yudao.tenant.enable` 配置项,前端 `VUE_APP_TENANT_ENABLE` 配置项,用于开关租户功能。 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/79311ecc71f0c6beabe0e5f84e1423ce745a5f09) 29 * 【新增】后端 `yudao.tenant.enable` 配置项,前端 `VUE_APP_TENANT_ENABLE` 配置项,用于开关租户功能。 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/79311ecc71f0c6beabe0e5f84e1423ce745a5f09)
30 * 【优化】调整默认所有表开启多租户的特性,可通过 `yudao.tenant.ignore-tables` 配置项进行忽略,替代原本默认不开启的策略 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/79311ecc71f0c6beabe0e5f84e1423ce745a5f09) 30 * 【优化】调整默认所有表开启多租户的特性,可通过 `yudao.tenant.ignore-tables` 配置项进行忽略,替代原本默认不开启的策略 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/79311ecc71f0c6beabe0e5f84e1423ce745a5f09)
31 * 【新增】通过 `yudao.tenant.ignore-urls` 配置忽略多租户的请求,例如说 ,例如说短信回调、支付回调等 Open API [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/79311ecc71f0c6beabe0e5f84e1423ce745a5f09) 31 * 【新增】通过 `yudao.tenant.ignore-urls` 配置忽略多租户的请求,例如说 ,例如说短信回调、支付回调等 Open API [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/79311ecc71f0c6beabe0e5f84e1423ce745a5f09)
  32 +* 【新增】新增 `@TenantIgnore` 注解,标记指定方法,忽略多租户的自动过滤,适合实现跨租户的逻辑 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/4d53944771c66b563da1e3d68d3ba43405af8a06)
32 * 【新增】租户套餐的管理,可配置每个租户的可使用的功能权限 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/6b6d676a6baa2dad16ae9bf03d5002209064c8cc) 33 * 【新增】租户套餐的管理,可配置每个租户的可使用的功能权限 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/6b6d676a6baa2dad16ae9bf03d5002209064c8cc)
33 -* 【优化】新建租户时,自动创建对应的管理员账号、角色等基础信息 []() 34 +* 【优化】新建租户时,自动创建对应的管理员账号、角色等基础信息 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/2598c033a95d4b61d5f5ab3da5f1414f25c510d6)
34 35
35 ### 🐞 Bug Fixes 36 ### 🐞 Bug Fixes
36 37