feat(database): 重构用户角色关联及权限体系
- 新增 BizException 构造函数支持自定义消息 - 优化 SQL 脚本结构,明确表设计最佳实践 - 修改 t_user、t_role 等表字段类型与索引策略 - 引入代理主键 id 到关联表 t_user_role 和 t_role_permission - 更新 UserRole 实体类适配 MyBatis-Plus 主键策略 - 增强 UserRoleService 接口功能,支持分配和撤销角色 - 实现批量操作和事务控制提升数据一致性 - 添加安全注解 @PreAuthorize 控制接口访问权限 - 修正 Mapper 注解并优化参数命名提高可读性 - 扩展 ErrorCode 常量增强错误描述准确性
This commit is contained in:
@@ -6,37 +6,87 @@ import cn.nopj.chaos_api.domain.entity.UserRole;
|
||||
import cn.nopj.chaos_api.dto.request.SetUserRoleRequest;
|
||||
import cn.nopj.chaos_api.mapper.UserRoleMapper;
|
||||
import cn.nopj.chaos_api.service.UserRoleService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class UserRoleServiceImpl implements UserRoleService {
|
||||
|
||||
@Autowired
|
||||
private UserRoleMapper userRoleMapper;
|
||||
// 继承 ServiceImpl<UserRoleMapper, UserRole> 以获得批量操作能力
|
||||
public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRole> implements UserRoleService {
|
||||
|
||||
/**
|
||||
* 批量分配角色给用户。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void assignRolesToUser(SetUserRoleRequest request) {
|
||||
if (request == null || request.getUserId() == null || request.getUserId() <= 0L){
|
||||
throw new BizException(ErrorCode.USER_ID_INVALID);
|
||||
}
|
||||
Long userId = request.getUserId();
|
||||
|
||||
public void setUserRole(Long userId, List<Long> roles_id) {
|
||||
if (request.getRolesId() == null || request.getRolesId().isEmpty()){
|
||||
this.baseMapper.delete(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId,userId));
|
||||
return;
|
||||
}
|
||||
|
||||
for (Long role_id : roles_id) {
|
||||
if (role_id == null || role_id == 0L) {
|
||||
throw new BizException(ErrorCode.ROLE_ID_INVALID);
|
||||
}else {
|
||||
userRoleMapper.insert(new UserRole(userId, role_id));
|
||||
List<Long> rolesId = request.getRolesId();
|
||||
|
||||
// 1. 数据预校验:确保没有无效角色ID (0或null)
|
||||
if (rolesId.stream().anyMatch(roleId -> roleId == null || roleId <= 0L)) {
|
||||
throw new BizException(ErrorCode.ROLE_ID_INVALID);
|
||||
}
|
||||
|
||||
// 2. 构建批量插入列表
|
||||
List<UserRole> userRoleList = rolesId.stream()
|
||||
.map(roleId -> {
|
||||
var userRole = new UserRole();
|
||||
userRole.setUserId(userId);
|
||||
userRole.setRoleId(roleId);
|
||||
return userRole;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
try {
|
||||
|
||||
// 替代:先删除用户所有旧角色,再插入新的角色集合 (常用授权模式)
|
||||
this.remove(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, userId));
|
||||
|
||||
// 保持原有逻辑:只添加新的角色
|
||||
boolean success = this.saveBatch(userRoleList);
|
||||
|
||||
if (!success) {
|
||||
// saveBatch 返回 false,通常是 MyBatis-Plus 内部错误或部分失败
|
||||
throw new BizException("批量分配角色操作失败。");
|
||||
}
|
||||
} catch (DataIntegrityViolationException e) {
|
||||
// 捕获数据完整性约束失败 (如外键约束失败: role_id 不存在)
|
||||
log.error("分配角色时外键约束失败: userId={}, rolesId={}", userId, rolesId, e);
|
||||
|
||||
// 给出更具体的提示,可能需要检查是哪个 role_id 不存在
|
||||
throw new BizException("分配角色失败:列表中包含一个或多个不存在的角色ID。");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量解除用户的角色关联。
|
||||
* 优化点: 使用 MyBatis-Plus 的批量删除,而不是在循环中单次删除。
|
||||
* @param request 包含用户ID和角色ID列表
|
||||
* @return 实际解除关联的记录数
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void setUserRole(SetUserRoleRequest request) {
|
||||
if (request == null || request.getUserId() == null ){
|
||||
public int revokeRolesFromUser(SetUserRoleRequest request) {
|
||||
if (request == null || request.getUserId() == null || request.getUserId() <= 0L){
|
||||
throw new BizException(ErrorCode.USER_ID_INVALID);
|
||||
}
|
||||
if (request.getRolesId() == null || request.getRolesId().isEmpty()){
|
||||
@@ -44,7 +94,22 @@ public class UserRoleServiceImpl implements UserRoleService {
|
||||
}
|
||||
|
||||
Long userId = request.getUserId();
|
||||
List<Long> roles_id = request.getRolesId();
|
||||
setUserRole(userId, roles_id);
|
||||
List<Long> rolesId = request.getRolesId();
|
||||
|
||||
|
||||
LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(UserRole::getUserId, userId)
|
||||
.in(UserRole::getRoleId, rolesId); // 批量删除指定的角色ID
|
||||
|
||||
|
||||
int count = this.baseMapper.delete(wrapper);
|
||||
|
||||
if (count == 0 && !rolesId.isEmpty()){
|
||||
// 如果用户传入了角色ID列表但删除了 0 行,可能是这些角色未分配给该用户
|
||||
log.warn("用户 {} 解除角色 {} 失败,0条记录被删除。", userId, rolesId);
|
||||
throw new BizException("解除角色失败,用户可能未分配这些角色。");
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user