Commit f56d8a2751e61c2436f774083962f53c05b0363b

Authored by puhui999
1 parent 1fae341c

重构操作日志记录实现

Showing 9 changed files with 78 additions and 48 deletions
yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/aop/OperateLogV2Aspect.java
@@ -16,7 +16,6 @@ import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2CreateReqDTO; @@ -16,7 +16,6 @@ import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2CreateReqDTO;
16 import com.google.common.collect.Maps; 16 import com.google.common.collect.Maps;
17 import com.mzt.logapi.beans.LogRecord; 17 import com.mzt.logapi.beans.LogRecord;
18 import io.swagger.v3.oas.annotations.Operation; 18 import io.swagger.v3.oas.annotations.Operation;
19 -import io.swagger.v3.oas.annotations.tags.Tag;  
20 import jakarta.annotation.Resource; 19 import jakarta.annotation.Resource;
21 import jakarta.servlet.http.HttpServletRequest; 20 import jakarta.servlet.http.HttpServletRequest;
22 import jakarta.servlet.http.HttpServletResponse; 21 import jakarta.servlet.http.HttpServletResponse;
@@ -46,7 +45,8 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC @@ -46,7 +45,8 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC
46 import static cn.iocoder.yudao.framework.operatelogv2.core.enums.OperateLogV2Constants.*; 45 import static cn.iocoder.yudao.framework.operatelogv2.core.enums.OperateLogV2Constants.*;
47 46
48 /** 47 /**
49 - * 拦截使用 @Operation 注解 48 + * 拦截使用 @Operation 注解, 获取操作类型、开始时间、持续时间、方法相关信息、执行结果等信息
  49 + * 对 mzt-biz-log 日志信息进行增强
50 * 50 *
51 * @author HUIHUI 51 * @author HUIHUI
52 */ 52 */
@@ -165,27 +165,9 @@ public class OperateLogV2Aspect { @@ -165,27 +165,9 @@ public class OperateLogV2Aspect {
165 LogRecord logRecord = CONTENT.get(); 165 LogRecord logRecord = CONTENT.get();
166 reqDTO.setBizId(Long.parseLong(logRecord.getBizNo())); // 操作模块业务编号 166 reqDTO.setBizId(Long.parseLong(logRecord.getBizNo())); // 操作模块业务编号
167 reqDTO.setContent(logRecord.getAction());// 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。 167 reqDTO.setContent(logRecord.getAction());// 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。
168 - if (EXTRA.get() != null) {  
169 - reqDTO.setExtra((Map<String, Object>) EXTRA.get().get(EXTRA_KEY)); // 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 ),例如说,记录订单编号,{ orderId: "1"}  
170 - }  
171 168
172 // type 属性 169 // type 属性
173 - if (logRecord.getType() != null) {  
174 - reqDTO.setType(logRecord.getType()); // 大模块类型如 crm 客户  
175 - }  
176 - if (StrUtil.isEmpty(reqDTO.getType())) {  
177 - Tag tag = getClassAnnotation(joinPoint, Tag.class);  
178 - if (tag != null) {  
179 - // 优先读取 @Tag 的 name 属性  
180 - if (StrUtil.isNotEmpty(tag.name())) {  
181 - reqDTO.setType(tag.name());  
182 - }  
183 - // 没有的话,读取 @API 的 description 属性  
184 - if (StrUtil.isEmpty(reqDTO.getType()) && ArrayUtil.isNotEmpty(tag.description())) {  
185 - reqDTO.setType(tag.description());  
186 - }  
187 - }  
188 - } 170 + reqDTO.setType(logRecord.getType()); // 大模块类型如 crm 客户
189 // subType 属性 171 // subType 属性
190 if (logRecord.getSubType() != null) { 172 if (logRecord.getSubType() != null) {
191 reqDTO.setSubType(logRecord.getSubType());// 操作名称如 转移客户 173 reqDTO.setSubType(logRecord.getSubType());// 操作名称如 转移客户
@@ -194,6 +176,24 @@ public class OperateLogV2Aspect { @@ -194,6 +176,24 @@ public class OperateLogV2Aspect {
194 reqDTO.setSubType(operation.summary()); 176 reqDTO.setSubType(operation.summary());
195 } 177 }
196 178
  179 + // 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 ),例如说,记录订单编号,{ orderId: "1"}
  180 + Map<String, Object> objectMap = EXTRA.get();
  181 + if (objectMap != null) {
  182 + Object object = objectMap.get(EXTRA_KEY);
  183 + if (object instanceof Map<?, ?> extraMap) {
  184 + if (extraMap.keySet().stream().allMatch(String.class::isInstance)) {
  185 + @SuppressWarnings("unchecked")
  186 + Map<String, Object> extra = (Map<String, Object>) extraMap;
  187 + reqDTO.setExtra(extra);
  188 + return;
  189 + }
  190 + }
  191 + // 激进一点不是 map 直接当 value 处理
  192 + Map<String, Object> extra = Maps.newHashMapWithExpectedSize(1);
  193 + extra.put(EXTRA_KEY, object);
  194 + reqDTO.setExtra(extra);
  195 + }
  196 +
197 } 197 }
198 198
199 private static void fillRequestFields(OperateLogV2CreateReqDTO reqDTO) { 199 private static void fillRequestFields(OperateLogV2CreateReqDTO reqDTO) {
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/function/CrmIndustryParseFunction.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/parse/CrmIndustryParseFunction.java
1 -package cn.iocoder.yudao.module.crm.framework.operatelog.function; 1 +package cn.iocoder.yudao.module.crm.framework.operatelog.parse;
2 2
3 import cn.hutool.core.util.StrUtil; 3 import cn.hutool.core.util.StrUtil;
4 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; 4 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/function/CrmLevelParseFunction.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/parse/CrmLevelParseFunction.java
1 -package cn.iocoder.yudao.module.crm.framework.operatelog.function; 1 +package cn.iocoder.yudao.module.crm.framework.operatelog.parse;
2 2
3 import cn.hutool.core.util.StrUtil; 3 import cn.hutool.core.util.StrUtil;
4 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; 4 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/function/CrmSourceParseFunction.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/parse/CrmSourceParseFunction.java
1 -package cn.iocoder.yudao.module.crm.framework.operatelog.function; 1 +package cn.iocoder.yudao.module.crm.framework.operatelog.parse;
2 2
3 import cn.hutool.core.util.StrUtil; 3 import cn.hutool.core.util.StrUtil;
4 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; 4 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.crm.service.customer; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.crm.service.customer;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.framework.operatelogv2.core.enums.OperateLogV2Constants;
6 import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerCreateReqVO; 7 import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerCreateReqVO;
7 import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO; 8 import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO;
8 import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO; 9 import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO;
@@ -65,17 +66,21 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @@ -65,17 +66,21 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
65 66
66 @Override 67 @Override
67 @Transactional(rollbackFor = Exception.class) 68 @Transactional(rollbackFor = Exception.class)
68 - @LogRecord(success = "更新了客户{_DIFF{#updateReqVO}}", type = CRM_CUSTOMER, subType = "更新客户", bizNo = "{{#updateReqVO.id}}") 69 + @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#updateReqVO.id}}", success = "更新了客户{_DIFF{#updateReqVO}}")
69 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) 70 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
70 public void updateCustomer(CrmCustomerUpdateReqVO updateReqVO) { 71 public void updateCustomer(CrmCustomerUpdateReqVO updateReqVO) {
71 // 校验存在 72 // 校验存在
72 CrmCustomerDO oldCustomerDO = validateCustomerExists(updateReqVO.getId()); 73 CrmCustomerDO oldCustomerDO = validateCustomerExists(updateReqVO.getId());
73 74
74 - // __DIFF 函数传递了一个参数,传递的参数是修改之后的对象,这种方式需要在方法内部向 LogRecordContext 中 put 一个变量,代表是之前的对象,这个对象可以是null  
75 - LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldCustomerDO, CrmCustomerUpdateReqVO.class));  
76 // 更新 75 // 更新
77 CrmCustomerDO updateObj = CrmCustomerConvert.INSTANCE.convert(updateReqVO); 76 CrmCustomerDO updateObj = CrmCustomerConvert.INSTANCE.convert(updateReqVO);
78 customerMapper.updateById(updateObj); 77 customerMapper.updateById(updateObj);
  78 +
  79 + // __DIFF 函数传递了一个参数,传递的参数是修改之后的对象,这种方式需要在方法内部向 LogRecordContext 中 put 一个变量,代表是之前的对象,这个对象可以是null
  80 + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldCustomerDO, CrmCustomerUpdateReqVO.class));
  81 + HashMap<String, Object> extra = new HashMap<>();
  82 + extra.put("tips", "随便记录一点啦");
  83 + LogRecordContext.putVariable(OperateLogV2Constants.EXTRA_KEY, extra);
79 } 84 }
80 85
81 @Override 86 @Override
@@ -125,27 +130,17 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @@ -125,27 +130,17 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
125 */ 130 */
126 @Override 131 @Override
127 public void validateCustomer(Long customerId) { 132 public void validateCustomer(Long customerId) {
128 - // 校验客户是否存在  
129 - if (customerId == null) {  
130 - throw exception(CUSTOMER_NOT_EXISTS);  
131 - }  
132 - CrmCustomerDO customer = customerMapper.selectById(customerId);  
133 - if (Objects.isNull(customer)) {  
134 - throw exception(CUSTOMER_NOT_EXISTS);  
135 - } 133 + validateCustomerExists(customerId);
136 } 134 }
137 135
138 @Override 136 @Override
139 @Transactional(rollbackFor = Exception.class) 137 @Transactional(rollbackFor = Exception.class)
140 - // TODO @puhui999:@LogRecord(type = CRM_CUSTOMER, subType = "客户转移", bizNo = "{{#reqVO.id}}", success = TRANSFER_CUSTOMER_LOG_SUCCESS)  
141 - @LogRecord(success = TRANSFER_CUSTOMER_LOG_SUCCESS, type = CRM_CUSTOMER, subType = "客户转移", bizNo = "{{#reqVO.id}}") 138 + @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#reqVO.id}}", success = TRANSFER_CUSTOMER_LOG_SUCCESS)
142 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) 139 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER)
143 public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) { 140 public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) {
144 // 1. 校验客户是否存在 141 // 1. 校验客户是否存在
145 - validateCustomer(reqVO.getId());  
146 - // 添加 crmCustomer 到日志上下文 TODO 日志记录放在 service 里是因为已经过了权限校验查询时不用走两次校验  
147 - // TODO @puhui999:customer 不用查询,从 1. 拿到哈;然后 put这个动作,可以放到 3.;这样逻辑结构就是,校验、逻辑、日志,更加清晰  
148 - LogRecordContext.putVariable("crmCustomer", customerMapper.selectById(reqVO.getId())); 142 + CrmCustomerDO customerDO = validateCustomerExists(reqVO.getId());
  143 +
149 // 2.1 数据权限转移 144 // 2.1 数据权限转移
150 crmPermissionService.transferPermission( 145 crmPermissionService.transferPermission(
151 CrmCustomerConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())); 146 CrmCustomerConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()));
@@ -153,6 +148,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @@ -153,6 +148,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
153 customerMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); 148 customerMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId());
154 149
155 // 3. TODO 记录转移日志 150 // 3. TODO 记录转移日志
  151 + LogRecordContext.putVariable("crmCustomer", customerDO);
