Commit 87c7b3fac2c291b45c3537d972d0ac3e690d4342
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
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 | ... | ... |