refactor(tenant): 优化及修复租户相关部分代码

- 移动 TenantExtensionProperties 到 common 模块
- 修复 MenuController#tree 接口 setExcludeMenuIdList 方法判断非默认租户条件缺失
- 修复更新租户套餐菜单,没有及时更新在线用户数据权限(后面考虑重构 satoken 权限数据读取部分)
- TenantService 接口 getByDomain => getIdByDomain、getByCode => getIdByCode
- 移除 MenuService 中已废弃的方法
- LogDaoLocalImpl 还原(未测出租户用户操作,无租户 ID 问题)
- 优化 pg 数据库脚本,移除菜单表的租户相关字段
- 其他代码优化
This commit is contained in:
2025-07-20 23:13:07 +08:00
parent ada6f3ef5c
commit 84b2c39a30
24 changed files with 164 additions and 233 deletions

View File

@@ -14,11 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
package top.continew.admin.tenant.config; package top.continew.admin.common.config;
import lombok.Data; import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import top.continew.starter.core.constant.PropertiesConstants; import top.continew.starter.core.constant.PropertiesConstants;
import top.continew.starter.extension.tenant.context.TenantContextHolder;
import java.util.List; import java.util.List;
@@ -47,4 +48,13 @@ public class TenantExtensionProperties {
* 忽略菜单 ID租户不能使用的菜单 * 忽略菜单 ID租户不能使用的菜单
*/ */
private List<Long> ignoreMenus; private List<Long> ignoreMenus;
/**
* 是否为默认租户
*
* @return 是否为默认租户
*/
public boolean isDefaultTenant() {
return defaultTenantId.equals(TenantContextHolder.getTenantId());
}
} }

View File

@@ -19,7 +19,7 @@ package top.continew.admin.tenant.config;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import top.continew.admin.tenant.model.entity.TenantDO; import top.continew.admin.common.config.TenantExtensionProperties;
import top.continew.admin.tenant.service.TenantService; import top.continew.admin.tenant.service.TenantService;
import top.continew.starter.core.util.ServletUtils; import top.continew.starter.core.util.ServletUtils;
import top.continew.starter.core.util.validation.CheckUtils; import top.continew.starter.core.util.validation.CheckUtils;
@@ -57,9 +57,9 @@ public class DefaultTenantProvider implements TenantProvider {
if (StrUtil.isBlank(tenantCode)) { if (StrUtil.isBlank(tenantCode)) {
return context; return context;
} }
TenantDO tenant = tenantService.getByCode(tenantCode); Long id = tenantService.getIdByCode(tenantCode);
CheckUtils.throwIfNull(tenant, "编码为 [%s] 的租户不存在".formatted(tenantCode)); CheckUtils.throwIfNull(id, "编码为 [%s] 的租户不存在".formatted(tenantCode));
tenantId = tenant.getId(); tenantId = id;
} else { } else {
// 指定租户 // 指定租户
tenantId = Long.parseLong(tenantIdAsString); tenantId = Long.parseLong(tenantIdAsString);

View File

@@ -19,6 +19,7 @@ package top.continew.admin.tenant.config;
import org.springdoc.core.models.GroupedOpenApi; import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import top.continew.admin.common.config.TenantExtensionProperties;
import top.continew.admin.tenant.service.TenantService; import top.continew.admin.tenant.service.TenantService;
import top.continew.starter.extension.tenant.annotation.ConditionalOnEnabledTenant; import top.continew.starter.extension.tenant.annotation.ConditionalOnEnabledTenant;
import top.continew.starter.extension.tenant.config.TenantProvider; import top.continew.starter.extension.tenant.config.TenantProvider;

View File

@@ -25,7 +25,6 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.tenant.model.entity.TenantDO;
import top.continew.admin.tenant.model.query.PackageQuery; import top.continew.admin.tenant.model.query.PackageQuery;
import top.continew.admin.tenant.service.PackageService; import top.continew.admin.tenant.service.PackageService;
import top.continew.admin.tenant.service.TenantService; import top.continew.admin.tenant.service.TenantService;
@@ -60,15 +59,11 @@ public class CommonController {
return packageService.listDict(query, sortQuery); return packageService.listDict(query, sortQuery);
} }
@Operation(summary = "根据域名查询租户ID", description = "根据域名查询租户编码")
@SaIgnore @SaIgnore
@TenantIgnore @TenantIgnore
@GetMapping("/id/domain") @Operation(summary = "根据域名查询租户 ID", description = "根据域名查询租户 ID")
public Long getTenantIdByUrl(@RequestParam("domain") String domain) { @GetMapping("/id")
TenantDO tenantDO = tenantService.getByDomain(domain); public Long getTenantIdByDomain(@RequestParam String domain) {
if (tenantDO != null) { return tenantService.getIdByDomain(domain);
return tenantDO.getId();
}
return null;
} }
} }

View File

@@ -24,7 +24,7 @@ import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.common.base.controller.BaseController; import top.continew.admin.common.base.controller.BaseController;
import top.continew.admin.tenant.config.TenantExtensionProperties; import top.continew.admin.common.config.TenantExtensionProperties;
import top.continew.admin.common.enums.DisEnableStatusEnum; import top.continew.admin.common.enums.DisEnableStatusEnum;
import top.continew.admin.system.model.query.MenuQuery; import top.continew.admin.system.model.query.MenuQuery;
import top.continew.admin.system.service.MenuService; import top.continew.admin.system.service.MenuService;

View File