156 } 152 }
157 153
158 @Override 154 @Override
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java
@@ -138,7 +138,6 @@ public class CrmPermissionServiceImpl implements CrmPermissionService { @@ -138,7 +138,6 @@ public class CrmPermissionServiceImpl implements CrmPermissionService {
138 } 138 }
139 139
140 @Override 140 @Override
141 - @Transactional(rollbackFor = Exception.class) // TODO @puhui999:这里不用加的,就一个操作哈;  
142 public void deletePermission(Integer bizType, Long bizId) { 141 public void deletePermission(Integer bizType, Long bizId) {
143 int deletedCount = crmPermissionMapper.deletePermission(bizType, bizId); 142 int deletedCount = crmPermissionMapper.deletePermission(bizType, bizId);
144 if (deletedCount == 0) { 143 if (deletedCount == 0) {
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogV2RespDTO.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.api.logger.dto; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.api.logger.dto;
3 import lombok.Data; 3 import lombok.Data;
4 4
5 import java.time.LocalDateTime; 5 import java.time.LocalDateTime;
  6 +import java.util.Map;
6 7
7 /** 8 /**
8 * 系统操作日志 Resp DTO 9 * 系统操作日志 Resp DTO
@@ -29,13 +30,13 @@ public class OperateLogV2RespDTO { @@ -29,13 +30,13 @@ public class OperateLogV2RespDTO {
29 */ 30 */
30 private Integer userType; 31 private Integer userType;
31 /** 32 /**
32 - * 操作模块 33 + * 操作模块类型
33 */ 34 */
34 - private String module; 35 + private String type;
35 /** 36 /**
36 * 操作名 37 * 操作名
37 */ 38 */
38 - private String name; 39 + private String subType;
39 /** 40 /**
40 * 操作模块业务编号 41 * 操作模块业务编号
41 */ 42 */
@@ -47,7 +48,7 @@ public class OperateLogV2RespDTO { @@ -47,7 +48,7 @@ public class OperateLogV2RespDTO {
47 /** 48 /**
48 * 拓展字段 49 * 拓展字段
49 */ 50 */
50 - private String extra; 51 + private Map<String, Object> extra;
51 52
52 /** 53 /**
53 * 请求方法名 54 * 请求方法名
@@ -67,6 +68,40 @@ public class OperateLogV2RespDTO { @@ -67,6 +68,40 @@ public class OperateLogV2RespDTO {
67 private String userAgent; 68 private String userAgent;
68 69
69 /** 70 /**
  71 + * Java 方法名
  72 + */
  73 + private String javaMethod;
  74 + /**
  75 + * Java 方法的参数
  76 + */
  77 + private String javaMethodArgs;
  78 +
  79 + /**
  80 + * 开始时间
  81 + */
  82 + private LocalDateTime startTime;
  83 +
  84 + /**
  85 + * 执行时长,单位:毫秒
  86 + */
  87 + private Integer duration;
  88 +
  89 + /**
  90 + * 结果码
  91 + */
  92 + private Integer resultCode;
  93 +
  94 + /**
  95 + * 结果提示
  96 + */
  97 + private String resultMsg;
  98 +
  99 + /**
  100 + * 结果数据
  101 + */
  102 + private String resultData;
  103 +
  104 + /**
70 * 创建时间 105 * 创建时间
71 */ 106 */
72 private LocalDateTime createTime; 107 private LocalDateTime createTime;
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/function/AdminUserParseFunction.java renamed to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/parse/AdminUserParseFunction.java
1 -package cn.iocoder.yudao.module.system.framework.operatelog.function; 1 +package cn.iocoder.yudao.module.system.framework.operatelog.parse;
2 2
3 import cn.hutool.core.util.ObjUtil; 3 import cn.hutool.core.util.ObjUtil;
4 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/function/AreaParseFunction.java renamed to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/parse/AreaParseFunction.java
1 -package cn.iocoder.yudao.module.system.framework.operatelog.function; 1 +package cn.iocoder.yudao.module.system.framework.operatelog.parse;
2 2
3 import cn.hutool.core.util.StrUtil; 3 import cn.hutool.core.util.StrUtil;
4 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; 4 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;