1.修复当有用户使用某个角色时,该角色也可以被禁用的BUG

2.引入热部署依赖,配置开启热部署(热更新快捷键:Ctrl+F9)
This commit is contained in:
dk
2026-04-07 11:14:28 +08:00
parent db96a8efa1
commit 7e22f79b5f
6 changed files with 98 additions and 38 deletions

View File

@@ -118,6 +118,15 @@
<artifactId>rdms-spring-boot-starter-websocket</artifactId>
<version>${revision}</version>
</dependency>
<!-- 热部署依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>${spring.boot.version}</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
</dependencies>
</dependencyManagement>

View File

@@ -39,6 +39,7 @@ public interface ErrorCodeConstants {
ErrorCode ROLE_CAN_NOT_DELETE_SYSTEM_TYPE_ROLE = new ErrorCode(1_002_002_003, "不能删除类型为系统内置的角色");
ErrorCode ROLE_IS_DISABLE = new ErrorCode(1_002_002_004, "名字为【{}】的角色已被禁用");
ErrorCode ROLE_ADMIN_CODE_ERROR = new ErrorCode(1_002_002_005, "标识【{}】不能使用");
ErrorCode ROLE_DISABLE_NOT_ALLOWED = new ErrorCode(1_002_005_006, "该角色还有用户在使用,不允许禁用");
// ========== 用户模块 1-002-003-000 ==========
ErrorCode USER_USERNAME_EXISTS = new ErrorCode(1_002_003_000, "用户账号已经存在");
@@ -70,6 +71,7 @@ public interface ErrorCodeConstants {
ErrorCode POST_NAME_DUPLICATE = new ErrorCode(1_002_005_002, "已经存在该名字的岗位");
ErrorCode POST_CODE_DUPLICATE = new ErrorCode(1_002_005_003, "已经存在该标识的岗位");
ErrorCode POST_TYPE_INVALID = new ErrorCode(1_002_005_004, "岗位类型({})不合法");
ErrorCode POST_DISABLE_NOT_ALLOWED = new ErrorCode(1_002_005_005, "该岗位还有用户在使用,不允许禁用");
// ========== 字典类型 1-002-006-000 ==========
ErrorCode DICT_TYPE_NOT_EXISTS = new ErrorCode(1_002_006_001, "当前字典类型不存在");

View File

@@ -31,8 +31,6 @@
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.njcn</groupId>
<artifactId>rdms-spring-boot-starter-biz-ip</artifactId>
@@ -79,8 +77,6 @@
<artifactId>rdms-spring-boot-starter-websocket</artifactId>
</dependency>
<!-- 消息队列相关 -->
<dependency>
<groupId>com.njcn</groupId>
@@ -125,6 +121,13 @@
<artifactId>s3</artifactId>
</dependency>
<!-- 热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
</dependencies>
<build>
@@ -136,6 +139,9 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<configuration>
<addResources>true</addResources> <!-- 开启热部署必须配置 -->
</configuration>
<executions>
<execution>
<goals>

View File

@@ -2,13 +2,16 @@ package com.njcn.rdms.module.system.service.dept;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.dept.vo.post.PostPageReqVO;
import com.njcn.rdms.module.system.controller.admin.dept.vo.post.PostSaveReqVO;
import com.njcn.rdms.module.system.dal.dataobject.dept.PostDO;
import com.njcn.rdms.module.system.dal.dataobject.user.AdminUserDO;
import com.njcn.rdms.module.system.dal.mysql.dept.PostMapper;
import com.njcn.rdms.module.system.dal.mysql.user.AdminUserMapper;
import com.njcn.rdms.module.system.enums.dept.PostTypeEnum;
import com.google.common.annotations.VisibleForTesting;
import jakarta.annotation.Resource;
@@ -36,6 +39,9 @@ public class PostServiceImpl implements PostService {
@Resource
private PostMapper postMapper;
@Resource
private AdminUserMapper userMapper;
@Override
public Long createPost(PostSaveReqVO createReqVO) {
// 校验正确性
@@ -52,6 +58,10 @@ public class PostServiceImpl implements PostService {
// 校验正确性
validatePostForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getName(), updateReqVO.getCode(), updateReqVO.getPostType());
//如果前端想要禁用,则去校验能否被禁用
if (updateReqVO.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) {
VerifyDoDisable(updateReqVO.getId());
}
// 更新岗位
PostDO updateObj = BeanUtils.toBean(updateReqVO, PostDO.class);
postMapper.updateById(updateObj);
@@ -130,6 +140,41 @@ public class PostServiceImpl implements PostService {
}
}
private void VerifyDoDisable(Long id) {
/*
通过岗位id去检查是否有用户在使用该岗位position_id = id
1.只查deleted = 0的即没被删除的用户
2.无论用户是被禁用还是正常的status = 0 | 1只要有用户使用该岗位则不能被禁用
*/
QueryWrapper<AdminUserDO> wrapper = new QueryWrapper<>();
wrapper.eq("deleted", false)
.eq("position_id", id);
Long res = userMapper.selectCount(wrapper);
if (res > 0) {
throw exception(POST_DISABLE_NOT_ALLOWED);
}
}
@Override
public void validatePostList(Collection<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return;
}
// 获得岗位信息
List<PostDO> posts = postMapper.selectByIds(ids);
Map<Long, PostDO> postMap = convertMap(posts, PostDO::getId);
// 校验
ids.forEach(id -> {
PostDO post = postMap.get(id);
if (post == null) {
throw exception(POST_NOT_FOUND);
}
if (!CommonStatusEnum.ENABLE.getStatus().equals(post.getStatus())) {
throw exception(POST_NOT_ENABLE, post.getName());
}
});
}
@Override
public List<PostDO> getPostList(Collection<Long> ids) {
if (CollUtil.isEmpty(ids)) {
@@ -152,24 +197,4 @@ public class PostServiceImpl implements PostService {
public PostDO getPost(Long id) {
return postMapper.selectById(id);
}
@Override
public void validatePostList(Collection<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return;
}
// 获得岗位信息
List<PostDO> posts = postMapper.selectByIds(ids);
Map<Long, PostDO> postMap = convertMap(posts, PostDO::getId);
// 校验
ids.forEach(id -> {
PostDO post = postMap.get(id);
if (post == null) {
throw exception(POST_NOT_FOUND);
}
if (!CommonStatusEnum.ENABLE.getStatus().equals(post.getStatus())) {
throw exception(POST_NOT_ENABLE, post.getName());
}
});
}
}

View File

@@ -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.QueryWrapper;
import com.google.common.annotations.VisibleForTesting;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.service.impl.DiffParseFunction;
@@ -16,7 +17,9 @@ import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.permission.vo.role.RolePageReqVO;
import com.njcn.rdms.module.system.controller.admin.permission.vo.role.RoleSaveReqVO;
import com.njcn.rdms.module.system.dal.dataobject.permission.RoleDO;
import com.njcn.rdms.module.system.dal.dataobject.permission.UserRoleDO;
import com.njcn.rdms.module.system.dal.mysql.permission.RoleMapper;
import com.njcn.rdms.module.system.dal.mysql.permission.UserRoleMapper;
import com.njcn.rdms.module.system.dal.redis.RedisKeyConstants;
import com.njcn.rdms.module.system.enums.permission.RoleCodeEnum;
import com.njcn.rdms.module.system.enums.permission.RoleTypeEnum;
@@ -35,19 +38,8 @@ import java.util.Map;
import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.njcn.rdms.framework.common.util.collection.CollectionUtils.convertMap;
import static com.njcn.rdms.module.system.enums.ErrorCodeConstants.ROLE_ADMIN_CODE_ERROR;
import static com.njcn.rdms.module.system.enums.ErrorCodeConstants.ROLE_CAN_NOT_DELETE_SYSTEM_TYPE_ROLE;
import static com.njcn.rdms.module.system.enums.ErrorCodeConstants.ROLE_CODE_DUPLICATE;
import static com.njcn.rdms.module.system.enums.ErrorCodeConstants.ROLE_IS_DISABLE;
import static com.njcn.rdms.module.system.enums.ErrorCodeConstants.ROLE_NAME_DUPLICATE;
import static com.njcn.rdms.module.system.enums.ErrorCodeConstants.ROLE_NOT_EXISTS;
import static com.njcn.rdms.module.system.enums.LogRecordConstants.SYSTEM_ROLE_CREATE_SUB_TYPE;
import static com.njcn.rdms.module.system.enums.LogRecordConstants.SYSTEM_ROLE_CREATE_SUCCESS;
import static com.njcn.rdms.module.system.enums.LogRecordConstants.SYSTEM_ROLE_DELETE_SUB_TYPE;
import static com.njcn.rdms.module.system.enums.LogRecordConstants.SYSTEM_ROLE_DELETE_SUCCESS;
import static com.njcn.rdms.module.system.enums.LogRecordConstants.SYSTEM_ROLE_TYPE;
import static com.njcn.rdms.module.system.enums.LogRecordConstants.SYSTEM_ROLE_UPDATE_SUB_TYPE;
import static com.njcn.rdms.module.system.enums.LogRecordConstants.SYSTEM_ROLE_UPDATE_SUCCESS;
import static com.njcn.rdms.module.system.enums.ErrorCodeConstants.*;
import static com.njcn.rdms.module.system.enums.LogRecordConstants.*;
@Service
@Slf4j
@@ -59,6 +51,9 @@ public class RoleServiceImpl implements RoleService {
@Resource
private RoleMapper roleMapper;
@Resource
private UserRoleMapper userRoleMapper;
@Override
@Transactional(rollbackFor = Exception.class)
@LogRecord(type = SYSTEM_ROLE_TYPE, subType = SYSTEM_ROLE_CREATE_SUB_TYPE, bizNo = "{{#role.id}}",
@@ -84,6 +79,11 @@ public class RoleServiceImpl implements RoleService {
String effectiveCode = shouldPreserveBuiltInCode(role) ? role.getCode() : updateReqVO.getCode();
validateRoleDuplicate(updateReqVO.getName(), effectiveCode, updateReqVO.getId());
//如果前端想要禁用,则去校验能否被禁用
if (updateReqVO.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) {
VerifyDoDisable(updateReqVO.getId());
}
RoleDO updateObj = BeanUtils.toBean(updateReqVO, RoleDO.class);
if (shouldPreserveBuiltInCode(role)) {
updateObj.setCode(role.getCode());
@@ -118,6 +118,21 @@ public class RoleServiceImpl implements RoleService {
ids.forEach(permissionService::processRoleDeleted);
}
private void VerifyDoDisable(Long id) {
/*
通过角色id去检查是否有用户在使用该角色检查system_user_role表
1.只查deleted = 0的即没被删除的记录
2.无论用户是被禁用还是正常的status = 0 | 1只要有用户使用该角色则不能被禁用
*/
QueryWrapper<UserRoleDO> wrapper = new QueryWrapper<>();
wrapper.eq("deleted", false)
.eq("role_id", id);
Long res = userRoleMapper.selectCount(wrapper);
if (res > 0) {
throw exception(ROLE_DISABLE_NOT_ALLOWED);
}
}
@VisibleForTesting
void validateRoleDuplicate(String name, String code, Long id) {
if (RoleCodeEnum.isBuiltIn(code)) {

View File

@@ -32,6 +32,10 @@
redis:
repositories:
enabled: false # 项目未使用到 Spring Data Redis 的 Repository所以直接禁用保证启动速度
# 热部署配置
devtools:
restart:
enabled: true
server:
port: 48081
@@ -40,7 +44,6 @@ logging:
name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径
--- #################### 接口文档配置 ####################
springdoc:
api-docs:
enabled: true # 1. 是否开启 Swagger 接文档的元数据