@@ -69,7 +69,6 @@ public class TenantDataHandlerForSystem implements TenantDataHandler {
private final PackageMenuService packageMenuService; private final PackageMenuService packageMenuService;
private final DeptMapper deptMapper; private final DeptMapper deptMapper;
private final MenuMapper menuMapper;
private final RoleMapper roleMapper; private final RoleMapper roleMapper;
private final RoleMenuService roleMenuService; private final RoleMenuService roleMenuService;
private final RoleMenuMapper roleMenuMapper; private final RoleMenuMapper roleMenuMapper;
@@ -93,11 +92,10 @@ public class TenantDataHandlerForSystem implements TenantDataHandler {
TenantUtils.execute(tenantId, () -> { TenantUtils.execute(tenantId, () -> {
// 初始化部门 // 初始化部门
Long deptId = this.initDeptData(tenant); Long deptId = this.initDeptData(tenant);
// 初始化菜单
List<Long> menuIds = packageMenuService.listMenuIdsByPackageId(tenant.getPackageId());
// 初始化角色 // 初始化角色
Long roleId = this.initRoleData(tenant); Long roleId = this.initRoleData(tenant);
// 角色绑定菜单 // 角色绑定菜单
List<Long> menuIds = packageMenuService.listMenuIdsByPackageId(tenant.getPackageId());
roleMenuService.add(menuIds, roleId); roleMenuService.add(menuIds, roleId);
// 初始化管理用户 // 初始化管理用户
Long userId = this.initUserData(tenant, deptId); Long userId = this.initUserData(tenant, deptId);
@@ -116,30 +114,30 @@ public class TenantDataHandlerForSystem implements TenantDataHandler {
for (UserDO user : userList) { for (UserDO user : userList) {
StpUtil.logout(user.getId()); StpUtil.logout(user.getId());
} }
Wrapper dw = Wrappers.query().eq("1", 1); Wrapper queryWrapper = Wrappers.query().eq("1", 1);
// 部门清除 // 部门清除
deptMapper.delete(dw); deptMapper.delete(queryWrapper);
// 文件清除 // 文件清除
List<Long> fileIds = CollUtils.mapToList(fileService.list(), FileDO::getId); List<Long> fileIds = CollUtils.mapToList(fileService.list(), FileDO::getId);
if (!fileIds.isEmpty()) { if (!fileIds.isEmpty()) {
fileService.delete(fileIds); fileService.delete(fileIds);
} }
// 日志清除 // 日志清除
logMapper.delete(dw); logMapper.delete(queryWrapper);
// 消息清除 // 消息清除
messageMapper.delete(dw); messageMapper.delete(queryWrapper);
messageUserMapper.delete(dw); messageUserMapper.delete(queryWrapper);
// 通知清除 // 通知清除
noticeMapper.delete(dw); noticeMapper.delete(queryWrapper);
// 角色相关数据清除 // 角色相关数据清除
roleMapper.delete(dw); roleMapper.delete(queryWrapper);
roleDeptMapper.delete(dw); roleDeptMapper.delete(queryWrapper);
roleMenuMapper.delete(dw); roleMenuMapper.delete(queryWrapper);
// 用户数据清除 // 用户数据清除
userMapper.delete(dw); userMapper.delete(queryWrapper);
userPasswordHistoryMapper.delete(dw); userPasswordHistoryMapper.delete(queryWrapper);
userRoleMapper.delete(dw); userRoleMapper.delete(queryWrapper);
userSocialMapper.delete(dw); userSocialMapper.delete(queryWrapper);
} }
/** /**

View File

@@ -39,17 +39,17 @@ public interface TenantService extends BaseService<TenantResp, TenantDetailResp,
* 根据绑定域名查询 * 根据绑定域名查询
* *
* @param domain 绑定域名 * @param domain 绑定域名
* @return 租户信息 * @return ID
*/ */
TenantDO getByDomain(String domain); Long getIdByDomain(String domain);
/** /**
* 根据编码查询 * 根据编码查询
* *
* @param code 编码 * @param code 编码
* @return 租户信息 * @return ID
*/ */
TenantDO getByCode(String code); Long getIdByCode(String code);
/** /**
* 检查租户状态 * 检查租户状态

View File

@@ -18,11 +18,12 @@ package top.continew.admin.tenant.service.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import com.alicp.jetcache.anno.Cached; import com.alicp.jetcache.anno.Cached;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import me.ahoo.cosid.provider.IdGeneratorProvider; import me.ahoo.cosid.provider.IdGeneratorProvider;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.continew.admin.common.base.service.BaseServiceImpl; import top.continew.admin.common.base.service.BaseServiceImpl;
import top.continew.admin.common.config.TenantExtensionProperties;
import top.continew.admin.common.constant.CacheConstants; import top.continew.admin.common.constant.CacheConstants;
import top.continew.admin.common.constant.SysConstants; import top.continew.admin.common.constant.SysConstants;
import top.continew.admin.common.enums.DisEnableStatusEnum; import top.continew.admin.common.enums.DisEnableStatusEnum;
@@ -30,7 +31,6 @@ import top.continew.admin.system.model.entity.RoleDO;
import top.continew.admin.system.model.entity.RoleMenuDO; import top.continew.admin.system.model.entity.RoleMenuDO;
import top.continew.admin.system.service.RoleMenuService; import top.continew.admin.system.service.RoleMenuService;
import top.continew.admin.system.service.RoleService; import top.continew.admin.system.service.RoleService;
import top.continew.admin.tenant.config.TenantExtensionProperties;
import top.continew.admin.tenant.constant.TenantCacheConstants; import top.continew.admin.tenant.constant.TenantCacheConstants;
import top.continew.admin.tenant.constant.TenantConstants; import top.continew.admin.tenant.constant.TenantConstants;
import top.continew.admin.tenant.handler.TenantDataHandler; import top.continew.admin.tenant.handler.TenantDataHandler;
@@ -44,13 +44,14 @@ import top.continew.admin.tenant.service.PackageService;
import top.continew.admin.tenant.service.TenantService; import top.continew.admin.tenant.service.TenantService;
import top.continew.starter.cache.redisson.util.RedisUtils; import top.continew.starter.cache.redisson.util.RedisUtils;
import top.continew.starter.core.constant.StringConstants; import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.core.util.CollUtils;
import top.continew.starter.core.util.validation.CheckUtils; import top.continew.starter.core.util.validation.CheckUtils;
import top.continew.starter.extension.tenant.util.TenantUtils; import top.continew.starter.extension.tenant.util.TenantUtils;
import java.io.Serializable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* 租户业务实现 * 租户业务实现
@@ -99,8 +100,7 @@ public class TenantServiceImpl extends BaseServiceImpl<TenantMapper, TenantDO, T
@Override @Override
public void afterUpdate(TenantReq req, TenantDO entity) { public void afterUpdate(TenantReq req, TenantDO entity) {
// 更新租户缓存 RedisUtils.deleteByPattern(TenantCacheConstants.TENANT_KEY_PREFIX + StringConstants.ASTERISK);
RedisUtils.set(TenantCacheConstants.TENANT_KEY_PREFIX + entity.getId(), entity);
} }
@Override @Override
@@ -113,23 +113,29 @@ public class TenantServiceImpl extends BaseServiceImpl<TenantMapper, TenantDO, T
@Override @Override
public void afterDelete(List<Long> ids) { public void afterDelete(List<Long> ids) {
ids.forEach(id -> RedisUtils.delete(TenantCacheConstants.TENANT_KEY_PREFIX + id)); RedisUtils.deleteByPattern(TenantCacheConstants.TENANT_KEY_PREFIX + StringConstants.ASTERISK);
} }
@Override @Override
@Cached(name = TenantCacheConstants.TENANT_KEY_PREFIX, key = "#id") @Cached(name = TenantCacheConstants.TENANT_KEY_PREFIX, key = "#domain")
public TenantDO getById(Serializable id) { public Long getIdByDomain(String domain) {
return super.getById(id); return baseMapper.lambdaQuery()
.select(TenantDO::getId)
.eq(TenantDO::getDomain, domain)
.oneOpt()
.map(TenantDO::getId)
.orElse(null);
} }
@Override @Override
public TenantDO getByDomain(String domain) { @Cached(name = TenantCacheConstants.TENANT_KEY_PREFIX, key = "#code")
return baseMapper.lambdaQuery().eq(TenantDO::getDomain, domain).oneOpt().orElse(null); public Long getIdByCode(String code) {
} return baseMapper.lambdaQuery()
.select(TenantDO::getId)
@Override .eq(TenantDO::getCode, code)
public TenantDO getByCode(String code) { .oneOpt()
return baseMapper.lambdaQuery().eq(TenantDO::getCode, code).oneOpt().orElse(null); .map(TenantDO::getId)
.orElse(null);
} }
@Override @Override
@@ -147,31 +153,39 @@ public class TenantServiceImpl extends BaseServiceImpl<TenantMapper, TenantDO, T
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void updateTenantMenu(List<Long> newMenuIds, Long packageId) { public void updateTenantMenu(List<Long> newMenuIds, Long packageId) {
List<Long> tenantIdList = this.listIdByPackageId(packageId); List<Long> tenantIdList = this.listIdByPackageId(packageId);
if (CollUtil.isEmpty(tenantIdList)) { if (CollUtil.isEmpty(tenantIdList)) {
return; return;
} }
// 删除旧菜单 // 删除旧菜单
tenantIdList.forEach(tenantId -> TenantUtils.execute(tenantId, () -> roleMenuService.remove(Wrappers
.lambdaQuery(RoleMenuDO.class)
.notIn(RoleMenuDO::getMenuId, newMenuIds))));
//新增菜单
tenantIdList.forEach(tenantId -> TenantUtils.execute(tenantId, () -> { tenantIdList.forEach(tenantId -> TenantUtils.execute(tenantId, () -> {
RoleDO roleDO = roleService.getByCode(SysConstants.TENANT_ADMIN_ROLE_CODE); // 更新在线用户上下文
List<Long> oldMenuIds = roleMenuService.list(Wrappers.lambdaQuery(RoleMenuDO.class) List<RoleMenuDO> roleMenuList = roleMenuService.lambdaQuery()
.eq(RoleMenuDO::getRoleId, roleDO.getId())).stream().map(RoleMenuDO::getMenuId).toList(); .select(RoleMenuDO::getRoleId)
List<Long> addMenuIds = CollUtil.disjunction(newMenuIds, oldMenuIds).stream().toList(); .notIn(RoleMenuDO::getMenuId, newMenuIds)
if (CollUtil.isNotEmpty(addMenuIds)) { .list();
List<RoleMenuDO> roleMenuDOList = new ArrayList<>(); Set<Long> roleIdSet = CollUtils.mapToSet(roleMenuList, RoleMenuDO::getRoleId);
for (Long addMenuId : addMenuIds) { roleIdSet.forEach(roleService::updateUserContext);
RoleMenuDO roleMenuDO = new RoleMenuDO(roleDO.getId(), addMenuId); // 删除旧菜单
roleMenuDOList.add(roleMenuDO); roleMenuService.lambdaUpdate().notIn(RoleMenuDO::getMenuId, newMenuIds).remove();
} }));
roleMenuService.saveBatch(roleMenuDOList, roleMenuDOList.size()); // 租户管理员:新增菜单
tenantIdList.forEach(tenantId -> TenantUtils.execute(tenantId, () -> {
RoleDO role = roleService.getByCode(SysConstants.TENANT_ADMIN_ROLE_CODE);
List<Long> oldMenuIdList = roleMenuService.listMenuIdByRoleIds(List.of(role.getId()));
Collection<Long> addMenuIdList = CollUtil.disjunction(newMenuIds, oldMenuIdList);
if (CollUtil.isNotEmpty(addMenuIdList)) {
List<RoleMenuDO> roleMenuList = addMenuIdList.stream()
.map(menuId -> new RoleMenuDO(role.getId(), menuId))
.toList();
roleMenuService.saveBatch(roleMenuList, roleMenuList.size());
// 更新在线用户上下文
roleService.updateUserContext(role.getId());
} }
})); }));
//清理角色菜单缓存 // 删除缓存
RedisUtils.deleteByPattern(CacheConstants.ROLE_MENU_KEY_PREFIX + StringConstants.ASTERISK); RedisUtils.deleteByPattern(CacheConstants.ROLE_MENU_KEY_PREFIX + StringConstants.ASTERISK);
} }

View File

@@ -20,7 +20,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import top.continew.admin.system.mapper.LogMapper; import top.continew.admin.system.mapper.LogMapper;
import top.continew.admin.system.service.UserService; import top.continew.admin.system.service.UserService;
import top.continew.starter.extension.tenant.autoconfigure.TenantProperties;
import top.continew.starter.log.annotation.ConditionalOnEnabledLog; import top.continew.starter.log.annotation.ConditionalOnEnabledLog;
import top.continew.starter.log.dao.LogDao; import top.continew.starter.log.dao.LogDao;
import top.continew.starter.trace.autoconfigure.TraceProperties; import top.continew.starter.trace.autoconfigure.TraceProperties;
@@ -39,10 +38,7 @@ public class LogConfiguration {
* 日志持久层接口本地实现类 * 日志持久层接口本地实现类
*/ */
@Bean @Bean
public LogDao logDao(UserService userService, public LogDao logDao(UserService userService, LogMapper logMapper, TraceProperties traceProperties) {
LogMapper logMapper, return new LogDaoLocalImpl(userService, logMapper, traceProperties);
TraceProperties traceProperties,
TenantProperties tenantProperties) {
return new LogDaoLocalImpl(userService, logMapper, traceProperties, tenantProperties);
} }
} }

View File

@@ -41,7 +41,7 @@ import top.continew.admin.system.service.UserService;
import top.continew.starter.core.constant.StringConstants; import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.core.util.ExceptionUtils; import top.continew.starter.core.util.ExceptionUtils;
import top.continew.starter.core.util.StrUtils; import top.continew.starter.core.util.StrUtils;
import top.continew.starter.extension.tenant.autoconfigure.TenantProperties; import top.continew.starter.extension.tenant.context.TenantContextHolder;
import top.continew.starter.extension.tenant.util.TenantUtils; import top.continew.starter.extension.tenant.util.TenantUtils;
import top.continew.starter.log.dao.LogDao; import top.continew.starter.log.dao.LogDao;
import top.continew.starter.log.model.LogRecord; import top.continew.starter.log.model.LogRecord;
@@ -67,7 +67,6 @@ public class LogDaoLocalImpl implements LogDao {
private final UserService userService; private final UserService userService;
private final LogMapper logMapper; private final LogMapper logMapper;
private final TraceProperties traceProperties; private final TraceProperties traceProperties;
private final TenantProperties tenantProperties;
@Async @Async
@Override @Override
@@ -88,12 +87,8 @@ public class LogDaoLocalImpl implements LogDao {
logDO.setCreateTime(LocalDateTime.ofInstant(logRecord.getTimestamp(), ZoneId.systemDefault())); logDO.setCreateTime(LocalDateTime.ofInstant(logRecord.getTimestamp(), ZoneId.systemDefault()));
// 设置操作人 // 设置操作人
this.setCreateUser(logDO, logRequest, logResponse); this.setCreateUser(logDO, logRequest, logResponse);
String strTenantId = logRequest.getHeaders().get(tenantProperties.getTenantIdHeader()); // 保存记录
if (StrUtil.isNotBlank(strTenantId)) { TenantUtils.execute(TenantContextHolder.getTenantId(), () -> logMapper.insert(logDO));
TenantUtils.execute(Long.parseLong(strTenantId), () -> logMapper.insert(logDO));
} else {
logMapper.insert(logDO);
}
} }
/** /**

View File

@@ -215,6 +215,7 @@ continew-starter.tenant:
- tenant_package_menu # 租户套餐与菜单关联表 - tenant_package_menu # 租户套餐与菜单关联表
- gen_config # 代码生成配置表 - gen_config # 代码生成配置表
- gen_field_config # 代码生成字段配置表 - gen_field_config # 代码生成字段配置表
- sys_menu # 菜单表
- sys_dict # 字典表 - sys_dict # 字典表
- sys_dict_item # 字典项表 - sys_dict_item # 字典项表
- sys_option # 参数表 - sys_option # 参数表
@@ -223,9 +224,9 @@ continew-starter.tenant:
- sys_sms_log # 短信日志表 - sys_sms_log # 短信日志表
- sys_client # 客户端表 - sys_client # 客户端表
- sys_app # 应用表 - sys_app # 应用表
- sys_menu # 菜单表
# 忽略菜单 ID租户不能使用的菜单 # 忽略菜单 ID租户不能使用的菜单
ignore-menus: ignore-menus:
- 1050 # 菜单管理
- 1130 # 字典管理 - 1130 # 字典管理
- 1140 # 字典项管理 - 1140 # 字典项管理
- 1150 # 系统配置 - 1150 # 系统配置
@@ -234,7 +235,6 @@ continew-starter.tenant:
- 7000 # 能力开放 - 7000 # 能力开放
- 8000 # 任务调度 - 8000 # 任务调度
- 9000 # 开发工具 - 9000 # 开发工具
- 1050 # 菜单管理
--- ### 限流器配置 --- ### 限流器配置
continew-starter: continew-starter:

View File

@@ -76,10 +76,6 @@ COMMENT ON COLUMN "tenant_package_menu"."menu_id" IS '菜单ID';
COMMENT ON TABLE "tenant_package_menu" IS '租户套餐和菜单关联表'; COMMENT ON TABLE "tenant_package_menu" IS '租户套餐和菜单关联表';
-- 为已有表增加租户字段 -- 为已有表增加租户字段
ALTER TABLE "sys_menu" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0;
COMMENT ON COLUMN "sys_menu"."tenant_id" IS '租户ID';
CREATE INDEX "idx_menu_tenant_id" ON "sys_menu" ("tenant_id");
ALTER TABLE "sys_dept" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0; ALTER TABLE "sys_dept" ADD COLUMN "tenant_id" int8 NOT NULL DEFAULT 0;
COMMENT ON COLUMN "sys_dept"."tenant_id" IS '租户ID'; COMMENT ON COLUMN "sys_dept"."tenant_id" IS '租户ID';
CREATE INDEX "idx_dept_tenant_id" ON "sys_dept" ("tenant_id"); CREATE INDEX "idx_dept_tenant_id" ON "sys_dept" ("tenant_id");
@@ -141,9 +137,6 @@ COMMENT ON COLUMN "sys_app"."tenant_id" IS '租户ID';
CREATE INDEX "idx_app_tenant_id" ON "sys_app" ("tenant_id"); CREATE INDEX "idx_app_tenant_id" ON "sys_app" ("tenant_id");
-- 调整唯一索引 -- 调整唯一索引
ALTER TABLE "sys_menu" DROP INDEX "uk_menu_title_parent_id";
CREATE UNIQUE INDEX "uk_menu_title_parent_id" ON "sys_menu" ("title", "parent_id", "tenant_id");
ALTER TABLE "sys_dept" DROP INDEX "uk_dept_name_parent_id"; ALTER TABLE "sys_dept" DROP INDEX "uk_dept_name_parent_id";
CREATE UNIQUE INDEX "uk_dept_name_parent_id" ON "sys_dept" ("name", "parent_id", "tenant_id"); CREATE UNIQUE INDEX "uk_dept_name_parent_id" ON "sys_dept" ("name", "parent_id", "tenant_id");

View File

@@ -24,6 +24,7 @@ import jakarta.servlet.http.HttpServletRequest;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import top.continew.admin.auth.model.req.LoginReq; import top.continew.admin.auth.model.req.LoginReq;
import top.continew.admin.auth.model.resp.LoginResp;
import top.continew.admin.common.context.RoleContext; import top.continew.admin.common.context.RoleContext;
import top.continew.admin.common.context.UserContext; import top.continew.admin.common.context.UserContext;
import top.continew.admin.common.context.UserContextHolder; import top.continew.admin.common.context.UserContextHolder;
@@ -88,9 +89,9 @@ public abstract class AbstractLoginHandler<T extends LoginReq> implements LoginH
* *
* @param user 用户信息 * @param user 用户信息
* @param client 客户端信息 * @param client 客户端信息
* @return token 令牌信息 * @return 登录响应参数
*/ */
protected String authenticate(UserDO user, ClientResp client) { protected LoginResp authenticate(UserDO user, ClientResp client) {
// 获取权限、角色、密码过期天数 // 获取权限、角色、密码过期天数
Long userId = user.getId(); Long userId = user.getId();
Long tenantId = TenantContextHolder.getTenantId(); Long tenantId = TenantContextHolder.getTenantId();
@@ -127,7 +128,10 @@ public abstract class AbstractLoginHandler<T extends LoginReq> implements LoginH
StpUtil.login(userContext.getId(), loginParameter.setExtraData(BeanUtil StpUtil.login(userContext.getId(), loginParameter.setExtraData(BeanUtil
.beanToMap(new UserExtraContext(ServletUtils.getRequest())))); .beanToMap(new UserExtraContext(ServletUtils.getRequest()))));
UserContextHolder.setContext(userContext); UserContextHolder.setContext(userContext);
return StpUtil.getTokenValue(); return LoginResp.builder()
.token(StpUtil.getTokenValue())
.tenantId(TenantContextHolder.isTenantEnabled() ? TenantContextHolder.getTenantId() : null)
.build();
} }
/** /**

View File

@@ -39,7 +39,6 @@ import top.continew.starter.cache.redisson.util.RedisUtils;
import top.continew.starter.core.util.ExceptionUtils; import top.continew.starter.core.util.ExceptionUtils;
import top.continew.starter.core.util.validation.CheckUtils; import top.continew.starter.core.util.validation.CheckUtils;
import top.continew.starter.core.util.validation.ValidationUtils; import top.continew.starter.core.util.validation.ValidationUtils;
import top.continew.starter.extension.tenant.context.TenantContextHolder;
import java.time.Duration; import java.time.Duration;
@@ -71,11 +70,7 @@ public class AccountLoginHandler extends AbstractLoginHandler<AccountLoginReq> {
// 检查用户状态 // 检查用户状态
super.checkUserStatus(user); super.checkUserStatus(user);
// 执行认证 // 执行认证
String token = this.authenticate(user, client); return super.authenticate(user, client);
return LoginResp.builder()
.token(token)
.tenantId(TenantContextHolder.isTenantEnabled() ? TenantContextHolder.getTenantId() : null)
.build();
} }
@Override @Override

View File

@@ -27,7 +27,6 @@ import top.continew.admin.system.model.entity.user.UserDO;
import top.continew.admin.system.model.resp.ClientResp; import top.continew.admin.system.model.resp.ClientResp;
import top.continew.starter.cache.redisson.util.RedisUtils; import top.continew.starter.cache.redisson.util.RedisUtils;
import top.continew.starter.core.util.validation.ValidationUtils; import top.continew.starter.core.util.validation.ValidationUtils;
import top.continew.starter.extension.tenant.context.TenantContextHolder;
/** /**
* 邮箱登录处理器 * 邮箱登录处理器
@@ -47,11 +46,7 @@ public class EmailLoginHandler extends AbstractLoginHandler<EmailLoginReq> {
// 检查用户状态 // 检查用户状态
super.checkUserStatus(user); super.checkUserStatus(user);
// 执行认证 // 执行认证
String token = super.authenticate(user, client); return super.authenticate(user, client);
return LoginResp.builder()
.token(token)
.tenantId(TenantContextHolder.isTenantEnabled() ? TenantContextHolder.getTenantId() : null)
.build();
} }
@Override @Override

View File

@@ -27,7 +27,6 @@ import top.continew.admin.system.model.entity.user.UserDO;
import top.continew.admin.system.model.resp.ClientResp; import top.continew.admin.system.model.resp.ClientResp;
import top.continew.starter.cache.redisson.util.RedisUtils; import top.continew.starter.cache.redisson.util.RedisUtils;
import top.continew.starter.core.util.validation.ValidationUtils; import top.continew.starter.core.util.validation.ValidationUtils;
import top.continew.starter.extension.tenant.context.TenantContextHolder;
/** /**
* 手机号登录处理器 * 手机号登录处理器
@@ -47,11 +46,7 @@ public class PhoneLoginHandler extends AbstractLoginHandler<PhoneLoginReq> {
// 检查用户状态 // 检查用户状态
super.checkUserStatus(user); super.checkUserStatus(user);
// 执行认证 // 执行认证
String token = super.authenticate(user, client); return super.authenticate(user, client);
return LoginResp.builder()
.token(token)
.tenantId(TenantContextHolder.isTenantEnabled() ? TenantContextHolder.getTenantId() : null)
.build();
} }
@Override @Override

View File

@@ -53,7 +53,6 @@ import top.continew.admin.system.service.UserSocialService;
import top.continew.starter.core.autoconfigure.application.ApplicationProperties; import top.continew.starter.core.autoconfigure.application.ApplicationProperties;
import top.continew.starter.core.exception.BadRequestException; import top.continew.starter.core.exception.BadRequestException;
import top.continew.starter.core.util.validation.ValidationUtils; import top.continew.starter.core.util.validation.ValidationUtils;
import top.continew.starter.extension.tenant.context.TenantContextHolder;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Collections; import java.util.Collections;
@@ -127,11 +126,7 @@ public class SocialLoginHandler extends AbstractLoginHandler<SocialLoginReq> {
userSocial.setLastLoginTime(LocalDateTime.now()); userSocial.setLastLoginTime(LocalDateTime.now());
userSocialService.saveOrUpdate(userSocial); userSocialService.saveOrUpdate(userSocial);
// 执行认证 // 执行认证
String token = super.authenticate(user, client); return super.authenticate(user, client);
return LoginResp.builder()
.token(token)
.tenantId(TenantContextHolder.isTenantEnabled() ? TenantContextHolder.getTenantId() : null)
.build();
} }
@Override @Override

View File

@@ -43,6 +43,9 @@ public class LoginResp implements Serializable {
@Schema(description = "令牌", example = "eyJ0eXAiOiJlV1QiLCJhbGciqiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb29pbiIsImxvZ2luSWQiOjEsInJuU3RyIjoiSjd4SUljYnU5cmNwU09vQ3Uyc1ND1BYYTYycFRjcjAifQ.KUPOYm-2wfuLUSfEEAbpGE527fzmkAJG7sMNcQ0pUZ8") @Schema(description = "令牌", example = "eyJ0eXAiOiJlV1QiLCJhbGciqiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb29pbiIsImxvZ2luSWQiOjEsInJuU3RyIjoiSjd4SUljYnU5cmNwU09vQ3Uyc1ND1BYYTYycFRjcjAifQ.KUPOYm-2wfuLUSfEEAbpGE527fzmkAJG7sMNcQ0pUZ8")
private String token; private String token;
/**
* 租户 ID
*/
@Schema(description = "租户 ID", example = "0") @Schema(description = "租户 ID", example = "0")
private Long tenantId; private Long tenantId;
} }

View File

@@ -23,11 +23,12 @@ import cn.hutool.core.util.StrUtil;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.common.constant.CacheConstants;
import top.continew.admin.common.base.controller.BaseController; import top.continew.admin.common.base.controller.BaseController;
import top.continew.admin.common.config.TenantExtensionProperties;
import top.continew.admin.common.constant.CacheConstants;
import top.continew.admin.system.model.query.MenuQuery; import top.continew.admin.system.model.query.MenuQuery;
import top.continew.admin.system.model.req.MenuReq; import top.continew.admin.system.model.req.MenuReq;
import top.continew.admin.system.model.resp.MenuResp; import top.continew.admin.system.model.resp.MenuResp;
@@ -40,6 +41,7 @@ import top.continew.starter.extension.crud.annotation.CrudApi;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping; import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.enums.Api; import top.continew.starter.extension.crud.enums.Api;
import top.continew.starter.extension.crud.model.query.SortQuery; import top.continew.starter.extension.crud.model.query.SortQuery;
import top.continew.starter.extension.tenant.context.TenantContextHolder;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.List; import java.util.List;
@@ -52,11 +54,12 @@ import java.util.List;
*/ */
@Tag(name = "菜单管理 API") @Tag(name = "菜单管理 API")
@RestController @RestController
@AllArgsConstructor @RequiredArgsConstructor
@CrudRequestMapping(value = "/system/menu", api = {Api.TREE, Api.GET, Api.CREATE, Api.UPDATE, Api.BATCH_DELETE}) @CrudRequestMapping(value = "/system/menu", api = {Api.TREE, Api.GET, Api.CREATE, Api.UPDATE, Api.BATCH_DELETE})
public class MenuController extends BaseController<MenuService, MenuResp, MenuResp, MenuQuery, MenuReq> { public class MenuController extends BaseController<MenuService, MenuResp, MenuResp, MenuQuery, MenuReq> {
private final MenuService menuService; private final MenuService menuService;
private final TenantExtensionProperties tenantExtensionProperties;
@Operation(summary = "清除缓存", description = "清除缓存") @Operation(summary = "清除缓存", description = "清除缓存")
@SaCheckPermission("system:menu:clearCache") @SaCheckPermission("system:menu:clearCache")
@@ -88,7 +91,9 @@ public class MenuController extends BaseController<MenuService, MenuResp, MenuRe
@Override @Override
public List<Tree<Long>> tree(@Valid MenuQuery query, @Valid SortQuery sortQuery) { public List<Tree<Long>> tree(@Valid MenuQuery query, @Valid SortQuery sortQuery) {
if (TenantContextHolder.isTenantEnabled() && !tenantExtensionProperties.isDefaultTenant()) {
query.setExcludeMenuIdList(menuService.listExcludeTenantMenu()); query.setExcludeMenuIdList(menuService.listExcludeTenantMenu());
}
return super.tree(query, sortQuery); return super.tree(query, sortQuery);
} }

View File

@@ -51,22 +51,9 @@ public interface MenuService extends BaseService<MenuResp, MenuResp, MenuQuery,
List<MenuResp> listByRoleId(Long roleId); List<MenuResp> listByRoleId(Long roleId);
/** /**
* 删除租户菜单 * 查询租户排除的菜单 ID 列表
* *
* @param menuS 菜单列表 * @return 租户排除的菜单 ID 列表
*/
void deleteTenantMenus(List<MenuDO> menuS);
/**
* 新增租户菜单
*
* @param menu 新增的菜单
* @param parentMenu 父菜单
*/
void addTenantMenu(MenuDO menu, MenuDO parentMenu);
/**
* 查询租户排除的菜单
*/ */
List<Long> listExcludeTenantMenu(); List<Long> listExcludeTenantMenu();
} }

View File

@@ -39,14 +39,14 @@ public interface RoleMenuService extends IService<RoleMenuDO> {
boolean add(List<Long> menuIds, Long roleId); boolean add(List<Long> menuIds, Long roleId);
/** /**
* 根据角色 ID 删除 * 根据角色 ID 列表删除
* *
* @param roleIds 角色 ID 列表 * @param roleIds 角色 ID 列表
*/ */
void deleteByRoleIds(List<Long> roleIds); void deleteByRoleIds(List<Long> roleIds);
/** /**
* 根据角色 ID 查询 * 根据角色 ID 列表查询
* *
* @param roleIds 角色 ID 列表 * @param roleIds 角色 ID 列表
* @return 菜单 ID 列表 * @return 菜单 ID 列表

View File

@@ -53,6 +53,13 @@ public interface RoleService extends BaseService<RoleResp, RoleDetailResp, RoleQ
*/ */
void assignToUsers(Long id, List<Long> userIds); void assignToUsers(Long id, List<Long> userIds);
/**
* 更新用户上下文
*
* @param roleId 角色 ID
*/
void updateUserContext(Long roleId);
/** /**
* 根据用户 ID 查询权限码 * 根据用户 ID 查询权限码
* *

View File

@@ -18,11 +18,11 @@ package top.continew.admin.system.service.impl;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.alicp.jetcache.anno.Cached; import com.alicp.jetcache.anno.Cached;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import top.continew.admin.common.base.service.BaseServiceImpl; import top.continew.admin.common.base.service.BaseServiceImpl;
@@ -31,20 +31,18 @@ import top.continew.admin.common.constant.SysConstants;
import top.continew.admin.common.enums.DisEnableStatusEnum; import top.continew.admin.common.enums.DisEnableStatusEnum;
import top.continew.admin.system.enums.MenuTypeEnum; import top.continew.admin.system.enums.MenuTypeEnum;
import top.continew.admin.system.mapper.MenuMapper; import top.continew.admin.system.mapper.MenuMapper;
import top.continew.admin.system.mapper.RoleMapper;
import top.continew.admin.system.model.entity.MenuDO; import top.continew.admin.system.model.entity.MenuDO;
import top.continew.admin.system.model.entity.RoleDO; import top.continew.admin.system.model.entity.RoleDO;
import top.continew.admin.system.model.entity.RoleMenuDO;
import top.continew.admin.system.model.query.MenuQuery; import top.continew.admin.system.model.query.MenuQuery;
import top.continew.admin.system.model.req.MenuReq; import top.continew.admin.system.model.req.MenuReq;
import top.continew.admin.system.model.resp.MenuResp; import top.continew.admin.system.model.resp.MenuResp;
import top.continew.admin.system.service.MenuService; import top.continew.admin.system.service.MenuService;
import top.continew.admin.system.service.RoleMenuService; import top.continew.admin.system.service.RoleService;
import top.continew.starter.cache.redisson.util.RedisUtils; import top.continew.starter.cache.redisson.util.RedisUtils;
import top.continew.starter.core.constant.StringConstants; import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.core.util.CollUtils;
import top.continew.starter.core.util.validation.CheckUtils; import top.continew.starter.core.util.validation.CheckUtils;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -58,8 +56,9 @@ import java.util.Set;
@RequiredArgsConstructor @RequiredArgsConstructor
public class MenuServiceImpl extends BaseServiceImpl<MenuMapper, MenuDO, MenuResp, MenuResp, MenuQuery, MenuReq> implements MenuService { public class MenuServiceImpl extends BaseServiceImpl<MenuMapper, MenuDO, MenuResp, MenuResp, MenuQuery, MenuReq> implements MenuService {
private final RoleMenuService roleMenuService; @Lazy
private final RoleMapper roleMapper; @Resource
private RoleService roleService;
@Override @Override
public Long create(MenuReq req) { public Long create(MenuReq req) {
@@ -114,66 +113,12 @@ public class MenuServiceImpl extends BaseServiceImpl<MenuMapper, MenuDO, MenuRes
return list; return list;
} }
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteTenantMenus(List<MenuDO> menuList) {
if (CollUtil.isEmpty(menuList)) {
return;
}
List<Long> delIds = new ArrayList<>();
for (MenuDO menu : menuList) {
MenuDO parentMenu = baseMapper.query()
.eq(menu.getType().equals(MenuTypeEnum.BUTTON), "CONCAT(title,permission)", menu.getTitle() + menu
.getPermission())
.eq(!menu.getType().equals(MenuTypeEnum.BUTTON), "name", menu.getName())
.one();
if (parentMenu != null) {
delIds.add(parentMenu.getId());
}
}
if (!delIds.isEmpty()) {
// 菜单删除
this.delete(delIds);
// 删除绑定关系
roleMenuService.remove(Wrappers.lambdaQuery(RoleMenuDO.class).in(RoleMenuDO::getMenuId, delIds));
}
// 删除缓存
RedisUtils.deleteByPattern(CacheConstants.ROLE_MENU_KEY_PREFIX + StringConstants.ASTERISK);
}
@Override
public void addTenantMenu(MenuDO menu, MenuDO parentMenu) {
Long parentId = SysConstants.SUPER_PARENT_ID;
if (parentMenu != null) {
MenuDO parent = baseMapper.query()
.eq(parentMenu.getType().equals(MenuTypeEnum.BUTTON), "CONCAT(title,permission)", parentMenu
.getTitle() + parentMenu.getPermission())
.eq(!parentMenu.getType().equals(MenuTypeEnum.BUTTON), "name", parentMenu.getName())
.one();
parentId = parent.getId();
}
menu.setId(null);
menu.setParentId(parentId);
// 菜单新增
baseMapper.insert(menu);
// 管理员绑定菜单
RoleDO role = roleMapper.selectOne(Wrappers.lambdaQuery(RoleDO.class)
.eq(RoleDO::getCode, SysConstants.TENANT_ADMIN_ROLE_CODE));
roleMenuService.save(new RoleMenuDO(role.getId(), menu.getId()));
// 删除缓存
RedisUtils.deleteByPattern(CacheConstants.ROLE_MENU_KEY_PREFIX + StringConstants.ASTERISK);
}
@Override @Override
public List<Long> listExcludeTenantMenu() { public List<Long> listExcludeTenantMenu() {
RoleDO role = roleMapper.selectOne(Wrappers.lambdaQuery(RoleDO.class) RoleDO role = roleService.getByCode(SysConstants.TENANT_ADMIN_ROLE_CODE);
.eq(RoleDO::getCode, SysConstants.TENANT_ADMIN_ROLE_CODE)); List<Long> allMenuIdList = CollUtils.mapToList(super.list(), MenuDO::getId);
if (role == null) { List<Long> menuIdList = CollUtils.mapToList(baseMapper.selectListByRoleId(role.getId()), MenuDO::getId);
return ListUtil.of(); return CollUtil.disjunction(allMenuIdList, menuIdList).stream().toList();
}
List<Long> allMenuList = list().stream().map(MenuDO::getId).toList();
List<Long> menuList = baseMapper.selectListByRoleId(role.getId()).stream().map(MenuDO::getId).toList();
return CollUtil.disjunction(allMenuList, menuList).stream().toList();
} }
/** /**

View File

@@ -20,6 +20,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.alicp.jetcache.anno.CacheInvalidate; import com.alicp.jetcache.anno.CacheInvalidate;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -57,7 +58,8 @@ import java.util.Set;
@RequiredArgsConstructor @RequiredArgsConstructor
public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleResp, RoleDetailResp, RoleQuery, RoleReq> implements RoleService { public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleResp, RoleDetailResp, RoleQuery, RoleReq> implements RoleService {
private final MenuService menuService; @Resource
private MenuService menuService;
private final RoleMenuService roleMenuService; private final RoleMenuService roleMenuService;
private final RoleDeptService roleDeptService; private final RoleDeptService roleDeptService;
private final UserRoleService userRoleService; private final UserRoleService userRoleService;
@@ -116,6 +118,17 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleRes
roleDeptService.deleteByRoleIds(ids); roleDeptService.deleteByRoleIds(ids);
} }
@Override
public void fill(Object obj) {
super.fill(obj);
if (obj instanceof RoleDetailResp detail) {
Long roleId = detail.getId();
List<MenuResp> list = menuService.listByRoleId(roleId);
List<Long> menuIds = CollUtils.mapToList(list, MenuResp::getId);
detail.setMenuIds(menuIds);
}
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@CacheInvalidate(key = "#id", name = CacheConstants.ROLE_MENU_KEY_PREFIX) @CacheInvalidate(key = "#id", name = CacheConstants.ROLE_MENU_KEY_PREFIX)
@@ -143,14 +156,16 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleRes
} }
@Override @Override
public void fill(Object obj) { public void updateUserContext(Long roleId) {
super.fill(obj); List<Long> userIdList = userRoleService.listUserIdByRoleId(roleId);
if (obj instanceof RoleDetailResp detail) { userIdList.forEach(userId -> {
Long roleId = detail.getId(); UserContext userContext = UserContextHolder.getContext(userId);
List<MenuResp> list = menuService.listByRoleId(roleId); if (userContext != null) {
List<Long> menuIds = CollUtils.mapToList(list, MenuResp::getId); userContext.setRoles(this.listByUserId(userId));
detail.setMenuIds(menuIds); userContext.setPermissions(this.listPermissionByUserId(userId));
UserContextHolder.setContext(userContext);
} }
});
} }
@Override @Override
@@ -232,21 +247,4 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleRes
.ne(id != null, RoleDO::getId, id) .ne(id != null, RoleDO::getId, id)
.exists(), "编码为 [{}] 的角色已存在", code); .exists(), "编码为 [{}] 的角色已存在", code);
} }
/**
* 更新用户上下文
*
* @param roleId 角色 ID
*/
private void updateUserContext(Long roleId) {
List<Long> userIdList = userRoleService.listUserIdByRoleId(roleId);
userIdList.parallelStream().forEach(userId -> {
UserContext userContext = UserContextHolder.getContext(userId);
if (userContext != null) {
userContext.setRoles(this.listByUserId(userId));
userContext.setPermissions(this.listPermissionByUserId(userId));
UserContextHolder.setContext(userContext);
}
});
}
} }