Commit 87c7b3fac2c291b45c3537d972d0ac3e690d4342

Authored by YunaiV
1 parent 20583417

【新增】system user 和 role 接入新操作日志

Showing 14 changed files with 232 additions and 108 deletions
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/util/DataPermissionUtils.java
... ... @@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
4 4 import cn.iocoder.yudao.framework.datapermission.core.aop.DataPermissionContextHolder;
5 5 import lombok.SneakyThrows;
6 6  
  7 +import java.util.concurrent.Callable;
  8 +
7 9 /**
8 10 * 数据权限 Util
9 11 *
... ... @@ -40,4 +42,22 @@ public class DataPermissionUtils {
40 42 }
41 43 }
42 44  
  45 + /**
  46 + * 忽略数据权限,执行对应的逻辑
  47 + *
  48 + * @param callable 逻辑
  49 + * @return 执行结果
  50 + */
  51 + @SneakyThrows
  52 + public static <T> T executeIgnore(Callable<T> callable) {
  53 + DataPermission dataPermission = getDisableDataPermissionDisable();
  54 + DataPermissionContextHolder.add(dataPermission);
  55 + try {
  56 + // 执行 callable
  57 + return callable.call();
  58 + } finally {
  59 + DataPermissionContextHolder.remove();
  60 + }
  61 + }
  62 +
