Explorar el Código

系统操作日志:集成 mzt-biz-log 3

puhui999 hace 1 año
padre
commit
c74881c8f0
Se han modificado 11 ficheros con 145 adiciones y 94 borrados
  1. 12 3
      yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java
  2. 2 3
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.http
  3. 0 1
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java
  4. 3 3
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
  5. 3 67
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/OperateLogV2DO.java
  6. 1 9
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/OperateLogV2Mapper.java
  7. 2 3
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/config/YudaoOperateLogV2Configuration.java
  8. 2 2
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/function/AdminUserParseFunction.java
  9. 42 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/service/ILogRecordServiceImpl.java
  10. 0 2
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java
  11. 78 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/bo/OperateLogV2CreateReqBO.java

+ 12 - 3
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java

@@ -7,12 +7,21 @@ package cn.iocoder.yudao.module.crm.enums;
  */
 public interface LogRecordConstants {
 
-    String WHO = "【{getAdminUserById{#userId}}】";
+    //======================= 客户模块类型 =======================
+    // TODO puhui999: 确保模块命名方式为 module + 子模块名称的方式。统一定义模块名称是为了方便查询各自记录的操作日志,列如说:查询客户【张三的操作日志】就可以 module + bizId
+    String CRM_LEADS = "CRM-线索";
+    String CRM_CUSTOMER = "CRM-客户";
+    String CRM_CONTACT = "CRM-联系人";
+    String CRM_BUSINESS = "CRM-商机";
+    String CRM_CONTRACT = "CRM-合同";
+    String CRM_PRODUCT = "CRM-产品";
+    String CRM_RECEIVABLE = "CRM-回款";
+    String CRM_RECEIVABLE_PLAN = "CRM-回款计划";
 
     //======================= 客户转移操作日志 =======================
 
-    String TRANSFER_CUSTOMER_LOG_TYPE = "客户转移";
-    String TRANSFER_CUSTOMER_LOG_SUCCESS = WHO + "把客户【{{#crmCustomer.name}}】负责人【{getAdminUserById{#crmCustomer.ownerUserId}}】转移给了【{getAdminUserById{#reqVO.newOwnerUserId}}】";
+    String TRANSFER_CUSTOMER_LOG_SUCCESS = "把客户【{{#crmCustomer == null ? '' : #crmCustomer.name}}】负责人从" +
+            "【{getAdminUserById{#crmCustomer == null ? '' : #crmCustomer.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】";
     String TRANSFER_CUSTOMER_LOG_FAIL = "";
 
 }

+ 2 - 3
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.http

@@ -5,9 +5,8 @@ Authorization: Bearer {{token}}
 tenant-id: {{adminTenentId}}
 
 {
-  "id": 11,
-  "newOwnerUserId": 127,
-  "oldOwnerPermissionLevel": 2
+  "id": 10,
+  "newOwnerUserId": 127
 }
 
 

+ 0 - 1
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java

@@ -123,7 +123,6 @@ public class CrmCustomerController {
     }
 
     @PutMapping("/transfer")
