diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java index 1dccd9cb24..6b25c79c7e 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java +++ b/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; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; +import com.google.common.collect.ImmutableMap; import java.util.*; import java.util.function.BinaryOperator; @@ -125,6 +126,15 @@ public class CollectionUtils { return from.stream().collect(Collectors.groupingBy(keyFunc, Collectors.mapping(valueFunc, Collectors.toSet()))); } + public static Map convertImmutableMap(Collection from, Function keyFunc) { + if (CollUtil.isEmpty(from)) { + return Collections.emptyMap(); + } + ImmutableMap.Builder builder = ImmutableMap.builder(); + from.forEach(item -> builder.put(keyFunc.apply(item), item)); + return builder.build(); + } + public static boolean containsAny(Collection source, Collection candidates) { return org.springframework.util.CollectionUtils.containsAny(source, candidates); } @@ -140,6 +150,15 @@ public class CollectionUtils { return from.stream().filter(predicate).findFirst().orElse(null); } + public static > V getMaxValue(List from, Function valueFunc) { + if (CollUtil.isEmpty(from)) { + return null; + } + assert from.size() > 0; // 断言,避免告警 + T t = from.stream().max(Comparator.comparing(valueFunc)).get(); + return valueFunc.apply(t); + } + public static void addIfNotNull(Collection coll, T item) { if (item == null) { return; diff --git a/yudao-module-pay/yudao-module-pay-impl/pom.xml b/yudao-module-pay/yudao-module-pay-impl/pom.xml index 33a3f93367..67ce903b1c 100644 --- a/yudao-module-pay/yudao-module-pay-impl/pom.xml +++ b/yudao-module-pay/yudao-module-pay-impl/pom.xml @@ -33,6 +33,10 @@ cn.iocoder.boot yudao-spring-boot-starter-biz-pay + + cn.iocoder.boot + yudao-spring-boot-starter-biz-tenant + diff --git a/yudao-module-pay/yudao-module-pay-impl/src/main/java/cn/iocoder/yudao/module/pay/service/merchant/PayChannelServiceImpl.java b/yudao-module-pay/yudao-module-pay-impl/src/main/java/cn/iocoder/yudao/module/pay/service/merchant/PayChannelServiceImpl.java index 68b6ff10db..d3410a2cbd 100644 --- a/yudao-module-pay/yudao-module-pay-impl/src/main/java/cn/iocoder/yudao/module/pay/service/merchant/PayChannelServiceImpl.java +++ b/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; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelCreateReqVO; import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelExportReqVO; import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelPageReqVO; import cn.iocoder.yudao.module.pay.controller.admin.merchant.vo.channel.PayChannelUpdateReqVO; import cn.iocoder.yudao.module.pay.convert.channel.PayChannelConvert; -import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayChannelDO; import cn.iocoder.yudao.module.pay.dal.mysql.merchant.PayChannelMapper; import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants; @@ -27,12 +28,12 @@ import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.validation.Validator; import java.util.Collection; -import java.util.Comparator; import java.util.Date; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_EXIST_SAME_CHANNEL_ERROR; +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_EXISTS; /** * 支付渠道 Service 实现类 @@ -66,9 +67,10 @@ public class PayChannelServiceImpl implements PayChannelService { @Override @PostConstruct + @TenantIgnore // 忽略自动化租户,全局初始化本地缓存 public void initPayClients() { // 获取支付渠道,如果有更新 - List payChannels = this.loadPayChannelIfUpdate(maxUpdateTime); + List payChannels = loadPayChannelIfUpdate(maxUpdateTime); if (CollUtil.isEmpty(payChannels)) { return; } @@ -78,8 +80,7 @@ public class PayChannelServiceImpl implements PayChannelService { payChannel.getCode(), payChannel.getConfig())); // 写入缓存 - assert payChannels.size() > 0; // 断言,避免告警 - maxUpdateTime = payChannels.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); + maxUpdateTime = CollectionUtils.getMaxValue(payChannels, PayChannelDO::getUpdateTime); log.info("[initPayClients][初始化 PayChannel 数量为 {}]", payChannels.size()); } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java index 8c45215a4e..fe31c20b4c 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java +++ b/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 { // 获得角色列表 List roleList = roleService.getRolesFromCache(getLoginUserRoleIds()); // 获得菜单列表 - List menuList = permissionService.getRoleMenusFromCache( + List menuList = permissionService.getRoleMenuListFromCache( getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它 SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType(), MenuTypeEnum.BUTTON.getType()), SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); @@ -84,7 +84,7 @@ public class AuthController { @ApiOperation("获得登录用户的菜单列表") public CommonResult> getMenus() { // 获得用户拥有的菜单列表 - List menuList = permissionService.getRoleMenusFromCache( + List menuList = permissionService.getRoleMenuListFromCache( getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它 SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型 SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的 diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/MenuController.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/MenuController.java index 8678da529c..7d4364dcfb 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/MenuController.java +++ b/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 { } @GetMapping("/list") - @ApiOperation("获取菜单列表") + @ApiOperation(value = "获取菜单列表", notes = "用于【菜单管理】界面") @PreAuthorize("@ss.hasPermission('system:menu:query')") public CommonResult> getMenus(MenuListReqVO reqVO) { List list = menuService.getMenus(reqVO); @@ -64,13 +64,13 @@ public class MenuController { } @GetMapping("/list-all-simple") - @ApiOperation(value = "获取菜单精简信息列表", notes = "只包含被开启的菜单,主要用于前端的下拉选项") + @ApiOperation(value = "获取菜单精简信息列表", notes = "只包含被开启的菜单,用于【角色分配菜单】功能的选项") public CommonResult> getSimpleMenus() { // 获得菜单列表,只要开启状态的 MenuListReqVO reqVO = new MenuListReqVO(); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); List list = menuService.getMenus(reqVO); - // 排序后,返回个诶前端 + // 排序后,返回给前端 list.sort(Comparator.comparing(MenuDO::getSort)); return success(MenuConvert.INSTANCE.convertList02(list)); } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java index de26fbf086..e325cc4208 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java +++ b/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 { @GetMapping("/list-role-resources") // @RequiresPermissions("system:permission:assign-role-menu") public CommonResult> listRoleMenus(Long roleId) { - return success(permissionService.listRoleMenuIds(roleId)); + return success(permissionService.getRoleMenuIds(roleId)); } @PostMapping("/assign-role-menu") diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageBaseVO.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageBaseVO.java index aa42b5e0cf..36c838366c 100755 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/vo/packages/TenantPackageBaseVO.java +++ b/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; import lombok.Data; import javax.validation.constraints.NotNull; -import java.util.List; +import java.util.Set; /** * 租户套餐 Base VO,提供给添加、修改、详细的子 VO 使用 @@ -26,6 +26,6 @@ public class TenantPackageBaseVO { @ApiModelProperty(value = "关联的菜单编号", required = true) @NotNull(message = "关联的菜单编号不能为空") - private List menuIds; + private Set menuIds; } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleDO.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleDO.java index 2a175a8662..ce58219b5d 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleDO.java +++ b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleDO.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.system.dal.dataobject.permission; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -21,7 +21,7 @@ import java.util.Set; @TableName(value = "system_role", autoResultMap = true) @Data @EqualsAndHashCode(callSuper = true) -public class RoleDO extends BaseDO { +public class RoleDO extends TenantBaseDO { /** * 角色ID diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleMenuDO.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleMenuDO.java index 6b7778bf07..7815e811cf 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleMenuDO.java +++ b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/permission/RoleMenuDO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.permission; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -14,7 +15,7 @@ import lombok.EqualsAndHashCode; @TableName("system_role_menu") @Data @EqualsAndHashCode(callSuper = true) -public class RoleMenuDO extends BaseDO { +public class RoleMenuDO extends TenantBaseDO { /** * 自增主键 diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java index 3a0f2c23f0..1de536caf3 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/permission/RoleMapper.java +++ b/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; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO; @@ -41,7 +42,7 @@ public interface RoleMapper extends BaseMapperX { } default List selectListByStatus(@Nullable Collection statuses) { - return selectList(new QueryWrapperX().in("status", statuses)); + return selectList(new LambdaQueryWrapperX().inIfPresent(RoleDO::getStatus, statuses)); } @InterceptorIgnore(tenantLine = "true") // 该方法忽略多租户。原因:该方法被异步 task 调用,此时获取不到租户编号 diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java index 6eb6149e5d..f7cb22c0c4 100755 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java +++ b/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; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; +import java.util.Date; import java.util.List; /** @@ -43,7 +45,14 @@ public interface TenantMapper extends BaseMapperX { } default Integer selectCountByPackageId(Long packageId) { - return selectCount("package_id", packageId); + return selectCount(TenantDO::getPackageId, packageId); } + default List selectListByPackageId(Long packageId) { + return selectList(TenantDO::getPackageId, packageId); + } + + @Select("SELECT id FROM system_tenant WHERE update_time > #{maxUpdateTime} LIMIT 1") + Long selectExistsByUpdateTimeAfter(Date maxUpdateTime); + } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/enums/permission/RoleCodeEnum.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/enums/permission/RoleCodeEnum.java index 44487a4d63..b501e26857 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/enums/permission/RoleCodeEnum.java +++ b/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; @AllArgsConstructor public enum RoleCodeEnum { - ADMIN("admin"), // 超级管理员 + SUPER_ADMIN("super_admin", "超级管理员"), + TENANT_ADMIN("tenant_admin", "租户管理员"), ; /** * 角色编码 */ - private final String key; + private final String code; + /** + * 名字 + */ + private final String name; } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsSendConsumer.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsSendConsumer.java index 495c06a9be..3b4ff216b5 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/sms/SmsSendConsumer.java +++ b/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; * 针对 {@link SmsSendMessage} 的消费者 * * @author zzf - * @date 2021/3/9 16:35 */ @Component @Slf4j diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/tenant/TenantRefreshConsumer.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/tenant/TenantRefreshConsumer.java new file mode 100644 index 0000000000..5bc008ace3 --- /dev/null +++ b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/tenant/TenantRefreshConsumer.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.system.mq.consumer.tenant; + +import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener; +import cn.iocoder.yudao.module.system.mq.message.tenant.TenantRefreshMessage; +import cn.iocoder.yudao.module.system.service.tenant.TenantService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 针对 {@link cn.iocoder.yudao.module.system.mq.message.tenant.TenantRefreshMessage} 的消费者 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class TenantRefreshConsumer extends AbstractChannelMessageListener { + + @Resource + private TenantService tenantService; + + @Override + public void onMessage(TenantRefreshMessage message) { + log.info("[onMessage][收到 Tenant 刷新消息]"); + tenantService.initLocalCache(); + } + +} diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/message/tenant/TenantRefreshMessage.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/message/tenant/TenantRefreshMessage.java new file mode 100644 index 0000000000..19092a4bb4 --- /dev/null +++ b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/message/tenant/TenantRefreshMessage.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.system.mq.message.tenant; + +import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 租户数据刷新 Message + * + * @author 芋道源码 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class TenantRefreshMessage extends AbstractChannelMessage { + + @Override + public String getChannel() { + return "system.tenant.refresh"; + } + +} diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/producer/tenant/TenantProducer.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/producer/tenant/TenantProducer.java new file mode 100644 index 0000000000..eaa9f658d8 --- /dev/null +++ b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/mq/producer/tenant/TenantProducer.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.system.mq.producer.tenant; + +import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; +import cn.iocoder.yudao.module.system.mq.message.permission.RoleRefreshMessage; +import cn.iocoder.yudao.module.system.mq.message.tenant.TenantRefreshMessage; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * Tenant 租户相关消息的 Producer + * + * @author 芋道源码 + */ +@Component +public class TenantProducer { + + @Resource + private RedisMQTemplate redisMQTemplate; + + /** + * 发送 {@link RoleRefreshMessage} 消息 + */ + public void sendTenantRefreshMessage() { + TenantRefreshMessage message = new TenantRefreshMessage(); + redisMQTemplate.send(message); + } + +} diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java index 6001f48c10..c8f57291df 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java +++ b/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; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO; import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO; @@ -73,9 +73,10 @@ public class DeptServiceImpl implements DeptService { @Override @PostConstruct + @TenantIgnore // 初始化缓存,无需租户过滤 public synchronized void initLocalCache() { // 获取部门列表,如果有更新 - List deptList = this.loadDeptIfUpdate(maxUpdateTime); + List deptList = loadDeptIfUpdate(maxUpdateTime); if (CollUtil.isEmpty(deptList)) { return; } @@ -90,8 +91,7 @@ public class DeptServiceImpl implements DeptService { // 设置缓存 deptCache = builder.build(); parentDeptCache = parentBuilder.build(); - assert deptList.size() > 0; // 断言,避免告警 - maxUpdateTime = deptList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); + maxUpdateTime = CollectionUtils.getMaxValue(deptList, DeptDO::getUpdateTime); log.info("[initLocalCache][初始化 Dept 数量为 {}]", deptList.size()); } @@ -107,7 +107,7 @@ public class DeptServiceImpl implements DeptService { * @param maxUpdateTime 当前部门的最大更新时间 * @return 部门列表 */ - private List loadDeptIfUpdate(Date maxUpdateTime) { + protected List loadDeptIfUpdate(Date maxUpdateTime) { // 第一步,判断是否要更新。 if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 log.info("[loadMenuIfUpdate][首次加载全量部门]"); @@ -118,7 +118,7 @@ public class DeptServiceImpl implements DeptService { log.info("[loadMenuIfUpdate][增量加载全量部门]"); } // 第二步,如果有更新,则从数据库加载所有部门 - return deptMapper.selectListIgnoreTenant(); + return deptMapper.selectList(); } @Override diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImpl.java index 4832507cd7..f80fe6503b 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImpl.java +++ b/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; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO; @@ -99,8 +99,7 @@ public class DictDataServiceImpl implements DictDataService { }); labelDictDataCache = labelDictDataBuilder.build(); valueDictDataCache = valueDictDataBuilder.build(); - assert dataList.size() > 0; // 断言,避免告警 - maxUpdateTime = dataList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); + maxUpdateTime = CollectionUtils.getMaxValue(dataList, DictDataDO::getUpdateTime); log.info("[initLocalCache][缓存字典数据,数量为:{}]", dataList.size()); } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuService.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuService.java index 405f390e4b..0ebf8c2f91 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuService.java +++ b/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 { * @param menusStatuses 菜单状态数组 * @return 菜单列表 */ - List listMenusFromCache(Collection menuTypes, Collection menusStatuses); + List getMenuListFromCache(Collection menuTypes, Collection menusStatuses); /** * 获得指定编号的菜单数组,从缓存中 @@ -78,8 +78,8 @@ public interface MenuService { * @param menusStatuses 菜单状态数组 * @return 菜单数组 */ - List listMenusFromCache(Collection menuIds, Collection menuTypes, - Collection menusStatuses); + List getMenuListFromCache(Collection menuIds, Collection menuTypes, + Collection menusStatuses); /** * 获得权限对应的菜单数组 diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java index 40d8c13c58..b3e8b4f3b6 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImpl.java +++ b/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; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuListReqVO; 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; import cn.iocoder.yudao.module.system.enums.permission.MenuIdEnum; import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum; import cn.iocoder.yudao.module.system.mq.producer.permission.MenuProducer; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; @@ -95,8 +94,7 @@ public class MenuServiceImpl implements MenuService { }); menuCache = menuCacheBuilder.build(); permissionMenuCache = permMenuCacheBuilder.build(); - assert menuList.size() > 0; // 断言,避免告警 - maxUpdateTime = menuList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); + maxUpdateTime = CollectionUtils.getMaxValue(menuList, MenuDO::getUpdateTime); log.info("[initLocalCache][缓存菜单,数量为:{}]", menuList.size()); } @@ -201,7 +199,7 @@ public class MenuServiceImpl implements MenuService { } @Override - public List listMenusFromCache(Collection menuTypes, Collection menusStatuses) { + public List getMenuListFromCache(Collection menuTypes, Collection menusStatuses) { // 任一一个参数为空,则返回空 if (CollectionUtils.isAnyEmpty(menuTypes, menusStatuses)) { return Collections.emptyList(); @@ -213,8 +211,8 @@ public class MenuServiceImpl implements MenuService { } @Override - public List listMenusFromCache(Collection menuIds, Collection menuTypes, - Collection menusStatuses) { + public List getMenuListFromCache(Collection menuIds, Collection menuTypes, + Collection menusStatuses) { // 任一一个参数为空,则返回空 if (CollectionUtils.isAnyEmpty(menuIds, menuTypes, menusStatuses)) { return Collections.emptyList(); diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionService.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionService.java index 153eb71ac7..11fe1ab887 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionService.java +++ b/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 * @param menusStatuses 菜单状态数组 * @return 菜单列表 */ - List getRoleMenusFromCache(Collection roleIds, Collection menuTypes, - Collection menusStatuses); + List getRoleMenuListFromCache(Collection roleIds, Collection menuTypes, + Collection menusStatuses); /** * 获得用户拥有的角色编号集合 @@ -51,7 +51,7 @@ public interface PermissionService extends SecurityPermissionFrameworkService, D * @param roleId 角色编号 * @return 菜单编号集合 */ - Set listRoleMenuIds(Long roleId); + Set getRoleMenuIds(Long roleId); /** * 设置角色菜单 diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java index f07f61719d..9033fe9351 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java +++ b/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; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; +import cn.iocoder.yudao.framework.security.core.LoginUser; +import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; @@ -12,13 +20,6 @@ import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper; import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper; import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer; import cn.iocoder.yudao.module.system.service.dept.DeptService; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; -import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum; -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; @@ -94,10 +95,10 @@ public class PermissionServiceImpl implements PermissionService { */ @Override @PostConstruct + @TenantIgnore // 初始化缓存,无需租户过滤 public void initLocalCache() { - Date now = new Date(); // 获取角色与菜单的关联列表,如果有更新 - List roleMenuList = this.loadRoleMenuIfUpdate(maxUpdateTime); + List roleMenuList = loadRoleMenuIfUpdate(maxUpdateTime); if (CollUtil.isEmpty(roleMenuList)) { return; } @@ -111,8 +112,7 @@ public class PermissionServiceImpl implements PermissionService { }); roleMenuCache = roleMenuCacheBuilder.build(); menuRoleCache = menuRoleCacheBuilder.build(); - assert roleMenuList.size() > 0; // 断言,避免告警 - maxUpdateTime = now; + maxUpdateTime = CollectionUtils.getMaxValue(roleMenuList, RoleMenuDO::getUpdateTime); log.info("[initLocalCache][初始化角色与菜单的关联数量为 {}]", roleMenuList.size()); } @@ -128,7 +128,7 @@ public class PermissionServiceImpl implements PermissionService { * @param maxUpdateTime 当前角色与菜单的关联的最大更新时间 * @return 角色与菜单的关联列表 */ - private List loadRoleMenuIfUpdate(Date maxUpdateTime) { + protected List loadRoleMenuIfUpdate(Date maxUpdateTime) { // 第一步,判断是否要更新。 if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 log.info("[loadRoleMenuIfUpdate][首次加载全量角色与菜单的关联]"); @@ -143,21 +143,22 @@ public class PermissionServiceImpl implements PermissionService { } @Override - public List getRoleMenusFromCache(Collection roleIds, Collection menuTypes, - Collection menusStatuses) { + public List getRoleMenuListFromCache(Collection roleIds, Collection menuTypes, + Collection menusStatuses) { // 任一一个参数为空时,不返回任何菜单 if (CollectionUtils.isAnyEmpty(roleIds, menuTypes, menusStatuses)) { return Collections.emptyList(); } - // 判断角色是否包含管理员 + + // 判断角色是否包含超级管理员。如果是超级管理员,获取到全部 List roleList = roleService.getRolesFromCache(roleIds); - boolean hasAdmin = roleService.hasAnyAdmin(roleList); - // 获得角色拥有的菜单关联 - if (hasAdmin) { // 管理员,获取到全部 - return menuService.listMenusFromCache(menuTypes, menusStatuses); + if (roleService.hasAnySuperAdmin(roleList)) { + return menuService.getMenuListFromCache(menuTypes, menusStatuses); } + + // 获得角色拥有的菜单关联 List menuIds = MapUtils.getList(roleMenuCache, roleIds); - return menuService.listMenusFromCache(menuIds, menuTypes, menusStatuses); + return menuService.getMenuListFromCache(menuIds, menuTypes, menusStatuses); } @Override @@ -174,10 +175,10 @@ public class PermissionServiceImpl implements PermissionService { } @Override - public Set listRoleMenuIds(Long roleId) { + public Set getRoleMenuIds(Long roleId) { // 如果是管理员的情况下,获取全部菜单编号 RoleDO role = roleService.getRole(roleId); - if (roleService.hasAnyAdmin(Collections.singletonList(role))) { + if (roleService.hasAnySuperAdmin(Collections.singletonList(role))) { return CollectionUtils.convertSet(menuService.getMenus(), MenuDO::getId); } // 如果是非管理员的情况下,获得拥有的菜单编号 @@ -302,7 +303,7 @@ public class PermissionServiceImpl implements PermissionService { return false; } // 判断是否是超管。如果是,当然符合条件 - if (roleService.hasAnyAdmin(roleIds)) { + if (roleService.hasAnySuperAdmin(roleIds)) { return true; } @@ -337,7 +338,7 @@ public class PermissionServiceImpl implements PermissionService { return false; } // 判断是否是超管。如果是,当然符合条件 - if (roleService.hasAnyAdmin(roleIds)) { + if (roleService.hasAnySuperAdmin(roleIds)) { return true; } Set userRoles = CollectionUtils.convertSet(roleService.getRolesFromCache(roleIds), diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleService.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleService.java index 6214ef1c3e..a060958449 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleService.java +++ b/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 { List getRolesFromCache(Collection ids); /** - * 判断角色数组中,是否有管理员 + * 判断角色数组中,是否有超级管理员 * * @param roleList 角色数组 * @return 是否有管理员 */ - boolean hasAnyAdmin(Collection roleList); + boolean hasAnySuperAdmin(Collection roleList); /** * 判断角色编号数组中,是否有管理员 @@ -103,8 +103,8 @@ public interface RoleService { * @param ids 角色编号数组 * @return 是否有管理员 */ - default boolean hasAnyAdmin(Set ids) { - return hasAnyAdmin(getRolesFromCache(ids)); + default boolean hasAnySuperAdmin(Set ids) { + return hasAnySuperAdmin(getRolesFromCache(ids)); } /** diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java index ea3cf0f52b..d27ba900be 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java +++ b/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; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO; 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; import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; import cn.iocoder.yudao.module.system.mq.producer.permission.RoleProducer; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableMap; import lombok.extern.slf4j.Slf4j; import org.springframework.lang.Nullable; import org.springframework.scheduling.annotation.Scheduled; @@ -78,19 +77,17 @@ public class RoleServiceImpl implements RoleService { */ @Override @PostConstruct + @TenantIgnore // 忽略自动多租户,全局初始化缓存 public void initLocalCache() { // 获取角色列表,如果有更新 - List roleList = this.loadRoleIfUpdate(maxUpdateTime); + List roleList = loadRoleIfUpdate(maxUpdateTime); if (CollUtil.isEmpty(roleList)) { return; } // 写入缓存 - ImmutableMap.Builder builder = ImmutableMap.builder(); - roleList.forEach(sysRoleDO -> builder.put(sysRoleDO.getId(), sysRoleDO)); - roleCache = builder.build(); - assert roleList.size() > 0; // 断言,避免告警 - maxUpdateTime = roleList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); + roleCache = CollectionUtils.convertMap(roleList, RoleDO::getId); + maxUpdateTime = CollectionUtils.getMaxValue(roleList, RoleDO::getUpdateTime); log.info("[initLocalCache][初始化 Role 数量为 {}]", roleList.size()); } @@ -216,11 +213,11 @@ public class RoleServiceImpl implements RoleService { } @Override - public boolean hasAnyAdmin(Collection roleList) { + public boolean hasAnySuperAdmin(Collection roleList) { if (CollectionUtil.isEmpty(roleList)) { return false; } - return roleList.stream().anyMatch(roleDO -> RoleCodeEnum.ADMIN.getKey().equals(roleDO.getCode())); + return roleList.stream().anyMatch(roleDO -> RoleCodeEnum.SUPER_ADMIN.getCode().equals(roleDO.getCode())); } @Override diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceImpl.java index f1fd44a901..8ccc8bc5dc 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceImpl.java +++ b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceImpl.java @@ -1,6 +1,10 @@ package cn.iocoder.yudao.module.system.service.sms; import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.sms.vo.channel.SmsChannelPageReqVO; 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; import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper; import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; -import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @@ -19,13 +19,12 @@ import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.util.Collection; -import java.util.Comparator; import java.util.Date; import java.util.List; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; /** * 短信渠道Service实现类 @@ -74,8 +73,7 @@ public class SmsChannelServiceImpl implements SmsChannelService { propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties)); // 写入缓存 - assert smsChannels.size() > 0; // 断言,避免告警 - maxUpdateTime = smsChannels.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); + maxUpdateTime = CollectionUtils.getMaxValue(smsChannels, SmsChannelDO::getUpdateTime); log.info("[initSmsClients][初始化 SmsChannel 数量为 {}]", smsChannels.size()); } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java index ce8e71435d..a829b3408e 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java +++ b/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; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateUpdateReqVO; import cn.iocoder.yudao.module.system.convert.sms.SmsTemplateConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsTemplateMapper; import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer; -import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.sms.core.client.SmsClient; -import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableMap; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @@ -31,8 +30,8 @@ import javax.annotation.Resource; import java.util.*; import java.util.regex.Pattern; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; /** * 短信模板 Service 实现类 @@ -89,11 +88,8 @@ public class SmsTemplateServiceImpl implements SmsTemplateService { } // 写入缓存 - ImmutableMap.Builder builder = ImmutableMap.builder(); - smsTemplateList.forEach(sysSmsTemplateDO -> builder.put(sysSmsTemplateDO.getCode(), sysSmsTemplateDO)); - smsTemplateCache = builder.build(); - assert smsTemplateList.size() > 0; // 断言,避免告警 - maxUpdateTime = smsTemplateList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); + smsTemplateCache = CollectionUtils.convertMap(smsTemplateList, SmsTemplateDO::getCode); + maxUpdateTime = CollectionUtils.getMaxValue(smsTemplateList, SmsTemplateDO::getUpdateTime); log.info("[initLocalCache][初始化 SmsTemplate 数量为 {}]", smsTemplateList.size()); } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImpl.java index 54b1a1eaaf..969d4c03e7 100755 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImpl.java +++ b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantPackageServiceImpl.java @@ -1,15 +1,18 @@ package cn.iocoder.yudao.module.system.service.tenant; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackageCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackagePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.packages.TenantPackageUpdateReqVO; import cn.iocoder.yudao.module.system.convert.tenant.TenantPackageConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantPackageMapper; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; @@ -45,12 +48,18 @@ public class TenantPackageServiceImpl implements TenantPackageService { } @Override + @Transactional(rollbackFor = Exception.class) public void updateTenantPackage(TenantPackageUpdateReqVO updateReqVO) { // 校验存在 - this.validateTenantPackageExists(updateReqVO.getId()); + TenantPackageDO tenantPackage = validateTenantPackageExists(updateReqVO.getId()); // 更新 TenantPackageDO updateObj = TenantPackageConvert.INSTANCE.convert(updateReqVO); tenantPackageMapper.updateById(updateObj); + // 如果菜单发生变化,则修改每个租户的菜单 + if (!CollUtil.isEqualList(tenantPackage.getMenuIds(), updateReqVO.getMenuIds())) { + List tenants = tenantService.getTenantListByPackageId(tenantPackage.getId()); + tenants.forEach(tenant -> tenantService.updateTenantRoleMenu(tenant.getId(), updateReqVO.getMenuIds())); + } } @Override @@ -63,10 +72,12 @@ public class TenantPackageServiceImpl implements TenantPackageService { tenantPackageMapper.deleteById(id); } - private void validateTenantPackageExists(Long id) { - if (tenantPackageMapper.selectById(id) == null) { + private TenantPackageDO validateTenantPackageExists(Long id) { + TenantPackageDO tenantPackage = tenantPackageMapper.selectById(id); + if (tenantPackage == null) { throw exception(TENANT_PACKAGE_NOT_EXISTS); } + return tenantPackage; } private void validateTenantUsed(Long id) { diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java index 7ad6ee5688..6560bc1575 100755 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java +++ b/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; import javax.validation.Valid; import java.util.Collection; import java.util.List; +import java.util.Set; /** * 租户 Service 接口 @@ -19,6 +20,11 @@ import java.util.List; */ public interface TenantService extends TenantFrameworkService { + /** + * 初始化租户的本地缓存 + */ + void initLocalCache(); + /** * 创建租户 * @@ -34,6 +40,14 @@ public interface TenantService extends TenantFrameworkService { */ void updateTenant(@Valid TenantUpdateReqVO updateReqVO); + /** + * 更新租户的角色菜单 + * + * @param tenantId 租户编号 + * @param menuIds 菜单编号数组 + */ + void updateTenantRoleMenu(Long tenantId, Set menuIds); + /** * 删除租户 * @@ -89,4 +103,12 @@ public interface TenantService extends TenantFrameworkService { */ Integer getTenantCountByPackageId(Long packageId); + /** + * 获得使用指定套餐的租户数组 + * + * @param packageId 租户套餐编号 + * @return 租户数组 + */ + List getTenantListByPackageId(Long packageId); + } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java index b43c2a6544..c35697ee75 100755 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java +++ b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java @@ -1,5 +1,8 @@ package cn.iocoder.yudao.module.system.service.tenant; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; 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 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantUpdateReqVO; import cn.iocoder.yudao.module.system.convert.tenant.TenantConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper; import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; +import cn.iocoder.yudao.module.system.mq.producer.tenant.TenantProducer; import cn.iocoder.yudao.module.system.service.permission.PermissionService; import cn.iocoder.yudao.module.system.service.permission.RoleService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.validation.annotation.Validated; +import javax.annotation.PostConstruct; import javax.annotation.Resource; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; @@ -37,8 +46,27 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; */ @Service @Validated +@Slf4j public class TenantServiceImpl implements TenantService { + /** + * 定时执行 {@link #schedulePeriodicRefresh()} 的周期 + * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高 + */ + private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; + + /** + * 角色缓存 + * key:角色编号 {@link RoleDO#getId()} + * + * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 + */ + private volatile Map tenantCache; + /** + * 缓存角色的最大更新时间,用于后续的增量轮询,判断是否有更新 + */ + private volatile Date maxUpdateTime; + @Resource private TenantMapper tenantMapper; @@ -51,15 +79,61 @@ public class TenantServiceImpl implements TenantService { @Resource private PermissionService permissionService; + @Resource + private TenantProducer tenantProducer; + + /** + * 初始化 {@link #tenantCache} 缓存 + */ + @Override + @PostConstruct + public void initLocalCache() { + // 获取租户列表,如果有更新 + List tenantList = loadTenantIfUpdate(maxUpdateTime); + if (CollUtil.isEmpty(tenantList)) { + return; + } + + // 写入缓存 + tenantCache = CollectionUtils.convertImmutableMap(tenantList, TenantDO::getId); + maxUpdateTime = CollectionUtils.getMaxValue(tenantList, TenantDO::getUpdateTime); + log.info("[initLocalCache][初始化 Tenant 数量为 {}]", tenantList.size()); + } + + @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) + public void schedulePeriodicRefresh() { + initLocalCache(); + } + + /** + * 如果租户发生变化,从数据库中获取最新的全量租户。 + * 如果未发生变化,则返回空 + * + * @param maxUpdateTime 当前租户的最大更新时间 + * @return 租户列表 + */ + private List loadTenantIfUpdate(Date maxUpdateTime) { + // 第一步,判断是否要更新。 + if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 + log.info("[loadTenantIfUpdate][首次加载全量租户]"); + } else { // 判断数据库中是否有更新的租户 + if (tenantMapper.selectExistsByUpdateTimeAfter(maxUpdateTime) == null) { + return null; + } + log.info("[loadTenantIfUpdate][增量加载全量租户]"); + } + // 第二步,如果有更新,则从数据库加载所有租户 + return tenantMapper.selectList(); + } + @Override public List getTenantIds() { - List tenants = tenantMapper.selectList(); - return CollectionUtils.convertList(tenants, TenantDO::getId); + return new ArrayList<>(tenantCache.keySet()); } @Override public void validTenant(Long id) { - TenantDO tenant = tenantMapper.selectById(id); + TenantDO tenant = tenantCache.get(id); if (tenant == null) { throw exception(TENANT_NOT_EXISTS); } @@ -75,7 +149,7 @@ public class TenantServiceImpl implements TenantService { @Transactional(rollbackFor = Exception.class) public Long createTenant(TenantCreateReqVO createReqVO) { // 校验套餐被禁用 - tenantPackageService.validTenantPackage(createReqVO.getPackageId()); + TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(createReqVO.getPackageId()); // 创建租户 TenantDO tenant = TenantConvert.INSTANCE.convert(createReqVO); @@ -83,13 +157,19 @@ public class TenantServiceImpl implements TenantService { TenantUtils.execute(tenant.getId(), () -> { // 创建角色 - Long roleId = createRole(); + Long roleId = createRole(tenantPackage); // 创建用户,并分配角色 Long userId = createUser(roleId, createReqVO); // 修改租户的管理员 tenantMapper.updateById(new TenantDO().setId(tenant.getId()).setContactUserId(userId)); }); - // 返回 + // 发送刷新消息 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override + public void afterCommit() { + tenantProducer.sendTenantRefreshMessage(); + } + }); return tenant.getId(); } @@ -101,36 +181,80 @@ public class TenantServiceImpl implements TenantService { return userId; } - private Long createRole() { + private Long createRole(TenantPackageDO tenantPackage) { + // 创建角色 RoleCreateReqVO reqVO = new RoleCreateReqVO(); - reqVO.setName(RoleCodeEnum.ADMIN.name()).setCode(RoleCodeEnum.ADMIN.getKey()).setSort(0); - return roleService.createRole(reqVO, RoleTypeEnum.SYSTEM.getType()); + reqVO.setName(RoleCodeEnum.TENANT_ADMIN.getName()).setCode(RoleCodeEnum.TENANT_ADMIN.getCode()) + .setSort(0).setRemark("系统自动生成"); + Long roleId = roleService.createRole(reqVO, RoleTypeEnum.SYSTEM.getType()); + // 分配权限 + permissionService.assignRoleMenu(roleId, tenantPackage.getMenuIds()); + return roleId; } @Override + @Transactional(rollbackFor = Exception.class) public void updateTenant(TenantUpdateReqVO updateReqVO) { // 校验存在 - this.validateTenantExists(updateReqVO.getId()); + TenantDO tenant = validateTenantExists(updateReqVO.getId()); // 校验套餐被禁用 - tenantPackageService.validTenantPackage(updateReqVO.getPackageId()); + TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(updateReqVO.getPackageId()); - // 更新 + // 更新租户 TenantDO updateObj = TenantConvert.INSTANCE.convert(updateReqVO); tenantMapper.updateById(updateObj); + // 如果套餐发生变化,则修改其角色的权限 + if (ObjectUtil.notEqual(tenant.getPackageId(), updateReqVO.getPackageId())) { + updateTenantRoleMenu(tenant.getId(), tenantPackage.getMenuIds()); + } + // 发送刷新消息 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override + public void afterCommit() { + tenantProducer.sendTenantRefreshMessage(); + } + }); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateTenantRoleMenu(Long tenantId, Set menuIds) { + TenantUtils.execute(tenantId, () -> { + // 获得所有角色 + List roles = roleService.getRoles(null); + roles.forEach(role -> Assert.isTrue(tenantId.equals(role.getTenantId()), "角色({}/{}) 租户不匹配", + role.getId(), role.getTenantId(), tenantId)); // 兜底校验 + // 重新分配每个角色的权限 + roles.forEach(role -> { + // 如果是租户管理员,重新分配其权限为租户套餐的权限 + if (Objects.equals(role.getCode(), RoleCodeEnum.TENANT_ADMIN.getCode())) { + permissionService.assignRoleMenu(role.getId(), menuIds); + log.info("[updateTenantRoleMenu][租户管理员({}/{}) 的权限修改为({})]", role.getId(), role.getTenantId(), menuIds); + return; + } + // 如果是其他角色,则去掉超过套餐的权限 + Set roleMenuIds = permissionService.getRoleMenuIds(role.getId()); + roleMenuIds = CollUtil.intersectionDistinct(roleMenuIds, menuIds); + permissionService.assignRoleMenu(role.getId(), roleMenuIds); + log.info("[updateTenantRoleMenu][角色({}/{}) 的权限修改为({})]", role.getId(), role.getTenantId(), roleMenuIds); + }); + }); } @Override public void deleteTenant(Long id) { // 校验存在 - this.validateTenantExists(id); + validateTenantExists(id); // 删除 tenantMapper.deleteById(id); } - private void validateTenantExists(Long id) { - if (tenantMapper.selectById(id) == null) { + private TenantDO validateTenantExists(Long id) { + TenantDO tenant = tenantMapper.selectById(id); + if (tenant == null) { throw exception(TENANT_NOT_EXISTS); } + return tenant; } @Override @@ -163,4 +287,9 @@ public class TenantServiceImpl implements TenantService { return tenantMapper.selectCountByPackageId(packageId); } + @Override + public List getTenantListByPackageId(Long packageId) { + return tenantMapper.selectListByPackageId(packageId); + } + } diff --git a/yudao-module-system/yudao-module-system-impl/src/test/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceTest.java b/yudao-module-system/yudao-module-system-impl/src/test/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceTest.java index 5c777eda7d..5bb144af74 100644 --- a/yudao-module-system/yudao-module-system-impl/src/test/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceTest.java +++ b/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 { menuDO = createMenuDO(4L, MenuTypeEnum.MENU, "name", 0L, 2); mockCacheMap.put(menuDO.getId(), menuDO); - List menuDOS = sysMenuService.listMenusFromCache(Collections.singletonList(MenuTypeEnum.MENU.getType()), + List menuDOS = sysMenuService.getMenuListFromCache(Collections.singletonList(MenuTypeEnum.MENU.getType()), Collections.singletonList(CommonStatusEnum.DISABLE.getStatus())); assertEquals(menuDOS.size(), idMenuMap.size()); menuDOS.forEach(m -> assertPojoEquals(idMenuMap.get(m.getId()), m)); @@ -270,7 +270,7 @@ public class MenuServiceTest extends BaseDbUnitTest { menuDO = createMenuDO(4L, MenuTypeEnum.MENU, "name", 0L, 2); mockCacheMap.put(menuDO.getId(), menuDO); - List menuDOS = sysMenuService.listMenusFromCache(Collections.singletonList(1L), + List menuDOS = sysMenuService.getMenuListFromCache(Collections.singletonList(1L), Collections.singletonList(MenuTypeEnum.MENU.getType()), Collections.singletonList(1)); assertEquals(menuDOS.size(), idMenuMap.size()); menuDOS.forEach(menu -> assertPojoEquals(idMenuMap.get(menu.getId()), menu)); diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index 5bb1736e42..3e7e51bbce 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -79,8 +79,8 @@ yudao: - cn.iocoder.yudao.module.tool.enums.ErrorCodeConstants tenant: # 多租户相关配置项 enable: true - ignore-urls: /admin-api/system/captcha/get-image, /admin-api/infra/file/get/* - 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 + ignore-urls: /admin-api/system/tenant/get-id-by-name, /admin-api/system/captcha/get-image, /admin-api/infra/file/get/* + 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 sms-code: # 短信验证码相关的配置项 expire-times: 10m send-frequency: 1m diff --git a/yudao-ui-admin/src/views/system/tenantPackage/index.vue b/yudao-ui-admin/src/views/system/tenantPackage/index.vue index 03b29223f7..f697d461b0 100755 --- a/yudao-ui-admin/src/views/system/tenantPackage/index.vue +++ b/yudao-ui-admin/src/views/system/tenantPackage/index.vue @@ -200,6 +200,8 @@ export default { this.reset(); this.open = true; this.title = "添加租户套餐"; + // 设置为非严格,继续使用半选中 + this.menuCheckStrictly = false; }, /** 修改按钮操作 */ handleUpdate(row) { @@ -222,12 +224,6 @@ export default { /** 获得菜单 */ getMenus() { listSimpleMenus().then(response => { - // 移除 BUTTON 类型,暂支只需要发 DIR、MENU 类型 - for (let i = response.data.length -1; i >= 0 ; i--) { - if (response.data[i].type === SystemMenuTypeEnum.BUTTON) { - response.data.splice(i, 1); - } - } // 处理 menuOptions 参数 this.menuOptions = []; // 只需要配置 diff --git a/更新日志.md b/更新日志.md index 72d58fa663..06291594bd 100644 --- a/更新日志.md +++ b/更新日志.md @@ -29,8 +29,9 @@ TODO * 【新增】后端 `yudao.tenant.enable` 配置项,前端 `VUE_APP_TENANT_ENABLE` 配置项,用于开关租户功能。 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/79311ecc71f0c6beabe0e5f84e1423ce745a5f09) * 【优化】调整默认所有表开启多租户的特性,可通过 `yudao.tenant.ignore-tables` 配置项进行忽略,替代原本默认不开启的策略 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/79311ecc71f0c6beabe0e5f84e1423ce745a5f09) * 【新增】通过 `yudao.tenant.ignore-urls` 配置忽略多租户的请求,例如说 ,例如说短信回调、支付回调等 Open API [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/79311ecc71f0c6beabe0e5f84e1423ce745a5f09) +* 【新增】新增 `@TenantIgnore` 注解,标记指定方法,忽略多租户的自动过滤,适合实现跨租户的逻辑 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/4d53944771c66b563da1e3d68d3ba43405af8a06) * 【新增】租户套餐的管理,可配置每个租户的可使用的功能权限 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/6b6d676a6baa2dad16ae9bf03d5002209064c8cc) -* 【优化】新建租户时,自动创建对应的管理员账号、角色等基础信息 []() +* 【优化】新建租户时,自动创建对应的管理员账号、角色等基础信息 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/2598c033a95d4b61d5f5ab3da5f1414f25c510d6) ### 🐞 Bug Fixes