43 63 }
... ...
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/LogRecordConstants.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.enums;
  2 +
  3 +/**
  4 + * System 操作日志枚举
  5 + * 目的:统一管理,也减少 Service 里各种“复杂”字符串
  6 + *
  7 + * @author 芋道源码
  8 + */
  9 +public interface LogRecordConstants {
  10 +
  11 + // ======================= SYSTEM_USER 用户 =======================
  12 +
  13 + String SYSTEM_USER_TYPE = "SYSTEM 用户";
  14 + String SYSTEM_USER_CREATE_SUB_TYPE = "创建用户";
  15 + String SYSTEM_USER_CREATE_SUCCESS = "创建了用户【{{#user.nickname}}】";
  16 + String SYSTEM_USER_UPDATE_SUB_TYPE = "更新用户";
  17 + String SYSTEM_USER_UPDATE_SUCCESS = "更新了用户【{{#user.nickname}}】: {_DIFF{#updateReqVO}}";
  18 + String SYSTEM_USER_DELETE_SUB_TYPE = "删除用户";
  19 + String SYSTEM_USER_DELETE_SUCCESS = "删除了用户【{{#user.nickname}}】";
  20 + String SYSTEM_USER_UPDATE_PASSWORD_SUB_TYPE = "重置用户密码";
  21 + String SYSTEM_USER_UPDATE_PASSWORD_SUCCESS = "将用户【{{#user.nickname}}】的密码从【{{#user.password}}】重置为【{{#newPassword}}】";
  22 +
  23 + // ======================= SYSTEM_ROLE 角色 =======================
  24 +
  25 + String SYSTEM_ROLE_TYPE = "SYSTEM 角色";
  26 + String SYSTEM_ROLE_CREATE_SUB_TYPE = "创建角色";
  27 + String SYSTEM_ROLE_CREATE_SUCCESS = "创建了角色【{{#role.name}}】";
  28 + String SYSTEM_ROLE_UPDATE_SUB_TYPE = "更新角色";
  29 + String SYSTEM_ROLE_UPDATE_SUCCESS = "更新了角色【{{#role.name}}】: {_DIFF{#updateReqVO}}";
  30 + String SYSTEM_ROLE_DELETE_SUB_TYPE = "删除角色";
  31 + String SYSTEM_ROLE_DELETE_SUCCESS = "删除了角色【{{#role.name}}】";
  32 +
  33 +}
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/RoleController.java
... ... @@ -52,14 +52,6 @@ public class RoleController {
52 52 return success(true);
53 53 }
54 54  
55   - @PutMapping("/update-status")
56   - @Operation(summary = "修改角色状态")
57   - @PreAuthorize("@ss.hasPermission('system:role:update')")
58   - public CommonResult<Boolean> updateRoleStatus(@Valid @RequestBody RoleUpdateStatusReqVO reqVO) {
59   - roleService.updateRoleStatus(reqVO.getId(), reqVO.getStatus());
60   - return success(true);
61   - }
62   -
63 55 @DeleteMapping("/delete")
64 56 @Operation(summary = "删除角色")
65 57 @Parameter(name = "id", description = "角色编号", required = true, example = "1024")
... ... @@ -87,10 +79,10 @@ public class RoleController {
87 79  
88 80 @GetMapping({"/list-all-simple", "/simple-list"})
89 81 @Operation(summary = "获取角色精简信息列表", description = "只包含被开启的角色,主要用于前端的下拉选项")
90   - public CommonResult<List<RoleSimpleRespVO>> getSimpleRoleList() {
  82 + public CommonResult<List<RoleRespVO>> getSimpleRoleList() {
91 83 List<RoleDO> list = roleService.getRoleListByStatus(singleton(CommonStatusEnum.ENABLE.getStatus()));
92 84 list.sort(Comparator.comparing(RoleDO::getSort));
93   - return success(BeanUtils.toBean(list, RoleSimpleRespVO.class));
  85 + return success(BeanUtils.toBean(list, RoleRespVO.class));
94 86 }
95 87  
96 88 @GetMapping("/export-excel")
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleSaveReqVO.java
1 1 package cn.iocoder.yudao.module.system.controller.admin.permission.vo.role;
2 2  
  3 +import com.mzt.logapi.starter.annotation.DiffLogField;
3 4 import io.swagger.v3.oas.annotations.media.Schema;
4 5 import lombok.Data;
5 6  
... ... @@ -7,7 +8,7 @@ import jakarta.validation.constraints.NotBlank;
7 8 import jakarta.validation.constraints.NotNull;
8 9 import jakarta.validation.constraints.Size;
9 10  
10   -@Schema(description = "管理后台 - 角色创建 Request VO")
  11 +@Schema(description = "管理后台 - 角色创建/更新 Request VO")
11 12 @Data
12 13 public class RoleSaveReqVO {
13 14  
... ... @@ -16,19 +17,23 @@ public class RoleSaveReqVO {
16 17  
17 18 @Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "管理员")
18 19 @NotBlank(message = "角色名称不能为空")
19   - @Size(max = 30, message = "角色名称长度不能超过30个字符")
  20 + @Size(max = 30, message = "角色名称长度不能超过 30 个字符")
  21 + @DiffLogField(name = "角色名称")
20 22 private String name;
21 23  
22 24 @NotBlank(message = "角色标志不能为空")
23   - @Size(max = 100, message = "角色标志长度不能超过100个字符")
  25 + @Size(max = 100, message = "角色标志长度不能超过 100 个字符")
24 26 @Schema(description = "角色编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "ADMIN")
  27 + @DiffLogField(name = "角色标志")
25 28 private String code;
26 29  
27 30 @Schema(description = "显示顺序不能为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
28 31 @NotNull(message = "显示顺序不能为空")
  32 + @DiffLogField(name = "显示顺序")
29 33 private Integer sort;
30 34  
31 35 @Schema(description = "备注", example = "我是一个角色")
  36 + @DiffLogField(name = "备注")
32 37 private String remark;
33 38  
34 39 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleUpdateStatusReqVO.java deleted
1   -package cn.iocoder.yudao.module.system.controller.admin.permission.vo.role;
2   -
3   -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4   -import cn.iocoder.yudao.framework.common.validation.InEnum;
5   -import io.swagger.v3.oas.annotations.media.Schema;
6   -import lombok.Data;
7   -
8   -import jakarta.validation.constraints.NotNull;
9   -
10   -@Schema(description = "管理后台 - 角色更新状态 Request VO")
11   -@Data
12   -public class RoleUpdateStatusReqVO {
13   -
14   - @Schema(description = "角色编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
15   - @NotNull(message = "角色编号不能为空")
16   - private Long id;
17   -
18   - @Schema(description = "状态,见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
19   - @NotNull(message = "状态不能为空")
20   - @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
21   - private Integer status;
22   -
23   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSaveReqVO.java
... ... @@ -2,12 +2,16 @@ package cn.iocoder.yudao.module.system.controller.admin.user.vo.user;
2 2  
3 3 import cn.hutool.core.util.ObjectUtil;
4 4 import cn.iocoder.yudao.framework.common.validation.Mobile;
  5 +import cn.iocoder.yudao.module.system.framework.operatelog.core.DeptParseFunction;
  6 +import cn.iocoder.yudao.module.system.framework.operatelog.core.PostParseFunction;
  7 +import cn.iocoder.yudao.module.system.framework.operatelog.core.SexParseFunction;
5 8 import com.fasterxml.jackson.annotation.JsonIgnore;
  9 +import com.mzt.logapi.starter.annotation.DiffLogField;
6 10 import io.swagger.v3.oas.annotations.media.Schema;
  11 +import jakarta.validation.constraints.*;
7 12 import lombok.Data;
8 13 import org.hibernate.validator.constraints.Length;
9 14  
10   -import jakarta.validation.constraints.*;
11 15 import java.util.Set;
12 16  
13 17 @Schema(description = "管理后台 - 用户创建/修改 Request VO")
... ... @@ -21,34 +25,43 @@ public class UserSaveReqVO {
21 25 @NotBlank(message = "用户账号不能为空")
22 26 @Pattern(regexp = "^[a-zA-Z0-9]{4,30}$", message = "用户账号由 数字、字母 组成")
23 27 @Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符")
  28 + @DiffLogField(name = "用户账号")
24 29 private String username;
25 30  
26 31 @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
27 32 @Size(max = 30, message = "用户昵称长度不能超过30个字符")
  33 + @DiffLogField(name = "用户昵称")
28 34 private String nickname;
29 35  
30 36 @Schema(description = "备注", example = "我是一个用户")
  37 + @DiffLogField(name = "备注")
31 38 private String remark;
32 39  
33   - @Schema(description = "部门ID", example = "我是一个用户")
  40 + @Schema(description = "部门编号", example = "我是一个用户")
  41 + @DiffLogField(name = "部门", function = DeptParseFunction.NAME)
34 42 private Long deptId;
35 43  
36 44 @Schema(description = "岗位编号数组", example = "1")
  45 + @DiffLogField(name = "岗位", function = PostParseFunction.NAME)
37 46 private Set<Long> postIds;
38 47  
39 48 @Schema(description = "用户邮箱", example = "yudao@iocoder.cn")
40 49 @Email(message = "邮箱格式不正确")
41 50 @Size(max = 50, message = "邮箱长度不能超过 50 个字符")
  51 + @DiffLogField(name = "用户邮箱")
42 52 private String email;
43 53  
44 54 @Schema(description = "手机号码", example = "15601691300")
45 55 @Mobile
  56 + @DiffLogField(name = "手机号码")
46 57 private String mobile;
47 58  
48 59 @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1")
  60 + @DiffLogField(name = "用户性别", function = SexParseFunction.NAME)
49 61 private Integer sex;
50 62  
51 63 @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png")
  64 + @DiffLogField(name = "用户头像")
52 65 private String avatar;
53 66  
54 67 // ========== 仅【创建】时,需要传递的字段 ==========
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AdminUserParseFunction.java
1 1 package cn.iocoder.yudao.module.system.framework.operatelog.core;
2 2  
  3 +import cn.hutool.core.convert.Convert;
3 4 import cn.hutool.core.util.StrUtil;
4   -import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
5   -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  5 +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
  6 +import cn.iocoder.yudao.module.system.service.user.AdminUserService;
6 7 import com.mzt.logapi.service.IParseFunction;
7 8 import jakarta.annotation.Resource;
8 9 import lombok.extern.slf4j.Slf4j;
... ... @@ -20,7 +21,7 @@ public class AdminUserParseFunction implements IParseFunction {
20 21 public static final String NAME = "getAdminUserById";
21 22  
22 23 @Resource
23   - private AdminUserApi adminUserApi;
  24 + private AdminUserService adminUserService;
24 25  
25 26 @Override
26 27 public String functionName() {
... ... @@ -34,7 +35,7 @@ public class AdminUserParseFunction implements IParseFunction {
34 35 }
35 36  
36 37 // 获取用户信息
37   - AdminUserRespDTO user = adminUserApi.getUser(Long.parseLong(value.toString()));
  38 + AdminUserDO user = adminUserService.getUser(Convert.toLong(value));
38 39 if (user == null) {
39 40 log.warn("[apply][获取用户{{}}为空", value);
40 41 return "";
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AreaParseFunction.java
1 1 package cn.iocoder.yudao.module.system.framework.operatelog.core;
2 2  
  3 +import cn.hutool.core.convert.Convert;
3 4 import cn.hutool.core.util.StrUtil;
4 5 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
5 6 import com.mzt.logapi.service.IParseFunction;
... ... @@ -32,7 +33,7 @@ public class AreaParseFunction implements IParseFunction {
32 33 if (StrUtil.isEmptyIfStr(value)) {
33 34 return "";
34 35 }
35   - return AreaUtils.format(Integer.parseInt(value.toString()));
  36 + return AreaUtils.format(Convert.toInt(value));
36 37 }
37 38  
38 39 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/DeptParseFunction.java
1 1 package cn.iocoder.yudao.module.system.framework.operatelog.core;
2 2  
  3 +import cn.hutool.core.convert.Convert;
3 4 import cn.hutool.core.util.StrUtil;
4   -import cn.iocoder.yudao.module.system.api.dept.DeptApi;
5   -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
  5 +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
  6 +import cn.iocoder.yudao.module.system.service.dept.DeptService;
6 7 import com.mzt.logapi.service.IParseFunction;
7 8 import jakarta.annotation.Resource;
8 9 import lombok.extern.slf4j.Slf4j;
9 10 import org.springframework.stereotype.Component;
10 11  
11 12 /**
12   - * 管理员名字的 {@link IParseFunction} 实现类
  13 + * 部门名字的 {@link IParseFunction} 实现类
13 14 *
14 15 * @author HUIHUI
15 16 */
... ... @@ -20,7 +21,7 @@ public class DeptParseFunction implements IParseFunction {
20 21 public static final String NAME = "getDeptById";
21 22  
22 23 @Resource
23   - private DeptApi deptApi;
  24 + private DeptService deptService;
24 25  
25 26 @Override
26 27 public String functionName() {
... ... @@ -34,7 +35,7 @@ public class DeptParseFunction implements IParseFunction {
34 35 }
35 36  
36 37 // 获取部门信息
37   - DeptRespDTO dept = deptApi.getDept(Long.parseLong(value.toString()));
  38 + DeptDO dept = deptService.getDept(Convert.toLong(value));
38 39 if (dept == null) {
39 40 log.warn("[apply][获取部门{{}}为空", value);
40 41 return "";
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/PostParseFunction.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.framework.operatelog.core;
  2 +
  3 +import cn.hutool.core.convert.Convert;
  4 +import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
  6 +import cn.iocoder.yudao.module.system.service.dept.PostService;
  7 +import com.mzt.logapi.service.IParseFunction;
  8 +import jakarta.annotation.Resource;
  9 +import lombok.extern.slf4j.Slf4j;
  10 +import org.springframework.stereotype.Component;
  11 +
  12 +/**
  13 + * 岗位名字的 {@link IParseFunction} 实现类
  14 + *
  15 + * @author HUIHUI
  16 + */
  17 +@Slf4j
  18 +@Component
  19 +public class PostParseFunction implements IParseFunction {
  20 +
  21 + public static final String NAME = "getPostById";
  22 +
  23 + @Resource
  24 + private PostService postService;
  25 +
  26 + @Override
  27 + public String functionName() {
  28 + return NAME;
  29 + }
  30 +
  31 + @Override
  32 + public String apply(Object value) {
  33 + if (StrUtil.isEmptyIfStr(value)) {
  34 + return "";
  35 + }
  36 +
  37 + // 获取岗位信息
  38 + PostDO post = postService.getPost(Convert.toLong(value));
  39 + if (post == null) {
  40 + log.warn("[apply][获取岗位{{}}为空", value);
  41 + return "";
  42 + }
  43 + return post.getName();
  44 + }
  45 +
  46 +}
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/package-info.java
  1 +/**
  2 + * 占位文件,避免文件夹缩进
  3 + */
1 4 package cn.iocoder.yudao.module.system.framework.operatelog;
2 5 \ No newline at end of file
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleService.java
... ... @@ -41,14 +41,6 @@ public interface RoleService {
41 41 void deleteRole(Long id);
42 42  
43 43 /**
44   - * 更新角色状态
45   - *
46   - * @param id 角色编号
47   - * @param status 状态
48   - */
49   - void updateRoleStatus(Long id, Integer status);
50   -
51   - /**
52 44 * 设置角色的数据权限
53 45 *
54 46 * @param id 角色编号
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java
... ... @@ -17,6 +17,8 @@ import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;
17 17 import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
18 18 import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
19 19 import com.google.common.annotations.VisibleForTesting;
  20 +import com.mzt.logapi.context.LogRecordContext;
  21 +import com.mzt.logapi.starter.annotation.LogRecord;
20 22 import lombok.extern.slf4j.Slf4j;
21 23 import org.springframework.cache.annotation.CacheEvict;
22 24 import org.springframework.cache.annotation.Cacheable;
... ... @@ -30,6 +32,7 @@ import java.util.*;
30 32 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
31 33 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
32 34 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
  35 +import static cn.iocoder.yudao.module.system.enums.LogRecordConstants.*;
33 36  
34 37 /**
35 38 * 角色 Service 实现类
... ... @@ -48,41 +51,40 @@ public class RoleServiceImpl implements RoleService {
48 51  
49 52 @Override
50 53 @Transactional(rollbackFor = Exception.class)
  54 + @LogRecord(type = SYSTEM_ROLE_TYPE, subType = SYSTEM_ROLE_CREATE_SUB_TYPE, bizNo = "{{#role.id}}",
  55 + success = SYSTEM_ROLE_CREATE_SUCCESS)
51 56 public Long createRole(RoleSaveReqVO createReqVO, Integer type) {
52   - // 校验角色
  57 + // 1. 校验角色
53 58 validateRoleDuplicate(createReqVO.getName(), createReqVO.getCode(), null);
54   - // 插入到数据库
55   - RoleDO role = BeanUtils.toBean(createReqVO, RoleDO.class);
56   - role.setType(ObjectUtil.defaultIfNull(type, RoleTypeEnum.CUSTOM.getType()));
57   - role.setStatus(CommonStatusEnum.ENABLE.getStatus());
58   - role.setDataScope(DataScopeEnum.ALL.getScope()); // 默认可查看所有数据。原因是,可能一些项目不需要项目权限
  59 +
  60 + // 2. 插入到数据库
  61 + RoleDO role = BeanUtils.toBean(createReqVO, RoleDO.class)
  62 + .setType(ObjectUtil.defaultIfNull(type, RoleTypeEnum.CUSTOM.getType()))
  63 + .setStatus(CommonStatusEnum.ENABLE.getStatus())
  64 + .setDataScope(DataScopeEnum.ALL.getScope()); // 默认可查看所有数据。原因是,可能一些项目不需要项目权限
59 65 roleMapper.insert(role);
60   - // 返回
  66 +
  67 + // 3. 记录操作日志上下文
  68 + LogRecordContext.putVariable("role", role);
61 69 return role.getId();
62 70 }
63 71  
64 72 @Override
65 73 @CacheEvict(value = RedisKeyConstants.ROLE, key = "#updateReqVO.id")
  74 + @LogRecord(type = SYSTEM_ROLE_TYPE, subType = SYSTEM_ROLE_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
  75 + success = SYSTEM_ROLE_UPDATE_SUCCESS)
66 76 public void updateRole(RoleSaveReqVO updateReqVO) {
67   - // 校验是否可以更新
68   - validateRoleForUpdate(updateReqVO.getId());
69   - // 校验角色的唯一字段是否重复
  77 + // 1.1 校验是否可以更新
  78 + RoleDO role = validateRoleForUpdate(updateReqVO.getId());
  79 + // 1.2 校验角色的唯一字段是否重复
70 80 validateRoleDuplicate(updateReqVO.getName(), updateReqVO.getCode(), updateReqVO.getId());
71 81  
72   - // 更新到数据库
  82 + // 2. 更新到数据库
73 83 RoleDO updateObj = BeanUtils.toBean(updateReqVO, RoleDO.class);
74 84 roleMapper.updateById(updateObj);
75   - }
76   -
77   - @Override
78   - @CacheEvict(value = RedisKeyConstants.ROLE, key = "#id")
79   - public void updateRoleStatus(Long id, Integer status) {
80   - // 校验是否可以更新
81   - validateRoleForUpdate(id);
82 85  
83   - // 更新状态
84   - RoleDO updateObj = new RoleDO().setId(id).setStatus(status);
85   - roleMapper.updateById(updateObj);
  86 + // 3. 记录操作日志上下文
  87 + LogRecordContext.putVariable("role", role);
86 88 }
87 89  
88 90 @Override
... ... @@ -102,13 +104,19 @@ public class RoleServiceImpl implements RoleService {
102 104 @Override
103 105 @Transactional(rollbackFor = Exception.class)
104 106 @CacheEvict(value = RedisKeyConstants.ROLE, key = "#id")
  107 + @LogRecord(type = SYSTEM_ROLE_TYPE, subType = SYSTEM_ROLE_DELETE_SUB_TYPE, bizNo = "{{#id}}",
  108 + success = SYSTEM_ROLE_DELETE_SUCCESS)
105 109 public void deleteRole(Long id) {
106   - // 校验是否可以更新
107   - validateRoleForUpdate(id);
108   - // 标记删除
  110 + // 1. 校验是否可以更新
  111 + RoleDO role = validateRoleForUpdate(id);
  112 +
  113 + // 2.1 标记删除
109 114 roleMapper.deleteById(id);
110   - // 删除相关数据
  115 + // 2.2 删除相关数据
111 116 permissionService.processRoleDeleted(id);
  117 +
  118 + // 3. 记录操作日志上下文
  119 + LogRecordContext.putVariable("role", role);
112 120 }
113 121  
114 122 /**
... ... @@ -149,15 +157,16 @@ public class RoleServiceImpl implements RoleService {
149 157 * @param id 角色编号
150 158 */
151 159 @VisibleForTesting
152   - void validateRoleForUpdate(Long id) {
153   - RoleDO roleDO = roleMapper.selectById(id);
154   - if (roleDO == null) {
  160 + RoleDO validateRoleForUpdate(Long id) {
  161 + RoleDO role = roleMapper.selectById(id);
  162 + if (role == null) {
155 163 throw exception(ROLE_NOT_EXISTS);
156 164 }
157 165 // 内置角色,不允许删除
158   - if (RoleTypeEnum.SYSTEM.getType().equals(roleDO.getType())) {
  166 + if (RoleTypeEnum.SYSTEM.getType().equals(role.getType())) {
159 167 throw exception(ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE);
160 168 }
  169 + return role;
161 170 }
162 171  
163 172 @Override
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
... ... @@ -27,6 +27,10 @@ import cn.iocoder.yudao.module.system.service.dept.PostService;
27 27 import cn.iocoder.yudao.module.system.service.permission.PermissionService;
28 28 import cn.iocoder.yudao.module.system.service.tenant.TenantService;
29 29 import com.google.common.annotations.VisibleForTesting;
  30 +import com.mzt.logapi.context.LogRecordContext;
  31 +import com.mzt.logapi.service.impl.DiffParseFunction;
  32 +import com.mzt.logapi.starter.annotation.LogRecord;
  33 +import jakarta.annotation.Resource;
30 34 import lombok.extern.slf4j.Slf4j;
31 35 import org.springframework.beans.factory.annotation.Value;
32 36 import org.springframework.context.annotation.Lazy;
... ... @@ -34,7 +38,6 @@ import org.springframework.security.crypto.password.PasswordEncoder;
34 38 import org.springframework.stereotype.Service;
35 39 import org.springframework.transaction.annotation.Transactional;
36 40  
37   -import jakarta.annotation.Resource;
38 41 import java.io.InputStream;
39 42 import java.time.LocalDateTime;
40 43 import java.util.*;
... ... @@ -43,6 +46,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
43 46 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
44 47 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
45 48 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
  49 +import static cn.iocoder.yudao.module.system.enums.LogRecordConstants.*;
46 50  
47 51 /**
48 52 * 后台用户 Service 实现类
... ... @@ -79,42 +83,54 @@ public class AdminUserServiceImpl implements AdminUserService {
79 83  
80 84 @Override
81 85 @Transactional(rollbackFor = Exception.class)
  86 + @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_CREATE_SUB_TYPE, bizNo = "{{#user.id}}",
  87 + success = SYSTEM_USER_CREATE_SUCCESS)
82 88 public Long createUser(UserSaveReqVO createReqVO) {
83   - // 校验账户配合
  89 + // 1.1 校验账户配合
84 90 tenantService.handleTenantInfo(tenant -> {
85 91 long count = userMapper.selectCount();
86 92 if (count >= tenant.getAccountCount()) {
87 93 throw exception(USER_COUNT_MAX, tenant.getAccountCount());
88 94 }
89 95 });
90   - // 校验正确性
  96 + // 1.2 校验正确性
91 97 validateUserForCreateOrUpdate(null, createReqVO.getUsername(),
92 98 createReqVO.getMobile(), createReqVO.getEmail(), createReqVO.getDeptId(), createReqVO.getPostIds());
93   - // 插入用户
  99 + // 2.1 插入用户
94 100 AdminUserDO user = BeanUtils.toBean(createReqVO, AdminUserDO.class);
95 101 user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
96 102 user.setPassword(encodePassword(createReqVO.getPassword())); // 加密密码
97 103 userMapper.insert(user);
98   - // 插入关联岗位
  104 + // 2.2 插入关联岗位
99 105 if (CollectionUtil.isNotEmpty(user.getPostIds())) {
100 106 userPostMapper.insertBatch(convertList(user.getPostIds(),
101 107 postId -> new UserPostDO().setUserId(user.getId()).setPostId(postId)));
102 108 }
  109 +
  110 + // 3. 记录操作日志上下文
  111 + LogRecordContext.putVariable("user", user);
103 112 return user.getId();
104 113 }
105 114  
106 115 @Override
107 116 @Transactional(rollbackFor = Exception.class)
  117 + @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
  118 + success = SYSTEM_USER_UPDATE_SUCCESS)
108 119 public void updateUser(UserSaveReqVO updateReqVO) {
109 120 updateReqVO.setPassword(null); // 特殊:此处不更新密码
110   - // 校验正确性
111   - validateUserForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getUsername(),
  121 + // 1. 校验正确性
  122 + AdminUserDO oldUser = validateUserForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getUsername(),
112 123 updateReqVO.getMobile(), updateReqVO.getEmail(), updateReqVO.getDeptId(), updateReqVO.getPostIds());
113   - // 更新用户
  124 +
  125 + // 2.1 更新用户
114 126 AdminUserDO updateObj = BeanUtils.toBean(updateReqVO, AdminUserDO.class);
115 127 userMapper.updateById(updateObj);
116   - // 更新岗位
  128 + // 2.2 更新岗位
117 129 updateUserPost(updateReqVO, updateObj);
  130 +
  131 + // 3. 记录操作日志上下文
  132 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldUser, UserSaveReqVO.class));
  133 + LogRecordContext.putVariable("user", oldUser);
118 134 }
119 135  
120 136 private void updateUserPost(UserSaveReqVO reqVO, AdminUserDO updateObj) {
... ... @@ -124,7 +140,7 @@ public class AdminUserServiceImpl implements AdminUserService {
124 140 Set<Long> postIds = CollUtil.emptyIfNull(updateObj.getPostIds());
125 141 Collection<Long> createPostIds = CollUtil.subtract(postIds, dbPostIds);
126 142 Collection<Long> deletePostIds = CollUtil.subtract(dbPostIds, postIds);
127   - // 执行新增和删除。对于已经授权的菜单,不用做任何处理
  143 + // 执行新增和删除。对于已经授权的岗位,不用做任何处理
128 144 if (!CollectionUtil.isEmpty(createPostIds)) {
129 145 userPostMapper.insertBatch(convertList(createPostIds,
130 146 postId -> new UserPostDO().setUserId(userId).setPostId(postId)));
... ... @@ -173,14 +189,21 @@ public class AdminUserServiceImpl implements AdminUserService {
173 189 }
174 190  
175 191 @Override
  192 + @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_UPDATE_PASSWORD_SUB_TYPE, bizNo = "{{#id}}",
  193 + success = SYSTEM_USER_UPDATE_PASSWORD_SUCCESS)
176 194 public void updateUserPassword(Long id, String password) {
177   - // 校验用户存在
178   - validateUserExists(id);
179   - // 更新密码
  195 + // 1. 校验用户存在
  196 + AdminUserDO user = validateUserExists(id);
  197 +
  198 + // 2. 更新密码
180 199 AdminUserDO updateObj = new AdminUserDO();
181 200 updateObj.setId(id);
182 201 updateObj.setPassword(encodePassword(password)); // 加密密码
183 202 userMapper.updateById(updateObj);
  203 +
  204 + // 3. 记录操作日志上下文
  205 + LogRecordContext.putVariable("user", user);
  206 + LogRecordContext.putVariable("newPassword", updateObj.getPassword());
184 207 }
185 208  
186 209 @Override
... ... @@ -196,15 +219,21 @@ public class AdminUserServiceImpl implements AdminUserService {
196 219  
197 220 @Override
198 221 @Transactional(rollbackFor = Exception.class)
  222 + @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_DELETE_SUB_TYPE, bizNo = "{{#id}}",
  223 + success = SYSTEM_USER_DELETE_SUCCESS)
199 224 public void deleteUser(Long id) {
200   - // 校验用户存在
201   - validateUserExists(id);
202   - // 删除用户
  225 + // 1. 校验用户存在
  226 + AdminUserDO user = validateUserExists(id);
  227 +
  228 + // 2.1 删除用户
203 229 userMapper.deleteById(id);
204   - // 删除用户关联数据
  230 + // 2.2 删除用户关联数据
205 231 permissionService.processUserDeleted(id);
206   - // 删除用户岗位
  232 + // 2.2 删除用户岗位
207 233 userPostMapper.deleteByUserId(id);
  234 +
  235 + // 3. 记录操作日志上下文
  236 + LogRecordContext.putVariable("user", user);
208 237 }
209 238  
210 239 @Override
... ... @@ -294,12 +323,12 @@ public class AdminUserServiceImpl implements AdminUserService {
294 323 return deptIds;
295 324 }
296 325  
297   - private void validateUserForCreateOrUpdate(Long id, String username, String mobile, String email,
  326 + private AdminUserDO validateUserForCreateOrUpdate(Long id, String username, String mobile, String email,
298 327 Long deptId, Set<Long> postIds) {
299 328 // 关闭数据权限,避免因为没有数据权限,查询不到数据,进而导致唯一校验不正确
300   - DataPermissionUtils.executeIgnore(() -> {
  329 + return DataPermissionUtils.executeIgnore(() -> {
301 330 // 校验用户存在
302   - validateUserExists(id);
  331 + AdminUserDO user = validateUserExists(id);
303 332 // 校验用户名唯一
304 333 validateUsernameUnique(id, username);
305 334 // 校验手机号唯一
... ... @@ -310,18 +339,20 @@ public class AdminUserServiceImpl implements AdminUserService {
310 339 deptService.validateDeptList(CollectionUtils.singleton(deptId));
311 340 // 校验岗位处于开启状态
312 341 postService.validatePostList(postIds);
  342 + return user;
313 343 });
314 344 }
315 345  
316 346 @VisibleForTesting
317   - void validateUserExists(Long id) {
  347 + AdminUserDO validateUserExists(Long id) {
318 348 if (id == null) {
319   - return;
  349 + return null;
320 350 }
321 351 AdminUserDO user = userMapper.selectById(id);
322 352 if (user == null) {
323 353 throw exception(USER_NOT_EXISTS);
324 354 }
  355 + return user;
325 356 }
326 357  
327 358 @VisibleForTesting
... ...