重构操作日志记录实现

This commit is contained in:
puhui999 2023-12-19 18:34:51 +08:00
parent 1fae341cae
commit f56d8a2751
9 changed files with 78 additions and 48 deletions

View File

@ -16,7 +16,6 @@ import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2CreateReqDTO;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.mzt.logapi.beans.LogRecord; import com.mzt.logapi.beans.LogRecord;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
@ -46,7 +45,8 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC
import static cn.iocoder.yudao.framework.operatelogv2.core.enums.OperateLogV2Constants.*; import static cn.iocoder.yudao.framework.operatelogv2.core.enums.OperateLogV2Constants.*;
/** /**
* 拦截使用 @Operation 注解 * 拦截使用 @Operation 注解, 获取操作类型开始时间持续时间方法相关信息执行结果等信息
* mzt-biz-log 日志信息进行增强
* *
* @author HUIHUI * @author HUIHUI
*/ */
@ -165,27 +165,9 @@ public class OperateLogV2Aspect {
LogRecord logRecord = CONTENT.get(); LogRecord logRecord = CONTENT.get();
reqDTO.setBizId(Long.parseLong(logRecord.getBizNo())); // 操作模块业务编号 reqDTO.setBizId(Long.parseLong(logRecord.getBizNo())); // 操作模块业务编号
reqDTO.setContent(logRecord.getAction());// 例如说修改编号为 1 的用户信息将性别从男改成女将姓名从芋道改成源码 reqDTO.setContent(logRecord.getAction());// 例如说修改编号为 1 的用户信息将性别从男改成女将姓名从芋道改成源码
if (EXTRA.get() != null) {
reqDTO.setExtra((Map<String, Object>) EXTRA.get().get(EXTRA_KEY)); // 拓展字段有些复杂的业务需要记录一些字段 ( JSON 格式 )例如说记录订单编号{ orderId: "1"}
}
// type 属性 // type 属性
if (logRecord.getType() != null) {
reqDTO.setType(logRecord.getType()); // 大模块类型如 crm 客户 reqDTO.setType(logRecord.getType()); // 大模块类型如 crm 客户
}
if (StrUtil.isEmpty(reqDTO.getType())) {
Tag tag = getClassAnnotation(joinPoint, Tag.class);
if (tag != null) {
// 优先读取 @Tag name 属性
if (StrUtil.isNotEmpty(tag.name())) {
reqDTO.setType(tag.name());
}
// 没有的话读取 @API description 属性
if (StrUtil.isEmpty(reqDTO.getType()) && ArrayUtil.isNotEmpty(tag.description())) {
reqDTO.setType(tag.description());
}
}
}
// subType 属性 // subType 属性
if (logRecord.getSubType() != null) { if (logRecord.getSubType() != null) {
reqDTO.setSubType(logRecord.getSubType());// 操作名称如 转移客户 reqDTO.setSubType(logRecord.getSubType());// 操作名称如 转移客户
@ -194,6 +176,24 @@ public class OperateLogV2Aspect {
reqDTO.setSubType(operation.summary()); reqDTO.setSubType(operation.summary());
} }
// 拓展字段有些复杂的业务需要记录一些字段 ( JSON 格式 )例如说记录订单编号{ orderId: "1"}
Map<String, Object> objectMap = EXTRA.get();
if (objectMap != null) {
Object object = objectMap.get(EXTRA_KEY);
if (object instanceof Map<?, ?> extraMap) {
if (extraMap.keySet().stream().allMatch(String.class::isInstance)) {
@SuppressWarnings("unchecked")
Map<String, Object> extra = (Map<String, Object>) extraMap;
reqDTO.setExtra(extra);
return;
}
}
// 激进一点不是 map 直接当 value 处理
Map<String, Object> extra = Maps.newHashMapWithExpectedSize(1);
extra.put(EXTRA_KEY, object);
reqDTO.setExtra(extra);
}
} }
private static void fillRequestFields(OperateLogV2CreateReqDTO reqDTO) { private static void fillRequestFields(OperateLogV2CreateReqDTO reqDTO) {

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.crm.framework.operatelog.function; package cn.iocoder.yudao.module.crm.framework.operatelog.parse;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.crm.framework.operatelog.function; package cn.iocoder.yudao.module.crm.framework.operatelog.parse;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.crm.framework.operatelog.function; package cn.iocoder.yudao.module.crm.framework.operatelog.parse;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.crm.service.customer;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.operatelogv2.core.enums.OperateLogV2Constants;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerCreateReqVO; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerCreateReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO;
@ -65,17 +66,21 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@LogRecord(success = "更新了客户{_DIFF{#updateReqVO}}", type = CRM_CUSTOMER, subType = "更新客户", bizNo = "{{#updateReqVO.id}}") @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#updateReqVO.id}}", success = "更新了客户{_DIFF{#updateReqVO}}")
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
public void updateCustomer(CrmCustomerUpdateReqVO updateReqVO) { public void updateCustomer(CrmCustomerUpdateReqVO updateReqVO) {
// 校验存在 // 校验存在
CrmCustomerDO oldCustomerDO = validateCustomerExists(updateReqVO.getId()); CrmCustomerDO oldCustomerDO = validateCustomerExists(updateReqVO.getId());
// __DIFF 函数传递了一个参数传递的参数是修改之后的对象这种方式需要在方法内部向 LogRecordContext put 一个变量代表是之前的对象这个对象可以是null
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldCustomerDO, CrmCustomerUpdateReqVO.class));
// 更新 // 更新
CrmCustomerDO updateObj = CrmCustomerConvert.INSTANCE.convert(updateReqVO); CrmCustomerDO updateObj = CrmCustomerConvert.INSTANCE.convert(updateReqVO);
customerMapper.updateById(updateObj); customerMapper.updateById(updateObj);
// __DIFF 函数传递了一个参数传递的参数是修改之后的对象这种方式需要在方法内部向 LogRecordContext put 一个变量代表是之前的对象这个对象可以是null
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldCustomerDO, CrmCustomerUpdateReqVO.class));
HashMap<String, Object> extra = new HashMap<>();
extra.put("tips", "随便记录一点啦");
LogRecordContext.putVariable(OperateLogV2Constants.EXTRA_KEY, extra);
} }
@Override @Override
@ -125,27 +130,17 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
*/ */
@Override @Override
public void validateCustomer(Long customerId) { public void validateCustomer(Long customerId) {
// 校验客户是否存在 validateCustomerExists(customerId);
if (customerId == null) {
throw exception(CUSTOMER_NOT_EXISTS);
}
CrmCustomerDO customer = customerMapper.selectById(customerId);
if (Objects.isNull(customer)) {
throw exception(CUSTOMER_NOT_EXISTS);
}
} }
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
// TODO @puhui999@LogRecord(type = CRM_CUSTOMER, subType = "客户转移", bizNo = "{{#reqVO.id}}", success = TRANSFER_CUSTOMER_LOG_SUCCESS) @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#reqVO.id}}", success = TRANSFER_CUSTOMER_LOG_SUCCESS)
@LogRecord(success = TRANSFER_CUSTOMER_LOG_SUCCESS, type = CRM_CUSTOMER, subType = "客户转移", bizNo = "{{#reqVO.id}}")
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER)
public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) { public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) {
// 1. 校验客户是否存在 // 1. 校验客户是否存在
validateCustomer(reqVO.getId()); CrmCustomerDO customerDO = validateCustomerExists(reqVO.getId());
// 添加 crmCustomer 到日志上下文 TODO 日志记录放在 service 里是因为已经过了权限校验查询时不用走两次校验
// TODO @puhui999customer 不用查询 1. 拿到哈然后 put这个动作可以放到 3.这样逻辑结构就是校验逻辑日志更加清晰
LogRecordContext.putVariable("crmCustomer", customerMapper.selectById(reqVO.getId()));
// 2.1 数据权限转移 // 2.1 数据权限转移
crmPermissionService.transferPermission( crmPermissionService.transferPermission(
CrmCustomerConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())); CrmCustomerConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()));
@ -153,6 +148,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
customerMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); customerMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId());
// 3. TODO 记录转移日志 // 3. TODO 记录转移日志
LogRecordContext.putVariable("crmCustomer", customerDO);
} }
@Override @Override

