feat(upms): 增强租户管理功能并优化用户租户信息处理

- 在UserInfo DTO中新增tenantName字段用于返回租户名称
- 重构SysTenantService.getOrUpdateTenant方法返回完整租户对象
- 更新用户登录逻辑以包含租户名称信息
- 修改默认租户名称为PIGX ADMIN
- 优化租户切换逻辑确保缓存一致性
This commit is contained in:
PIGCLOUD committed 2025-12-30 21:42:42 +08:00
1 parent 36620c05ad
commit 7bdf9e1d8c
6 files changed
+494 -453

No files matched your search

+1 -1
View File
@@ -1311,7 +1311,7 @@ CREATE TABLE `sys_tenant` (
-- Records of sys_tenant
-- ----------------------------
BEGIN;
INSERT INTO `sys_tenant` VALUES (1, '北京分公司', '1', '', NULL, NULL, NULL, NULL, NULL, '2019-05-15 00:00:00', '2099-12-31 00:00:00', '0', '0', '', 'admin', '2019-05-15 15:44:57', '2023-07-30 14:52:57', 1642752536722997250);
INSERT INTO `sys_tenant` VALUES (1, 'PIGX ADMIN', '1', '', NULL, NULL, NULL, NULL, NULL, '2019-05-15 00:00:00', '2099-12-31 00:00:00', '0', '0', '', 'admin', '2019-05-15 15:44:57', '2023-07-30 14:52:57', 1642752536722997250);
COMMIT;
+1 -1
View File
@@ -1295,7 +1295,7 @@ CREATE TABLE `sys_tenant` (
-- Records of sys_tenant
-- ----------------------------
BEGIN;
INSERT INTO `sys_tenant` VALUES (1, '北京分公司', '1', '', NULL, NULL, NULL, NULL, NULL, '2019-05-15 00:00:00', '2099-12-31 00:00:00', '0', '0', '', 'admin', '2019-05-15 15:44:57', '2023-07-30 14:52:57', 1642752536722997250);
INSERT INTO `sys_tenant` VALUES (1, 'PIGX ADMIN', '1', '', NULL, NULL, NULL, NULL, NULL, '2019-05-15 00:00:00', '2099-12-31 00:00:00', '0', '0', '', 'admin', '2019-05-15 15:44:57', '2023-07-30 14:52:57', 1642752536722997250);
COMMIT;
@@ -40,22 +40,24 @@ import java.util.List;
@EqualsAndHashCode(callSuper = true)
public class UserInfo extends UserVO implements Serializable {
/**
* 密码
*/
@JsonIgnore(value = false)
private String password;
/**
* 密码
*/
@JsonIgnore(value = false)
private String password;
/**
* 随机盐
*/
@JsonIgnore(value = false)
private String salt;
/**
* 随机盐
*/
@JsonIgnore(value = false)
private String salt;
/**
* 权限标识集合
*/
@Schema(description = "权限标识集合")
private List<String> permissions = new ArrayList<>();
/**
* 权限标识集合
*/
@Schema(description = "权限标识集合")
private List<String> permissions = new ArrayList<>();
@Schema(description = "租户名称")
private String tenantName;
}
@@ -114,8 +114,11 @@ public interface SysTenantService extends IService<SysTenant> {
R updateUserTenant(UserDTO userDto);
/**
* 检查或更新租户信息
* 获取或更新当前用户的租户信息
* <p>
* 如果当前租户已过期或无效,则自动切换到用户的其他有效租户
* @return 当前有效的租户对象,如果无有效租户则返回null
*/
Long getOrUpdateTenant();
SysTenant getOrUpdateTenant();
}
@@ -67,475 +67,510 @@ import java.util.*;
@AllArgsConstructor
public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant> implements SysTenantService {
private final SysOauthClientDetailsService clientServices;
private final SysOauthClientDetailsService clientServices;
private final SysRoleMenuMapper roleMenuMapper;
private final SysRoleMenuMapper roleMenuMapper;
private final SysDictItemService dictItemService;
private final SysDictItemService dictItemService;
private final SysPublicParamService paramService;
private final SysPublicParamService paramService;
private final SysRoleService roleService;
private final SysRoleService roleService;
private final SysMenuService menuService;
private final SysMenuService menuService;
private final SysDeptService deptService;
private final SysDeptService deptService;
private final SysDictService dictService;
private final SysDictService dictService;
private final SysUserMapper sysUserMapper;
private final SysUserMapper sysUserMapper;
private final SysTenantUserMapper sysTenantUserMapper;
private final SysTenantUserMapper sysTenantUserMapper;
private final SysUserPostMapper sysUserPostMapper;
private final SysUserPostMapper sysUserPostMapper;
private final SysUserRoleMapper sysUserRoleMapper;
private final SysUserRoleMapper sysUserRoleMapper;
private final SysUserDeptMapper sysUserDeptMapper;
private final SysUserDeptMapper sysUserDeptMapper;
private final SysRoleMapper sysRoleMapper;
private final SysRoleMapper sysRoleMapper;
private final SysDeptMapper sysDeptMapper;
private final SysDeptMapper sysDeptMapper;
private final SysPostMapper sysPostMapper;
private final SysPostMapper sysPostMapper;
private final CacheManager cacheManager;
private final CacheManager cacheManager;
/**
* 获取正常状态租户
* <p>
* 1. 状态正常 2. 开始时间小于等于当前时间 3. 结束时间大于等于当前时间
* @return
*/
@Override
@Cacheable(value = CacheConstants.TENANT_DETAILS)
public List<SysTenant> getNormalTenant() {
return baseMapper
.selectList(Wrappers.<SysTenant>lambdaQuery().eq(SysTenant::getStatus, TenantStateEnum.NORMAL.getCode()));
}
/**
* 获取正常状态租户
* <p>
* 1. 状态正常 2. 开始时间小于等于当前时间 3. 结束时间大于等于当前时间
*
* @return
*/
@Override
@Cacheable(value = CacheConstants.TENANT_DETAILS)
public List<SysTenant> getNormalTenant() {
return baseMapper
.selectList(Wrappers.<SysTenant>lambdaQuery().eq(SysTenant::getStatus, TenantStateEnum.NORMAL.getCode()));
}
/**
* 保存租户
* <p>
* 1. 保存租户 2. 初始化权限相关表 - sys_user - sys_role - sys_menu - sys_user_role -
* sys_role_menu - sys_dict - sys_dict_item - sys_client_details - sys_public_params
* @param sysTenant 租户实体
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
@CacheEvict(value = CacheConstants.TENANT_DETAILS)
public Boolean saveTenant(SysTenant sysTenant) {
this.save(sysTenant);
// 查询系统默认租户配置参数
TenantDefaultConfig tenantDefault = new TenantDefaultConfig();
/**
* 保存租户
* <p>
* 1. 保存租户 2. 初始化权限相关表 - sys_user - sys_role - sys_menu - sys_user_role -
* sys_role_menu - sys_dict - sys_dict_item - sys_client_details - sys_public_params
*
* @param sysTenant 租户实体
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
@CacheEvict(value = CacheConstants.TENANT_DETAILS)
public Boolean saveTenant(SysTenant sysTenant) {
this.save(sysTenant);
// 查询系统默认租户配置参数
TenantDefaultConfig tenantDefault = new TenantDefaultConfig();
List<SysDict> dictList = new ArrayList<>(32);
List<Long> dictIdList = new ArrayList<>(32);
List<SysDictItem> dictItemList = new ArrayList<>(64);
List<SysMenu> menuList = new ArrayList<>(128);
List<SysOauthClientDetails> clientDetailsList = new ArrayList<>(16);
List<SysPublicParam> publicParamList = new ArrayList<>(64);
List<SysDict> dictList = new ArrayList<>(32);
List<Long> dictIdList = new ArrayList<>(32);
List<SysDictItem> dictItemList = new ArrayList<>(64);
List<SysMenu> menuList = new ArrayList<>(128);
List<SysOauthClientDetails> clientDetailsList = new ArrayList<>(16);
List<SysPublicParam> publicParamList = new ArrayList<>(64);
TenantBroker.runAs(tenantDefault.getTenantDefaultId(), (id) -> {
// 查询系统内置字典
dictList.addAll(dictService.list());
// 查询系统内置字典项目
dictIdList.addAll(dictList.stream().map(SysDict::getId).toList());
dictItemList.addAll(
dictItemService.list(Wrappers.<SysDictItem>lambdaQuery().in(SysDictItem::getDictId, dictIdList)));
List<SysMenu> newMenuList = menuService.list(Wrappers.<SysMenu>lambdaQuery()
.in(SysMenu::getMenuId, StrUtil.split(sysTenant.getMenuId(), CharUtil.COMMA)));
// 查询当前租户菜单
menuList.addAll(newMenuList);
// 查询客户端配置
clientDetailsList.addAll(clientServices.list());
// 查询系统参数配置
publicParamList.addAll(paramService.list());
});
TenantBroker.runAs(tenantDefault.getTenantDefaultId(), (id) -> {
// 查询系统内置字典
dictList.addAll(dictService.list());
// 查询系统内置字典项目
dictIdList.addAll(dictList.stream().map(SysDict::getId).toList());
dictItemList.addAll(
dictItemService.list(Wrappers.<SysDictItem>lambdaQuery().in(SysDictItem::getDictId, dictIdList)));
List<SysMenu> newMenuList = menuService.list(Wrappers.<SysMenu>lambdaQuery()
.in(SysMenu::getMenuId,
StrUtil.split(sysTenant.getMenuId(), CharUtil.COMMA).stream().map(Long::parseLong).toList()));
// 查询当前租户菜单
menuList.addAll(newMenuList);
// 查询客户端配置
clientDetailsList.addAll(clientServices.list());
// 查询系统参数配置
publicParamList.addAll(paramService.list());
});
// 保证插入租户为新的租户
TenantBroker.applyAs(sysTenant.getId(), (id -> {
// 插入部门
SysDept dept = new SysDept();
dept.setName(tenantDefault.getTenantDefaultDeptname());
dept.setParentId(0L);
deptService.save(dept);
// 保证插入租户为新的租户
TenantBroker.applyAs(sysTenant.getId(), (id -> {
// 插入部门
SysDept dept = new SysDept();
dept.setName(tenantDefault.getTenantDefaultDeptname());
dept.setParentId(0L);
dept.setSortOrder(0);
deptService.save(dept);
// 构造普通用户角色
SysRole roleDefault = new SysRole();
roleDefault.setRoleCode(tenantDefault.getUserDefaultRolecode());
roleDefault.setRoleName(tenantDefault.getUserDefaultRolename());
roleDefault.setDsType(DataScopeTypeEnum.SELF_LEVEL.getType());
roleService.save(roleDefault);
// 构造普通用户角色
SysRole roleDefault = new SysRole();
roleDefault.setRoleCode(tenantDefault.getUserDefaultRolecode());
roleDefault.setRoleName(tenantDefault.getUserDefaultRolename());
roleDefault.setDsType(DataScopeTypeEnum.SELF_LEVEL.getType());
roleService.save(roleDefault);
// 构造新角色 管理员角色
SysRole role = new SysRole();
role.setRoleCode(tenantDefault.getTenantDefaultRolecode());
role.setRoleName(tenantDefault.getTenantDefaultRolename());
role.setDsType(DataScopeTypeEnum.ALL.getType());
roleService.save(role);
// 插入新的菜单
saveTenantMenu(menuList, CommonConstants.MENU_TREE_ROOT_ID, CommonConstants.MENU_TREE_ROOT_ID);
// 构造新角色 管理员角色
SysRole role = new SysRole();
role.setRoleCode(tenantDefault.getTenantDefaultRolecode());
role.setRoleName(tenantDefault.getTenantDefaultRolename());
role.setDsType(DataScopeTypeEnum.ALL.getType());
roleService.save(role);
// 插入新的菜单
saveTenantMenu(menuList, CommonConstants.MENU_TREE_ROOT_ID, CommonConstants.MENU_TREE_ROOT_ID);
// 重新查询出所有的菜单关联角色
List<SysMenu> list = menuService.list();
// 重新查询出所有的菜单关联角色
List<SysMenu> list = menuService.list();
// 查询全部菜单,构造角色菜单关系
List<SysRoleMenu> roleMenuList = list.stream().map(menu -> {
SysRoleMenu roleMenu = new SysRoleMenu();
roleMenu.setRoleId(role.getRoleId());
roleMenu.setMenuId(menu.getMenuId());
return roleMenu;
}).toList();
roleMenuList.forEach(roleMenuMapper::insert);
// 插入系统字典
dictService.saveBatch(dictList.stream().peek(d -> d.setId(null)).toList());
// 处理字典项最新关联的字典ID
List<SysDictItem> itemList = dictList.stream()
.flatMap(dict -> dictItemList.stream()
.filter(item -> item.getDictType().equals(dict.getDictType()))
.peek(item -> {
item.setDictId(dict.getId());
item.setId(null);
}))
.toList();
// 查询全部菜单,构造角色菜单关系
List<SysRoleMenu> roleMenuList = list.stream().map(menu -> {
SysRoleMenu roleMenu = new SysRoleMenu();
roleMenu.setRoleId(role.getRoleId());
roleMenu.setMenuId(menu.getMenuId());
return roleMenu;
}).toList();
roleMenuList.forEach(roleMenuMapper::insert);
// 插入系统字典
dictService.saveBatch(dictList.stream().peek(d -> d.setId(null)).toList());
// 处理字典项最新关联的字典ID
List<SysDictItem> itemList = dictList.stream()
.flatMap(dict -> dictItemList.stream()
.filter(item -> item.getDictType().equals(dict.getDictType()))
.peek(item -> {
item.setDictId(dict.getId());
item.setId(null);
}))
.toList();
// 插入客户端
clientServices.saveBatch(clientDetailsList.stream().peek(d -> d.setId(null)).toList());
// 插入系统配置
paramService.saveBatch(publicParamList.stream().peek(d -> d.setPublicId(null)).toList());
return dictItemService.saveBatch(itemList);
}));
// 插入客户端
clientServices.saveBatch(clientDetailsList.stream().peek(d -> d.setId(null)).toList());
// 插入系统配置
paramService.saveBatch(publicParamList.stream().peek(d -> d.setPublicId(null)).toList());
return dictItemService.saveBatch(itemList);
}));
SpringContextHolder.publishEvent(new ClientDetailsInitRunner.ClientDetailsInitEvent(sysTenant));
SpringContextHolder.publishEvent(new ClientDetailsInitRunner.ClientDetailsInitEvent(sysTenant));
return Boolean.TRUE;
}
return Boolean.TRUE;
}
/**
* 修改租户
* @param tenantDTO 新旧套餐数据
* @return true/false
*/
@Override
@Transactional(rollbackFor = Exception.class)
@CacheEvict(value = CacheConstants.TENANT_DETAILS, allEntries = true)
public Boolean updateTenant(SysTenant tenantDTO) {
SysTenant oldTenant = baseMapper.selectById(tenantDTO.getId());
List<String> newMenuIdList = StrUtil.split(tenantDTO.getMenuId(), CharUtil.COMMA);
List<String> oldMenuIdList = StrUtil.split(oldTenant.getMenuId(), CharUtil.COMMA);
/**
* 修改租户
*
* @param tenantDTO 新旧套餐数据
* @return true/false
*/
@Override
@Transactional(rollbackFor = Exception.class)
@CacheEvict(value = CacheConstants.TENANT_DETAILS, allEntries = true)
public Boolean updateTenant(SysTenant tenantDTO) {
SysTenant oldTenant = baseMapper.selectById(tenantDTO.getId());
List<String> newMenuIdList = StrUtil.split(tenantDTO.getMenuId(), CharUtil.COMMA);
List<String> oldMenuIdList = StrUtil.split(oldTenant.getMenuId(), CharUtil.COMMA);
// 更新租户信息
updateById(tenantDTO);
// 更新租户信息
updateById(tenantDTO);
// 如果没有修改租户套餐
TenantDefaultConfig tenantDefault = new TenantDefaultConfig();
List<SysMenu> sysMenuList = TenantBroker.applyAs(tenantDefault.getTenantDefaultId(), id -> menuService.list());
if (tenantDefault.getTenantDefaultId().equals(tenantDTO.getId())) {
return Boolean.TRUE;
}
// 如果没有修改租户套餐
TenantDefaultConfig tenantDefault = new TenantDefaultConfig();
List<SysMenu> sysMenuList = TenantBroker.applyAs(tenantDefault.getTenantDefaultId(), id -> menuService.list());
if (tenantDefault.getTenantDefaultId().equals(tenantDTO.getId())) {
return Boolean.TRUE;
}
// 比较新旧套餐是否一致
if (CollUtil.isEqualList(newMenuIdList, oldMenuIdList)) {
return Boolean.TRUE;
}
// 比较新旧套餐是否一致
if (CollUtil.isEqualList(newMenuIdList, oldMenuIdList)) {
return Boolean.TRUE;
}
// 0. 计算两个差集,差集表示变化的功能项
Collection<String> disjunctionList = CollUtil.disjunction(newMenuIdList, oldMenuIdList);
// 1. 如果旧套餐包含差集元素则删除
CollUtil.intersection(oldMenuIdList, disjunctionList)
.forEach(menuId -> TenantBroker.runAs(tenantDTO.getId(), (tenantId -> {
// 查询租户菜单元信息
SysMenu menu = CollUtil.findOneByField(sysMenuList, SysMenu.Fields.menuId, Long.parseLong(menuId));
// 0. 计算两个差集,差集表示变化的功能项
Collection<String> disjunctionList = CollUtil.disjunction(newMenuIdList, oldMenuIdList);
// 1. 如果旧套餐包含差集元素则删除
CollUtil.intersection(oldMenuIdList, disjunctionList)
.forEach(menuId -> TenantBroker.runAs(tenantDTO.getId(), (tenantId -> {
// 查询租户菜单元信息
SysMenu menu = CollUtil.findOneByField(sysMenuList, SysMenu.Fields.menuId, Long.parseLong(menuId));
// 根据path 或者 permisson 删除目标租户菜单
menuService.remove(Wrappers.<SysMenu>lambdaQuery()
.eq(StrUtil.isNotBlank(menu.getPath()), SysMenu::getPath, menu.getPath())
.or()
.eq(StrUtil.isNotBlank(menu.getPermission()), SysMenu::getPermission, menu.getPermission()));
})));
if (Objects.isNull(menu)) {
return;
}
// 2. 如果旧套餐不包含差集元素则新增
List<SysMenu> newTenantMenuIdList = CollUtil.subtract(disjunctionList, oldMenuIdList)
.stream()
.map(menuId -> TenantBroker.applyAs(tenantDTO.getId(), (tenantId -> {
// 查询租户菜单元信息
SysMenu menu = CollUtil.findOneByField(sysMenuList, SysMenu.Fields.menuId, Long.parseLong(menuId));
// 根据path 或者 permisson 删除目标租户菜单
menuService.remove(Wrappers.<SysMenu>lambdaQuery()
.eq(StrUtil.isNotBlank(menu.getPath()), SysMenu::getPath, menu.getPath())
.or()
.eq(StrUtil.isNotBlank(menu.getPermission()), SysMenu::getPermission, menu.getPermission()));
})));
// 新增租户菜单,但未维护上下级关系
SysMenu newMenu = new SysMenu();
BeanUtils.copyProperties(menu, newMenu, SysMenu.Fields.menuId);
menuService.save(newMenu);
return newMenu;
})))
.toList();
// 2. 如果旧套餐不包含差集元素则新增
List<SysMenu> newTenantMenuIdList = CollUtil.subtract(disjunctionList, oldMenuIdList)
.stream()
.map(menuId -> TenantBroker.applyAs(tenantDTO.getId(), (tenantId -> {
// 查询租户菜单元信息
SysMenu menu = CollUtil.findOneByField(sysMenuList, SysMenu.Fields.menuId, Long.parseLong(menuId));
// 3. 更新新增菜单上下级关系
for (SysMenu tenantMenu : newTenantMenuIdList) {
// 查询租户菜单父元信息
SysMenu parentMenu = CollUtil.findOneByField(sysMenuList, SysMenu.Fields.menuId, tenantMenu.getParentId());
// 查询目标租户父菜单元信息
TenantBroker.runAs(tenantDTO.getId(), tenantId -> {
// 如何菜单父节点是根节点则直接插入,不要查询父节点判断
if (Objects.equals(tenantMenu.getParentId(), CommonConstants.MENU_TREE_ROOT_ID)) {
menuService.updateById(tenantMenu);
return;
}
// 新增租户菜单,但未维护上下级关系
SysMenu newMenu = new SysMenu();
BeanUtils.copyProperties(menu, newMenu, SysMenu.Fields.menuId);
menuService.save(newMenu);
return newMenu;
})))
.toList();
// 根据path 或者 permisson 查询目标父菜单
SysMenu tenantParentMenu = menuService.getOne(Wrappers.<SysMenu>lambdaQuery()
.eq(StrUtil.isNotBlank(parentMenu.getPath()), SysMenu::getPath, parentMenu.getPath())
.or()
.eq(StrUtil.isNotBlank(parentMenu.getPermission()), SysMenu::getPermission,
parentMenu.getPermission()),
false);
// 3. 更新新增菜单上下级关系
for (SysMenu tenantMenu : newTenantMenuIdList) {
// 查询租户菜单父元信息
SysMenu parentMenu = CollUtil.findOneByField(sysMenuList, SysMenu.Fields.menuId, tenantMenu.getParentId());
// 查询目标租户父菜单元信息
TenantBroker.runAs(tenantDTO.getId(), tenantId -> {
// 如何菜单父节点是根节点则直接插入,不要查询父节点判断
if (Objects.equals(tenantMenu.getParentId(), CommonConstants.MENU_TREE_ROOT_ID)) {
menuService.updateById(tenantMenu);
return;
}
tenantMenu.setParentId(tenantParentMenu.getMenuId());
menuService.updateById(tenantMenu);
});
}
// 根据path 或者 permisson 查询目标父菜单
SysMenu tenantParentMenu = menuService.getOne(Wrappers.<SysMenu>lambdaQuery()
.eq(StrUtil.isNotBlank(parentMenu.getPath()), SysMenu::getPath, parentMenu.getPath())
.or()
.eq(StrUtil.isNotBlank(parentMenu.getPermission()), SysMenu::getPermission,
parentMenu.getPermission()),
false);
// 清空指定租户的菜单权限缓存
Set<String> keys = RedisUtils.keys(String.format("%s:%s::*", tenantDTO.getId(), CacheConstants.MENU_DETAILS));
if (CollUtil.isNotEmpty(keys)) {
RedisUtils.delete(keys.toArray(new String[0]));
}
return Boolean.TRUE;
}
tenantMenu.setParentId(tenantParentMenu.getMenuId());
menuService.updateById(tenantMenu);
});
}
/**
* 获取用户所属租户列表
* @return 用户所属租户列表
*/
@Override
public List<SysTenant> getUserTenant() {
MPJLambdaWrapper<SysTenant> wrapper = new MPJLambdaWrapper<SysTenant>().selectAll(SysTenant.class)
.leftJoin(SysTenantUser.class, SysTenantUser::getTenantId, SysTenant::getId)
.eq(SysTenantUser::getUserId, SecurityUtils.getUser().getId())
.eq(SysTenant::getStatus, TenantStateEnum.NORMAL.getCode());
// 清空指定租户的菜单权限缓存
Set<String> keys = RedisUtils.keys(String.format("%s:%s::*", tenantDTO.getId(), CacheConstants.MENU_DETAILS));
if (CollUtil.isNotEmpty(keys)) {
RedisUtils.delete(keys.toArray(new String[0]));
}
return Boolean.TRUE;
}
return baseMapper.selectJoinList(wrapper)
.stream()
.filter(tenant -> tenant.getStartTime().isBefore(LocalDateTime.now()))
.filter(tenant -> tenant.getEndTime().isAfter(LocalDateTime.now()))
.toList();
}
/**
* 获取用户所属租户列表
*
* @return 用户所属租户列表
*/
@Override
public List<SysTenant> getUserTenant() {
MPJLambdaWrapper<SysTenant> wrapper = new MPJLambdaWrapper<SysTenant>().selectAll(SysTenant.class)
.leftJoin(SysTenantUser.class, SysTenantUser::getTenantId, SysTenant::getId)
.eq(SysTenantUser::getUserId, SecurityUtils.getUser().getId())
.eq(SysTenant::getStatus, TenantStateEnum.NORMAL.getCode());
/**
* 获取用户租户分页信息
* @param page 分页参数
* @param userDTO 用户信息
* @return 用户租户分页结果
*/
@Override
public Page getUserTenantPage(Page page, UserDTO userDTO) {
MPJLambdaWrapper<SysUser> wrapper = new MPJLambdaWrapper<SysUser>().selectAll(SysUser.class)
.innerJoin(SysTenantUser.class, SysTenantUser::getUserId, SysUser::getUserId)
.like(StrUtil.isNotBlank(userDTO.getUsername()), SysUser::getUsername, userDTO.getUsername())
.like(StrUtil.isNotBlank(userDTO.getPhone()), SysUser::getPhone, userDTO.getPhone())
.like(StrUtil.isNotBlank(userDTO.getEmail()), SysUser::getEmail, userDTO.getEmail())
.eq(Objects.nonNull(userDTO.getTenantId()), SysTenantUser::getTenantId, userDTO.getTenantId());
return TenantBroker.noneAs(() -> sysUserMapper.selectJoinPage(page, wrapper));
}
return baseMapper.selectJoinList(wrapper)
.stream()
.filter(tenant -> tenant.getStartTime().isBefore(LocalDateTime.now()))
.filter(tenant -> tenant.getEndTime().isAfter(LocalDateTime.now()))
.toList();
}
/**
* 移除租户用户
* @param tenantUserDTO 租户用户信息
* @return 是否移除成功
*/
@Override
public Boolean removeTenantUser(SysTenantUserDTO tenantUserDTO) {
ArrayList<Long> userIdList = CollUtil.toList(tenantUserDTO.getUserIds());
/**
* 获取用户租户分页信息
*
* @param page 分页参数
* @param userDTO 用户信息
* @return 用户租户分页结果
*/
@Override
public Page getUserTenantPage(Page page, UserDTO userDTO) {
MPJLambdaWrapper<SysUser> wrapper = new MPJLambdaWrapper<SysUser>().selectAll(SysUser.class)
.innerJoin(SysTenantUser.class, SysTenantUser::getUserId, SysUser::getUserId)
.like(StrUtil.isNotBlank(userDTO.getUsername()), SysUser::getUsername, userDTO.getUsername())
.like(StrUtil.isNotBlank(userDTO.getPhone()), SysUser::getPhone, userDTO.getPhone())
.like(StrUtil.isNotBlank(userDTO.getEmail()), SysUser::getEmail, userDTO.getEmail())
.eq(Objects.nonNull(userDTO.getTenantId()), SysTenantUser::getTenantId, userDTO.getTenantId());
return TenantBroker.noneAs(() -> sysUserMapper.selectJoinPage(page, wrapper));
}
// 删除租户用户关系
sysTenantUserMapper.delete(Wrappers.<SysTenantUser>lambdaQuery()
.eq(SysTenantUser::getTenantId, tenantUserDTO.getTenantId())
.in(SysTenantUser::getUserId, userIdList));
/**
* 移除租户用户
*
* @param tenantUserDTO 租户用户信息
* @return 是否移除成功
*/
@Override
public Boolean removeTenantUser(SysTenantUserDTO tenantUserDTO) {
ArrayList<Long> userIdList = CollUtil.toList(tenantUserDTO.getUserIds());
TenantBroker.runAs(tenantUserDTO.getTenantId(), (tenantId -> {
// 删除用户岗位
sysUserPostMapper.delete(Wrappers.<SysUserPost>lambdaQuery().in(SysUserPost::getUserId, userIdList));
// 删除用户角色
sysUserRoleMapper.delete(Wrappers.<SysUserRole>lambdaQuery().in(SysUserRole::getUserId, userIdList));
// 删除用户部门
sysUserDeptMapper.delete(Wrappers.<SysUserDept>lambdaQuery().in(SysUserDept::getUserId, userIdList));
}));
return Boolean.TRUE;
}
// 删除租户用户关系
sysTenantUserMapper.delete(Wrappers.<SysTenantUser>lambdaQuery()
.eq(SysTenantUser::getTenantId, tenantUserDTO.getTenantId())
.in(SysTenantUser::getUserId, userIdList));
/**
* 根据用户信息查询租户用户列表
* @param userDTO 用户信息传输对象
* @return 租户用户列表
*/
@Override
public List<SysUser> listTenantUser(UserDTO userDTO) {
return TenantBroker.noneAs(() -> sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery()
.ne(SysUser::getTenantId, userDTO.getTenantId())
.like(StrUtil.isNotBlank(userDTO.getUsername()), SysUser::getUsername, userDTO.getUsername())));
}
TenantBroker.runAs(tenantUserDTO.getTenantId(), (tenantId -> {
// 删除用户岗位
sysUserPostMapper.delete(Wrappers.<SysUserPost>lambdaQuery().in(SysUserPost::getUserId, userIdList));
// 删除用户角色
sysUserRoleMapper.delete(Wrappers.<SysUserRole>lambdaQuery().in(SysUserRole::getUserId, userIdList));
// 删除用户部门
sysUserDeptMapper.delete(Wrappers.<SysUserDept>lambdaQuery().in(SysUserDept::getUserId, userIdList));
}));
return Boolean.TRUE;
}
/**
* 保存租户用户信息
* @param tenantUserDTO 租户用户信息DTO
* @return 保存是否成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean saveTenantUser(SysTenantUserDTO tenantUserDTO) {
TenantBroker.runAs(tenantUserDTO.getTenantId(), (tenantId -> {
for (Long userId : tenantUserDTO.getUserIds()) {
List<SysTenantUser> sysTenantUsers = sysTenantUserMapper
.selectList(Wrappers.<SysTenantUser>lambdaQuery()
.eq(SysTenantUser::getTenantId, tenantId)
.eq(SysTenantUser::getUserId, userId));
if (CollUtil.isEmpty(sysTenantUsers)) {
// 插入租户用户关系
SysTenantUser sysTenantUser = new SysTenantUser();
sysTenantUser.setUserId(userId);
sysTenantUser.setTenantId(tenantId);
sysTenantUserMapper.insert(sysTenantUser);
}
/**
* 根据用户信息查询租户用户列表
*
* @param userDTO 用户信息传输对象
* @return 租户用户列表
*/
@Override
public List<SysUser> listTenantUser(UserDTO userDTO) {
return TenantBroker.noneAs(() -> sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery()
.like(StrUtil.isNotBlank(userDTO.getUsername()), SysUser::getUsername, userDTO.getUsername())));
}
List<SysUserRole> userRoleList = sysUserRoleMapper.selectList(Wrappers.<SysUserRole>lambdaQuery()
.eq(SysUserRole::getUserId, userId)
.eq(SysUserRole::getRoleId, tenantUserDTO.getRoleId()));
if (CollUtil.isEmpty(userRoleList)) {
// 插入用户角色关系
SysUserRole sysUserRole = new SysUserRole();
sysUserRole.setUserId(userId);
sysUserRole.setRoleId(tenantUserDTO.getRoleId());
sysUserRoleMapper.insert(sysUserRole);
}
/**
* 保存租户用户信息
*
* @param tenantUserDTO 租户用户信息DTO
* @return 保存是否成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean saveTenantUser(SysTenantUserDTO tenantUserDTO) {
TenantBroker.runAs(tenantUserDTO.getTenantId(), (tenantId -> {
for (Long userId : tenantUserDTO.getUserIds()) {
List<SysTenantUser> sysTenantUsers = sysTenantUserMapper
.selectList(Wrappers.<SysTenantUser>lambdaQuery()
.eq(SysTenantUser::getTenantId, tenantId)
.eq(SysTenantUser::getUserId, userId));
if (CollUtil.isEmpty(sysTenantUsers)) {
// 插入租户用户关系
SysTenantUser sysTenantUser = new SysTenantUser();
sysTenantUser.setUserId(userId);
sysTenantUser.setTenantId(tenantId);
sysTenantUserMapper.insert(sysTenantUser);
}
List<SysUserDept> userDeptList = sysUserDeptMapper.selectList(Wrappers.<SysUserDept>lambdaQuery()
.eq(SysUserDept::getUserId, userId)
.eq(SysUserDept::getDeptId, tenantUserDTO.getDeptId()));
List<SysUserRole> userRoleList = sysUserRoleMapper.selectList(Wrappers.<SysUserRole>lambdaQuery()
.eq(SysUserRole::getUserId, userId)
.eq(SysUserRole::getRoleId, tenantUserDTO.getRoleId()));
if (CollUtil.isEmpty(userRoleList)) {
// 插入用户角色关系
SysUserRole sysUserRole = new SysUserRole();
sysUserRole.setUserId(userId);
sysUserRole.setRoleId(tenantUserDTO.getRoleId());
sysUserRoleMapper.insert(sysUserRole);
}
if (CollUtil.isEmpty(userDeptList)) {
// 插入用户部门关系
SysUserDept sysUserDept = new SysUserDept();
sysUserDept.setUserId(userId);
sysUserDept.setDeptId(tenantUserDTO.getDeptId());
sysUserDeptMapper.insert(sysUserDept);
}
List<SysUserDept> userDeptList = sysUserDeptMapper.selectList(Wrappers.<SysUserDept>lambdaQuery()
.eq(SysUserDept::getUserId, userId)
.eq(SysUserDept::getDeptId, tenantUserDTO.getDeptId()));
List<SysUserPost> userPostList = sysUserPostMapper.selectList(Wrappers.<SysUserPost>lambdaQuery()
.eq(SysUserPost::getUserId, userId)
.eq(SysUserPost::getPostId, tenantUserDTO.getPostId()));
if (CollUtil.isEmpty(userDeptList)) {
// 插入用户部门关系
SysUserDept sysUserDept = new SysUserDept();
sysUserDept.setUserId(userId);
sysUserDept.setDeptId(tenantUserDTO.getDeptId());
sysUserDeptMapper.insert(sysUserDept);
}
if (CollUtil.isEmpty(userPostList) && Objects.nonNull(tenantUserDTO.getPostId())) {
// 插入用户岗位关系
SysUserPost sysUserPost = new SysUserPost();
sysUserPost.setUserId(userId);
sysUserPost.setPostId(tenantUserDTO.getPostId());
sysUserPostMapper.insert(sysUserPost);
}
}
}));
return Boolean.TRUE;
}
List<SysUserPost> userPostList = sysUserPostMapper.selectList(Wrappers.<SysUserPost>lambdaQuery()
.eq(SysUserPost::getUserId, userId)
.eq(SysUserPost::getPostId, tenantUserDTO.getPostId()));
/**
* 获取租户角色列表
* @param userDTO 用户信息
* @return 租户角色列表
*/
@Override
public Map<String, Object> listTenantOrg(UserDTO userDTO) {
return TenantBroker.applyAs(userDTO.getTenantId(), tenantId -> {
// 过滤有权限配置的菜单
List<SysRole> sysRoles = sysRoleMapper.selectList(Wrappers.lambdaQuery())
.stream()
.filter(role -> roleMenuMapper
.exists(Wrappers.<SysRoleMenu>lambdaQuery().eq(SysRoleMenu::getRoleId, role.getRoleId())))
.toList();
List<SysDept> sysDepts = sysDeptMapper.selectList(Wrappers.lambdaQuery());
List<SysPost> sysPosts = sysPostMapper.selectList(Wrappers.lambdaQuery());
return Map.of("sysRoles", sysRoles, "sysDepts", sysDepts, "sysPosts", sysPosts);
});
}
if (CollUtil.isEmpty(userPostList) && Objects.nonNull(tenantUserDTO.getPostId())) {
// 插入用户岗位关系
SysUserPost sysUserPost = new SysUserPost();
sysUserPost.setUserId(userId);
sysUserPost.setPostId(tenantUserDTO.getPostId());
sysUserPostMapper.insert(sysUserPost);
}
}
}));
return Boolean.TRUE;
}
/**
* 移除租户
* @param ids 租户ID列表
* @return 是否移除成功
*/
@Override
@CacheEvict(value = CacheConstants.TENANT_DETAILS, allEntries = true)
public Boolean removeTenant(Long[] ids) {
baseMapper.deleteByIds(CollUtil.toList(ids));
sysTenantUserMapper
.delete(Wrappers.<SysTenantUser>lambdaQuery().in(SysTenantUser::getTenantId, CollUtil.toList(ids)));
return Boolean.TRUE;
}
/**
* 获取租户角色列表
*
* @param userDTO 用户信息
* @return 租户角色列表
*/
@Override
public Map<String, Object> listTenantOrg(UserDTO userDTO) {
return TenantBroker.applyAs(userDTO.getTenantId(), tenantId -> {
// 过滤有权限配置的菜单
List<SysRole> sysRoles = sysRoleMapper.selectList(Wrappers.lambdaQuery())
.stream()
.filter(role -> roleMenuMapper
.exists(Wrappers.<SysRoleMenu>lambdaQuery().eq(SysRoleMenu::getRoleId, role.getRoleId())))
.toList();
List<SysDept> sysDepts = sysDeptMapper.selectList(Wrappers.lambdaQuery());
List<SysPost> sysPosts = sysPostMapper.selectList(Wrappers.lambdaQuery());
return Map.of("sysRoles", sysRoles, "sysDepts", sysDepts, "sysPosts", sysPosts);
});
}
/**
* 更新用户租户信息
* @param userDto 用户数据传输对象
* @return 更新结果
*/
@Override
@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
public R updateUserTenant(UserDTO userDto) {
return R.ok(TenantBroker.noneAs(() -> sysUserMapper.update(Wrappers.<SysUser>lambdaUpdate()
.set(SysUser::getTenantId, userDto.getTenantId())
.eq(SysUser::getUserId, userDto.getUserId()))));
}
/**
* 移除租户
*
* @param ids 租户ID列表
* @return 是否移除成功
*/
@Override
@CacheEvict(value = CacheConstants.TENANT_DETAILS, allEntries = true)
public Boolean removeTenant(Long[] ids) {
baseMapper.deleteByIds(CollUtil.toList(ids));
sysTenantUserMapper
.delete(Wrappers.<SysTenantUser>lambdaQuery().in(SysTenantUser::getTenantId, CollUtil.toList(ids)));
return Boolean.TRUE;
}
/**
* 保存新的租户菜单,维护成新的菜单
* @param menuList 菜单列表
* @param originParentId 原始上级
* @param targetParentId 目标上级
*/
private void saveTenantMenu(List<SysMenu> menuList, Long originParentId, Long targetParentId) {
menuList.stream().filter(menu -> menu.getParentId().equals(originParentId)).forEach(menu -> {
// 保存菜单原始menuId, 方便查询子节点使用
Long originMenuId = menu.getMenuId();
menu.setMenuId(null);
menu.setParentId(targetParentId);
menuService.save(menu);
// 查找此节点的子节点,然后子节点的重新插入父节点更改为新的menuId
saveTenantMenu(menuList, originMenuId, menu.getMenuId());
});
}
/**
* 更新用户租户信息
*
* @param userDto 用户数据传输对象
* @return 更新结果
*/
@Override
@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
public R updateUserTenant(UserDTO userDto) {
return R.ok(TenantBroker.noneAs(() -> sysUserMapper.update(Wrappers.<SysUser>lambdaUpdate()
.set(SysUser::getTenantId, userDto.getTenantId())
.eq(SysUser::getUserId, userDto.getUserId()))));
}
/**
* 获取或更新当前用户的租户信息
* @return 更新后的租户ID,如果无需更新则返回null
*/
@Override
public Long getOrUpdateTenant() {
PigxUser loginUser = SecurityUtils.getUser();
boolean match = this.getNormalTenant()
.stream()
.filter(tenant -> tenant.getStartTime().isBefore(LocalDateTime.now()))
.filter(tenant -> tenant.getEndTime().isAfter(LocalDateTime.now()))
.anyMatch(tenant -> tenant.getId().equals(loginUser.getTenantId()));
/**
* 保存新的租户菜单,维护成新的菜单
*
* @param menuList 菜单列表
* @param originParentId 原始上级
* @param targetParentId 目标上级
*/
private void saveTenantMenu(List<SysMenu> menuList, Long originParentId, Long targetParentId) {
menuList.stream().filter(menu -> menu.getParentId().equals(originParentId)).forEach(menu -> {
// 保存菜单原始menuId, 方便查询子节点使用
Long originMenuId = menu.getMenuId();
menu.setMenuId(null);
menu.setParentId(targetParentId);
menuService.save(menu);
// 查找此节点的子节点,然后子节点的重新插入父节点更改为新的menuId
saveTenantMenu(menuList, originMenuId, menu.getMenuId());
});
}
if (!match) {
SysTenantUser tenantUser = sysTenantUserMapper.selectOne(Wrappers.<SysTenantUser>lambdaQuery()
.eq(SysTenantUser::getUserId, SecurityUtils.getUser().getId())
.ne(SysTenantUser::getTenantId, loginUser.getTenantId()), false);
// 如果当前用户没有租户信息,则不进行任何操作
if (Objects.isNull(tenantUser)) {
return null;
}
/**
* 获取或更新当前用户的租户信息
* <p>
* 如果当前租户已过期或无效,则自动切换到用户的其他有效租户
*
* @return 当前有效的租户对象,如果无有效租户则返回null
*/
@Override
public SysTenant getOrUpdateTenant() {
PigxUser loginUser = SecurityUtils.getUser();
// 通过代理对象调用以确保 @Cacheable 生效,避免自调用导致缓存失效
List<SysTenant> normalTenantList = SpringContextHolder.getBean(SysTenantService.class)
.getNormalTenant()
.stream()
.filter(tenant -> tenant.getStartTime().isBefore(LocalDateTime.now()))
.filter(tenant -> tenant.getEndTime().isAfter(LocalDateTime.now()))
.toList();
// 切换至状态正常的租户
UserDTO userDTO = new UserDTO();
userDTO.setUserId(loginUser.getId());
userDTO.setTenantId(tenantUser.getTenantId());
userDTO.setUsername(loginUser.getUsername());
updateUserTenant(userDTO);
cacheManager.getCache(CacheConstants.USER_DETAILS).evict(loginUser.getUsername());
return tenantUser.getTenantId();
}
boolean match = normalTenantList.stream()
.anyMatch(tenant -> tenant.getId().equals(loginUser.getTenantId()));
return null;
}
if (match) {
// 当前租户有效,返回当前租户对象
return normalTenantList.stream()
.filter(tenant -> tenant.getId().equals(loginUser.getTenantId()))
.findFirst()
.orElse(null);
}
SysTenantUser tenantUser = sysTenantUserMapper.selectOne(Wrappers.<SysTenantUser>lambdaQuery()
.eq(SysTenantUser::getUserId, SecurityUtils.getUser().getId())
.ne(SysTenantUser::getTenantId, loginUser.getTenantId()), false);
// 如果当前用户没有租户信息,则不进行任何操作
if (Objects.isNull(tenantUser)) {
return null;
}
// 切换至状态正常的租户
UserDTO userDTO = new UserDTO();
userDTO.setUserId(loginUser.getId());
userDTO.setTenantId(tenantUser.getTenantId());
userDTO.setUsername(loginUser.getUsername());
updateUserTenant(userDTO);
cacheManager.getCache(CacheConstants.USER_DETAILS).evict(loginUser.getUsername());
// 返回切换后的租户对象
return normalTenantList.stream()
.filter(tenant -> tenant.getId().equals(tenantUser.getTenantId()))
.findFirst()
.orElseGet(() -> baseMapper.selectById(tenantUser.getTenantId()));
}
}
@@ -545,36 +580,36 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
@Data
class TenantDefaultConfig {
private Long tenantDefaultId = 1L;
private Long tenantDefaultId = 1L;
private String tenantDefaultDeptname = "租户默认部门";
private String tenantDefaultDeptname = "租户默认部门";
private String tenantDefaultUsername = "admin";
private String tenantDefaultUsername = "admin";
private String tenantDefaultPassword = "123456";
private String tenantDefaultPassword = "123456";
private String tenantDefaultRolecode = "ROLE_ADMIN";
private String tenantDefaultRolecode = "ROLE_ADMIN";
private String tenantDefaultRolename = "租户默认角色";
private String tenantDefaultRolename = "租户默认角色";
private String userDefaultRolecode = "GENERAL_USER";
private String userDefaultRolecode = "GENERAL_USER";
private String userDefaultRolename = "普通用户";
private String userDefaultRolename = "普通用户";
@SneakyThrows
public TenantDefaultConfig() {
List<String> args = Arrays.stream(ReflectUtil.getFields(this.getClass()))
.map(Field::getName)
.map(StrUtil::toUnderlineCase)
.map(String::toUpperCase)
.toList();
Map<String, Object> paramsMap = ParamResolver.getMap(args.toArray(new String[] {}));
for (Field field : ReflectUtil.getFields(this.getClass())) {
String key = StrUtil.toUnderlineCase(field.getName()).toUpperCase();
if (paramsMap.containsKey(key)) {
field.set(this, paramsMap.get(key));
}
}
}
@SneakyThrows
public TenantDefaultConfig() {
List<String> args = Arrays.stream(ReflectUtil.getFields(this.getClass()))
.map(Field::getName)
.map(StrUtil::toUnderlineCase)
.map(String::toUpperCase)
.toList();
Map<String, Object> paramsMap = ParamResolver.getMap(args.toArray(new String[]{}));
for (Field field : ReflectUtil.getFields(this.getClass())) {
String key = StrUtil.toUnderlineCase(field.getName()).toUpperCase();
if (paramsMap.containsKey(key)) {
field.set(this, paramsMap.get(key));
}
}
}
}
@@ -202,9 +202,10 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
// 如果是登录成功以后查询租户信息并进行校验
if (Objects.nonNull(SecurityUtils.getUser())) {
Long updateTenantId = sysTenantService.getOrUpdateTenant();
if (Objects.nonNull(updateTenantId)) {
userInfo.setTenantId(updateTenantId);
SysTenant updateTenant = sysTenantService.getOrUpdateTenant();
if (Objects.nonNull(updateTenant)) {
userInfo.setTenantId(updateTenant.getId());
userInfo.setTenantName(updateTenant.getName());
}
}