-    @Operation(summary = "客户转移")
     @PreAuthorize("@ss.hasPermission('crm:customer:update')")
     public CommonResult<Boolean> transfer(@Valid @RequestBody CrmCustomerTransferReqVO reqVO) {
         customerService.transferCustomer(reqVO, getLoginUserId());

+ 3 - 3
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java

@@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerUpdat
 import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert;
 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
 import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper;
-import cn.iocoder.yudao.module.crm.enums.LogRecordConstants;
 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
 import cn.iocoder.yudao.module.crm.framework.core.annotations.CrmPermission;
@@ -27,6 +26,8 @@ import java.util.*;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.CRM_CUSTOMER;
+import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.TRANSFER_CUSTOMER_LOG_SUCCESS;
 import static java.util.Collections.singletonList;
 
 /**
@@ -129,8 +130,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    @LogRecord(success = LogRecordConstants.TRANSFER_CUSTOMER_LOG_SUCCESS,
-            type = LogRecordConstants.TRANSFER_CUSTOMER_LOG_TYPE, bizNo = "{{#reqVO.id}}")
+    @LogRecord(success = TRANSFER_CUSTOMER_LOG_SUCCESS, type = CRM_CUSTOMER, subType = "客户转移", bizNo = "{{#reqVO.id}}")
     @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER)
     public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) {
         // 1. 校验客户是否存在

+ 3 - 67
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/OperateLogV2DO.java

@@ -1,22 +1,15 @@
 package cn.iocoder.yudao.module.system.dal.dataobject.logger;
 
 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
 import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
-import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
-import java.time.LocalDateTime;
-import java.util.Map;
-
 /**
- * 操作日志表
+ * 操作日志表 V2
  *
  * @author 芋道源码
  */
@@ -27,16 +20,6 @@ import java.util.Map;
 public class OperateLogV2DO extends BaseDO {
 
     /**
-     * {@link #javaMethodArgs} 的最大长度
-     */
-    public static final Integer JAVA_METHOD_ARGS_MAX_LENGTH = 8000;
-
-    /**
-     * {@link #resultData} 的最大长度
-     */
-    public static final Integer RESULT_MAX_LENGTH = 4000;
-
-    /**
      * 日志主键
      */
     @TableId
@@ -68,22 +51,14 @@ public class OperateLogV2DO extends BaseDO {
      */
     private String name;
     /**
-     * 操作分类
-     *
-     * 枚举 {@link OperateTypeEnum}
+     * 操作模块业务编号
      */
-    private Integer type;
+    private Long bizId;
     /**
      * 操作内容,记录整个操作的明细
      * 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。
      */
     private String content;
-    /**
-     * 拓展字段,有些复杂的业务,需要记录一些字段
-     * 例如说,记录订单编号,则可以添加 key 为 "orderId",value 为订单编号
-     */
-    @TableField(typeHandler = JacksonTypeHandler.class)
-    private Map<String, Object> exts;
 
     /**
      * 请求方法名
@@ -102,43 +77,4 @@ public class OperateLogV2DO extends BaseDO {
      */
     private String userAgent;
 
-    /**
-     * Java 方法名
-     */
-    private String javaMethod;
-    /**
-     * Java 方法的参数
-     *
-     * 实际格式为 Map<String, Object>
-     * 不使用 @TableField(typeHandler = FastjsonTypeHandler.class) 注解的原因是,数据库存储有长度限制,会进行裁剪,会导致 JSON 反序列化失败
-     * 其中,key 为参数名,value 为参数值
-     */
-    private String javaMethodArgs;
-    /**
-     * 开始时间
-     */
-    private LocalDateTime startTime;
-    /**
-     * 执行时长,单位:毫秒
-     */
-    private Integer duration;
-    /**
-     * 结果码
-     *
-     * 目前使用的 {@link CommonResult#getCode()} 属性
-     */
-    private Integer resultCode;
-    /**
-     * 结果提示
-     *
-     * 目前使用的 {@link CommonResult#getMsg()} 属性
-     */
-    private String resultMsg;
-    /**
-     * 结果数据
-     *
-     * 如果是对象,则使用 JSON 格式化
-     */
-    private String resultData;
-
 }

+ 1 - 9
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/OperateLogV2Mapper.java

@@ -1,6 +1,5 @@
 package cn.iocoder.yudao.module.system.dal.mysql.logger;
 
-import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
@@ -16,14 +15,7 @@ public interface OperateLogV2Mapper extends BaseMapperX<OperateLogV2DO> {
     default PageResult<OperateLogV2DO> selectPage(OperateLogPageReqVO reqVO, Collection<Long> userIds) {
         LambdaQueryWrapperX<OperateLogV2DO> query = new LambdaQueryWrapperX<OperateLogV2DO>()
                 .likeIfPresent(OperateLogV2DO::getModule, reqVO.getModule())
-                .inIfPresent(OperateLogV2DO::getUserId, userIds)
-                .eqIfPresent(OperateLogV2DO::getType, reqVO.getType())
-                .betweenIfPresent(OperateLogV2DO::getStartTime, reqVO.getStartTime());
-        if (Boolean.TRUE.equals(reqVO.getSuccess())) {
-            query.eq(OperateLogV2DO::getResultCode, GlobalErrorCodeConstants.SUCCESS.getCode());
-        } else if (Boolean.FALSE.equals(reqVO.getSuccess())) {
-            query.gt(OperateLogV2DO::getResultCode, GlobalErrorCodeConstants.SUCCESS.getCode());
-        }
+                .inIfPresent(OperateLogV2DO::getUserId, userIds);
         query.orderByDesc(OperateLogV2DO::getId); // 降序
         return selectPage(reqVO, query);
     }

+ 2 - 3
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/config/YudaoOperateLogV2Configuration.java

@@ -3,14 +3,13 @@ package cn.iocoder.yudao.module.system.framework.bizlog.config;
 import com.mzt.logapi.starter.annotation.EnableLogRecord;
 import org.springframework.context.annotation.Configuration;
 
-
 /**
- *
+ * mzt-biz-log 配置类
  *
  * @author HUIHUI
  */
 @Configuration(proxyBeanMethods = false)
-@EnableLogRecord(tenant = "${yudao.info.base-package}")
+@EnableLogRecord(tenant = "") // 貌似用不上 tenant 这玩意给个空好啦
 public class YudaoOperateLogV2Configuration {
 
 }

+ 2 - 2
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/function/AdminUserParseFunction.java

@@ -34,11 +34,11 @@ public class AdminUserParseFunction implements IParseFunction {
     @Override
     public String apply(Object value) {
         if (value == null) {
-            log.warn("(getAdminUserById) 解析异常参数为 null");
+            //log.warn("(getAdminUserById) 解析异常参数为 null");
             return "";
         }
         if (StrUtil.isEmpty(value.toString())) {
-            log.warn("(getAdminUserById) 解析异常参数为空");
+            //log.warn("(getAdminUserById) 解析异常参数为空");
             return "";
         }
 

+ 42 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/service/ILogRecordServiceImpl.java

@@ -1,9 +1,14 @@
 package cn.iocoder.yudao.module.system.framework.bizlog.service;
 
+import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
+import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
+import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
 import cn.iocoder.yudao.module.system.api.logger.OperateLogApi;
+import cn.iocoder.yudao.module.system.service.logger.bo.OperateLogV2CreateReqBO;
 import com.mzt.logapi.beans.LogRecord;
 import com.mzt.logapi.service.ILogRecordService;
 import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletRequest;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
@@ -26,7 +31,42 @@ public class ILogRecordServiceImpl implements ILogRecordService {
 
     @Override
     public void record(LogRecord logRecord) {
-        log.info("【logRecord】log={}", logRecord);
+        OperateLogV2CreateReqBO reqBO = new OperateLogV2CreateReqBO();
+        // 补全通用字段
+        reqBO.setTraceId(TracerUtils.getTraceId());
+        // 补充用户信息
+        fillUserFields(reqBO);
+        // 补全模块信息
+        fillModuleFields(reqBO, logRecord);
+        // 补全请求信息
+        fillRequestFields(reqBO);
+        // 异步记录日志
+        log.info("操作日志 ===> {}", reqBO);
+    }
+
+    private static void fillUserFields(OperateLogV2CreateReqBO reqBO) {
+        reqBO.setUserId(WebFrameworkUtils.getLoginUserId());
+        reqBO.setUserType(WebFrameworkUtils.getLoginUserType());
+    }
+
+    public static void fillModuleFields(OperateLogV2CreateReqBO reqBO, LogRecord logRecord) {
+        reqBO.setModule(logRecord.getType()); // 大模块类型如 crm-客户
+        reqBO.setName(logRecord.getSubType());// 操作名称如 转移客户
+        reqBO.setBizId(Long.parseLong(logRecord.getBizNo())); // 操作模块业务编号
+        reqBO.setContent(logRecord.getAction());// 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。
+    }
+
+    private static void fillRequestFields(OperateLogV2CreateReqBO reqBO) {
+        // 获得 Request 对象
+        HttpServletRequest request = ServletUtils.getRequest();
+        if (request == null) {
+            return;
+        }
+        // 补全请求信息
+        reqBO.setRequestMethod(request.getMethod());
+        reqBO.setRequestUrl(request.getRequestURI());
+        reqBO.setUserIp(ServletUtils.getClientIP(request));
+        reqBO.setUserAgent(ServletUtils.getUserAgent(request));
     }
 
     @Override
@@ -38,4 +78,5 @@ public class ILogRecordServiceImpl implements ILogRecordService {
     public List<LogRecord> queryLogByBizNo(String bizNo, String type, String subType) {
         return Collections.emptyList();
     }
+
 }

+ 0 - 2
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java

@@ -53,8 +53,6 @@ public class OperateLogServiceImpl implements OperateLogService {
     @Override
     public void createOperateLogV2(OperateLogCreateReqDTO createReqDTO) {
         OperateLogV2DO log = BeanUtils.toBean(createReqDTO, OperateLogV2DO.class);
-        log.setJavaMethodArgs(StrUtils.maxLength(log.getJavaMethodArgs(), JAVA_METHOD_ARGS_MAX_LENGTH));
-        log.setResultData(StrUtils.maxLength(log.getResultData(), RESULT_MAX_LENGTH));
         operateLogV2Mapper.insert(log);
     }
 

+ 78 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/bo/OperateLogV2CreateReqBO.java

@@ -0,0 +1,78 @@
+package cn.iocoder.yudao.module.system.service.logger.bo;
+
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
+import jakarta.validation.constraints.NotEmpty;
+import lombok.Data;
+
+/**
+ * 系统操作日志 Create Req BO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class OperateLogV2CreateReqBO {
+
+    /**
+     * 链路追踪编号
+     *
+     * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。
+     */
+    private String traceId;
+    /**
+     * 用户编号
+     *
+     * 关联 MemberUserDO 的 id 属性,或者 AdminUserDO 的 id 属性
+     */
+    @NotEmpty(message = "用户编号不能为空")
+    private Long userId;
+    /**
+     * 用户类型
+     *
+     * 关联 {@link  UserTypeEnum}
+     */
+    @NotEmpty(message = "用户类型不能为空")
+    private Integer userType;
+    /**
+     * 操作模块
+     */
+    @NotEmpty(message = "操作模块不能为空")
+    private String module;
+    /**
+     * 操作名
+     */
+    @NotEmpty(message = "操作名不能为空")
+    private String name;
+    /**
+     * 操作模块业务编号
+     */
+    @NotEmpty(message = "操作模块业务编号不能为空")
+    private Long bizId;
+    /**
+     * 操作内容,记录整个操作的明细
+     * 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。
+     */
+    @NotEmpty(message = "操作内容不能为空")
+    private String content;
+
+    /**
+     * 请求方法名
+     */
+    @NotEmpty(message = "请求方法名不能为空")
+    private String requestMethod;
+    /**
+     * 请求地址
+     */
+    @NotEmpty(message = "请求地址不能为空")
+    private String requestUrl;
+    /**
+     * 用户 IP
+     */
+    @NotEmpty(message = "用户 IP 不能为空")
+    private String userIp;
+    /**
+     * 浏览器 UA
+     */
+    @NotEmpty(message = "浏览器 UA 不能为空")
+    private String userAgent;
+
+}