View File

@ -138,7 +138,6 @@ public class CrmPermissionServiceImpl implements CrmPermissionService {
} }
@Override @Override
@Transactional(rollbackFor = Exception.class) // TODO @puhui999这里不用加的就一个操作哈
public void deletePermission(Integer bizType, Long bizId) { public void deletePermission(Integer bizType, Long bizId) {
int deletedCount = crmPermissionMapper.deletePermission(bizType, bizId); int deletedCount = crmPermissionMapper.deletePermission(bizType, bizId);
if (deletedCount == 0) { if (deletedCount == 0) {

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.api.logger.dto;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Map;
/** /**
* 系统操作日志 Resp DTO * 系统操作日志 Resp DTO
@ -29,13 +30,13 @@ public class OperateLogV2RespDTO {
*/ */
private Integer userType; private Integer userType;
/** /**
* 操作模块 * 操作模块类型
*/ */
private String module; private String type;
/** /**
* 操作名 * 操作名
*/ */
private String name; private String subType;
/** /**
* 操作模块业务编号 * 操作模块业务编号
*/ */
@ -47,7 +48,7 @@ public class OperateLogV2RespDTO {
/** /**
* 拓展字段 * 拓展字段
*/ */
private String extra; private Map<String, Object> extra;
/** /**
* 请求方法名 * 请求方法名
@ -66,6 +67,40 @@ public class OperateLogV2RespDTO {
*/ */
private String userAgent; private String userAgent;
/**
* Java 方法名
*/
private String javaMethod;
/**
* Java 方法的参数
*/
private String javaMethodArgs;
/**
* 开始时间
*/
private LocalDateTime startTime;
/**
* 执行时长单位毫秒
*/
private Integer duration;
/**
* 结果码
*/
private Integer resultCode;
/**
* 结果提示
*/
private String resultMsg;
/**
* 结果数据
*/
private String resultData;
/** /**
* 创建时间 * 创建时间
*/ */

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.system.framework.operatelog.function; package cn.iocoder.yudao.module.system.framework.operatelog.parse;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.system.framework.operatelog.function; package cn.iocoder.yudao.module.system.framework.operatelog.parse;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;