Commit e4be51b14adfeba6d31424a30976d8729d441b9e
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<RoleDO> { | @@ -41,7 +42,7 @@ public interface RoleMapper extends BaseMapperX<RoleDO> { | ||
| 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<TenantDO> { | @@ -43,7 +45,14 @@ public interface TenantMapper extends BaseMapperX<TenantDO> { | ||
| 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 |