From 43690bd978ad03a195f9fe57bad2ea2ca91a6e3c Mon Sep 17 00:00:00 2001 From: yanhuiqing Date: Sat, 10 Jan 2026 10:36:58 +0800 Subject: [PATCH] 用户列表 展示角色字段,扩展用户体系方法,角色从缓存获取 --- urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/user/UserController.java | 54 ++++++++++++++++++++++++++++++++++++++++++++++++------ urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/user/vo/user/UserRespVO.java | 3 +++ urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/convert/user/UserConvert.java | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/PermissionService.java | 9 +++++++++ urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/PermissionServiceImpl.java | 18 ++++++++++++++++++ urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/RoleService.java | 8 ++++++++ urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/RoleServiceImpl.java | 32 ++++++++++++++++++++++++++++++++ 7 files changed, 185 insertions(+), 7 deletions(-) diff --git a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/user/UserController.java b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/user/UserController.java index de2f271..2e2481e 100644 --- a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/user/UserController.java +++ b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/user/UserController.java @@ -11,9 +11,12 @@ import com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils; import com.zteits.urbanops.module.system.controller.admin.user.vo.user.*; import com.zteits.urbanops.module.system.convert.user.UserConvert; import com.zteits.urbanops.module.system.dal.dataobject.dept.DeptDO; +import com.zteits.urbanops.module.system.dal.dataobject.permission.RoleDO; import com.zteits.urbanops.module.system.dal.dataobject.user.AdminUserDO; import com.zteits.urbanops.module.system.enums.common.SexEnum; import com.zteits.urbanops.module.system.service.dept.DeptService; +import com.zteits.urbanops.module.system.service.permission.PermissionService; +import com.zteits.urbanops.module.system.service.permission.RoleService; import com.zteits.urbanops.module.system.service.user.AdminUserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -31,6 +34,8 @@ import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; import static com.zteits.urbanops.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static com.zteits.urbanops.framework.common.pojo.CommonResult.success; @@ -47,6 +52,12 @@ public class UserController { @Resource private DeptService deptService; + @Resource + private PermissionService permissionService; + + @Resource + private RoleService roleService; + @PostMapping("/create") @Operation(summary = "新增用户") @PreAuthorize("@ss.hasPermission('system:user:create')") @@ -101,16 +112,47 @@ public class UserController { @Operation(summary = "获得用户分页列表") @PreAuthorize("@ss.hasPermission('system:user:query')") public CommonResult> getUserPage(@Valid UserPageReqVO pageReqVO) { - // 获得用户分页列表 + // 1. 获得用户分页列表(AdminUserDO 是数据库实体) PageResult pageResult = userService.getUserPage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { - return success(new PageResult<>(pageResult.getTotal())); + // 无数据时,返回空分页结果(保持返回结构一致) + return CommonResult.success(new PageResult<>(pageResult.getTotal())); } - // 拼接数据 + + // 2. 提取当前页所有用户ID(用于批量查询,避免N+1查询问题) + List userIdList = pageResult.getList().stream() + .map(AdminUserDO::getId) + .collect(Collectors.toList()); + + // 3. 批量拼接关联数据:部门信息(原有逻辑,保持不变) Map deptMap = deptService.getDeptMap( - convertList(pageResult.getList(), AdminUserDO::getDeptId)); - return success(new PageResult<>(UserConvert.INSTANCE.convertList(pageResult.getList(), deptMap), - pageResult.getTotal())); + pageResult.getList().stream().map(AdminUserDO::getDeptId).collect(Collectors.toList()) + ); + + // 4. 批量拼接关联数据:角色信息(核心修正与完善) + // 4.1 批量获取「用户ID-角色ID列表」的映射(从权限服务获取,批量查询提升效率) + Map> userId2RoleIdListMap = permissionService.getUserRoleIdListByUserIds(userIdList); + // 4.2 提取所有涉及的角色ID,去重后批量查询角色信息(从缓存获取,符合芋道缓存规范) + List allRoleIdList = userId2RoleIdListMap.values().stream() + .flatMap(List::stream) + .distinct() + .collect(Collectors.toList()); + Map roleMap = roleService.getRoleMapFromCache(allRoleIdList); // 批量查询角色缓存,返回「角色ID-角色DO」映射 + // 4.3 封装「用户ID-角色列表」的映射(供转换VO使用) + Map> userId2RoleListMap = userId2RoleIdListMap.entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> entry.getValue().stream() + .map(roleMap::get) // 从角色映射中获取对应RoleDO(可能返回null) + .filter(Objects::nonNull) // 过滤null的RoleDO对象,解决报错核心 + .collect(Collectors.toList()) + )); + + // 5. 转换VO并拼接关联数据(修改转换器,支持接收角色映射) + List userRespVOList = UserConvert.INSTANCE.convertList(pageResult.getList(), deptMap, userId2RoleListMap); + + // 6. 封装并返回结果 + return CommonResult.success(new PageResult<>(userRespVOList, pageResult.getTotal())); } @PostMapping("/listForPage") diff --git a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/user/vo/user/UserRespVO.java b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/user/vo/user/UserRespVO.java index 9cb21ee..93a8666 100644 --- a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/user/vo/user/UserRespVO.java +++ b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/user/vo/user/UserRespVO.java @@ -38,6 +38,9 @@ public class UserRespVO{ @ExcelProperty("部门名称") private String deptName; + @Schema(description = "角色名称") + private String roleNames; + @Schema(description = "岗位编号数组", example = "1") private Set postIds; diff --git a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/convert/user/UserConvert.java b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/convert/user/UserConvert.java index 22fa340..3f32ad8 100644 --- a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/convert/user/UserConvert.java +++ b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/convert/user/UserConvert.java @@ -1,5 +1,6 @@ package com.zteits.urbanops.module.system.convert.user; +import cn.hutool.core.collection.CollUtil; import com.zteits.urbanops.framework.common.util.collection.CollectionUtils; import com.zteits.urbanops.framework.common.util.collection.MapUtils; import com.zteits.urbanops.framework.common.util.object.BeanUtils; @@ -16,14 +17,79 @@ import com.zteits.urbanops.module.system.dal.dataobject.user.AdminUserDO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; +import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; -@Mapper +@Mapper(componentModel = "spring") public interface UserConvert { UserConvert INSTANCE = Mappers.getMapper(UserConvert.class); + /** + * 转换单个用户VO,拼接部门和角色信息 + */ + default UserRespVO convert(AdminUserDO adminUserDO, Map deptMap, Map> userId2RoleListMap) { + // 1. 判空处理,避免空指针 + if (adminUserDO == null) { + return null; + } + // 2. 新建VO对象,手动拷贝所有字段(对应原MapStruct自动映射的同名字段) + UserRespVO userRespVO = BeanUtils.toBean(adminUserDO,UserRespVO.class); + // 3. 手动调用辅助方法,设置拼接后的部门名称和角色名称 + userRespVO.setDeptName(getDeptName(adminUserDO.getDeptId(), deptMap)); + userRespVO.setRoleNames(getRoleNames(adminUserDO.getId(), userId2RoleListMap)); + + return userRespVO; + } + /** + * 批量转换用户VO + */ + default List convertList(List adminUserDOList, Map deptMap, Map> userId2RoleListMap) { + // 1. 判空处理 + if (CollUtil.isEmpty(adminUserDOList)) { + return new ArrayList<>(); + } + + // 2. 遍历单个转换,收集结果 + List userRespVOList = new ArrayList<>(); + for (AdminUserDO adminUserDO : adminUserDOList) { + UserRespVO userRespVO = convert(adminUserDO, deptMap, userId2RoleListMap); + if (userRespVO != null) { + userRespVOList.add(userRespVO); + } + } + + return userRespVOList; + } + /** + * 从部门映射中获取部门名称 + */ + default String getDeptName(Long deptId, Map deptMap) { + if (deptId == null || deptMap == null) { + return null; + } + DeptDO deptDO = deptMap.get(deptId); + return deptDO != null ? deptDO.getName() : null; + } + + /** + * 从角色映射中获取角色名称(拼接为逗号分隔字符串) + */ + default String getRoleNames(Long userId, Map> userId2RoleListMap) { + if (userId == null || userId2RoleListMap == null) { + return null; + } + List roleDOList = userId2RoleListMap.get(userId); + if (CollUtil.isEmpty(roleDOList)) { + return null; + } + // 拼接角色名称为逗号分隔的字符串(如:"管理员,普通用户") + return roleDOList.stream() + .map(RoleDO::getName) + .collect(Collectors.joining(",")); + } default List convertList(List list, Map deptMap) { return CollectionUtils.convertList(list, user -> convert(user, deptMap.get(user.getDeptId()))); } diff --git a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/PermissionService.java b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/PermissionService.java index 0b3e089..4362373 100644 --- a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/PermissionService.java +++ b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/PermissionService.java @@ -3,6 +3,8 @@ package com.zteits.urbanops.module.system.service.permission; import com.zteits.urbanops.framework.common.biz.system.permission.dto.DeptDataPermissionRespDTO; import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.Set; import static java.util.Collections.singleton; @@ -26,6 +28,13 @@ public interface PermissionService { boolean hasAnyPermissions(Long userId, String... permissions); /** + * 获取多个用户的角色信息 + * @param userIdList + * @return + */ + public Map> getUserRoleIdListByUserIds(List userIdList); + + /** * 判断是否有角色,任一一个即可 * * @param roles 角色数组 diff --git a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/PermissionServiceImpl.java b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/PermissionServiceImpl.java index 21cdac4..0be2829 100644 --- a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/PermissionServiceImpl.java +++ b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/PermissionServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.extra.spring.SpringUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.zteits.urbanops.framework.common.enums.CommonStatusEnum; import com.zteits.urbanops.framework.common.util.collection.CollectionUtils; import com.zteits.urbanops.framework.datapermission.core.annotation.DataPermission; @@ -32,6 +33,7 @@ import org.springframework.transaction.annotation.Transactional; import jakarta.annotation.Resource; import java.util.*; import java.util.function.Supplier; +import java.util.stream.Collectors; import static com.zteits.urbanops.framework.common.util.collection.CollectionUtils.convertSet; import static com.zteits.urbanops.framework.common.util.json.JsonUtils.toJsonString; @@ -60,6 +62,22 @@ public class PermissionServiceImpl implements PermissionService { private AdminUserService userService; @Override + public Map> getUserRoleIdListByUserIds(List userIdList) { + if (CollUtil.isEmpty(userIdList)) { + return Collections.emptyMap(); + } + // 查询用户-角色关联数据 + List userRoleDOList = userRoleMapper.selectList(Wrappers.lambdaQuery() + .in(UserRoleDO::getUserId, userIdList)); + // 分组封装为「用户ID-角色ID列表」 + return userRoleDOList.stream() + .collect(Collectors.groupingBy( + UserRoleDO::getUserId, + Collectors.mapping(UserRoleDO::getRoleId, Collectors.toList()) + )); + } + + @Override public boolean hasAnyPermissions(Long userId, String... permissions) { // 如果为空,说明已经有权限 if (ArrayUtil.isEmpty(permissions)) { diff --git a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/RoleService.java b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/RoleService.java index c37568d..fdd3056 100644 --- a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/RoleService.java +++ b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/RoleService.java @@ -9,6 +9,7 @@ import jakarta.validation.Valid; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -19,6 +20,13 @@ import java.util.Set; public interface RoleService { /** + * 从缓存中批量获取角色信息,返回「角色ID-角色DO」的映射 + * @param roleIdList 角色ID列表 + * @return Map 角色ID为key,RoleDO为value + */ + Map getRoleMapFromCache(List roleIdList); + + /** * 创建角色 * * @param createReqVO 创建角色信息 diff --git a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/RoleServiceImpl.java b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/RoleServiceImpl.java index ed00444..2e6379b 100644 --- a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/RoleServiceImpl.java +++ b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/service/permission/RoleServiceImpl.java @@ -5,6 +5,7 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.extra.spring.SpringUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.zteits.urbanops.framework.common.enums.CommonStatusEnum; import com.zteits.urbanops.framework.common.pojo.PageResult; @@ -34,6 +35,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.util.*; +import java.util.stream.Collectors; import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.zteits.urbanops.framework.common.util.collection.CollectionUtils.convertMap; @@ -58,6 +60,36 @@ public class RoleServiceImpl implements RoleService { @Resource private UserRoleMapper userRoleMapper; + /** + * 从缓存中批量获取角色信息,缓存未命中则查询数据库并缓存结果 + */ + @Override + @Cacheable(value = "role", key = "#roleIdList.toString()", unless = "#result.isEmpty()") + // 缓存注解说明: + // value:缓存名称,区分不同模块缓存 + // key:缓存键,用角色ID列表拼接作为唯一键 + // unless:结果为空时不缓存,避免无效缓存 + public Map getRoleMapFromCache(List roleIdList) { + // 1. 空值处理,避免无效查询 + if (CollUtil.isEmpty(roleIdList)) { + return Map.of(); // 返回空不可变Map,避免空指针 + } + + // 2. 批量查询数据库(缓存未命中时执行) + List roleDOList = roleMapper.selectList( + new LambdaQueryWrapper() + .in(RoleDO::getId, roleIdList) // 批量查询,仅一次数据库访问 + ); + + // 3. 转换为「角色ID-角色DO」的Map,方便后续取值 + return roleDOList.stream() + .collect(Collectors.toMap( + RoleDO::getId, // 以角色ID作为key + roleDO -> roleDO, // 以角色DO作为value + (existing, replacement) -> existing // 解决重复ID冲突(取已有值,实际不会出现) + )); + } + @Override @Transactional(rollbackFor = Exception.class) @LogRecord(type = SYSTEM_ROLE_TYPE, subType = SYSTEM_ROLE_CREATE_SUB_TYPE, bizNo = "{{#role.id}}", -- libgit2 0.21.4