Browse Source

操作日志:完善 code review 提到的问题

puhui999 1 year ago
parent
commit
6950368991
27 changed files with 183 additions and 649 deletions
  1. 0 7
      yudao-framework/yudao-spring-boot-starter-biz-operatelog/pom.xml
  2. 14 10
      yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogAutoConfiguration.java
  3. 0 330
      yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/aop/OperateLogV2Aspect.java
  4. 0 35
      yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/enums/OperateLogV2Constants.java
  5. 0 39
      yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/service/ILogRecordServiceImpl.java
  6. 0 1
      yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/package-info.java
  7. 1 2
      yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  8. 7 0
      yudao-framework/yudao-spring-boot-starter-security/pom.xml
  9. 3 9
      yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogV2Configuration.java
  10. 1 0
      yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/package-info.java
  11. 83 0
      yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/ILogRecordServiceImpl.java
  12. 2 1
      yudao-framework/yudao-spring-boot-starter-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  13. 7 3
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java
  14. 3 4
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerOperateLogPageReqVO.java
  15. 4 10
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmIndustryParseFunction.java
  16. 5 7
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmLevelParseFunction.java
  17. 5 7
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmSourceParseFunction.java
  18. 8 8
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
  19. 2 39
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogV2CreateReqDTO.java
  20. 2 44
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogV2RespDTO.java
  21. 3 15
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApiImpl.java
  22. 19 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/logger/OperateLogConvert.java
  23. 3 61
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/OperateLogV2DO.java
  24. 3 6
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AdminUserParseFunction.java
  25. 3 3
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AreaParseFunction.java
  26. 0 2
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java
  27. 5 6
      yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java

+ 0 - 7
yudao-framework/yudao-spring-boot-starter-biz-operatelog/pom.xml

@@ -47,13 +47,6 @@
             <artifactId>guava</artifactId>
         </dependency>
 
-        <dependency>
-            <!-- Spring Boot 通用操作日志组件,基于注解实现 -->
-            <!-- 此组件解决的问题是:「谁」在「什么时间」对「什么」做了「什么事」 -->
-            <groupId>io.github.mouzt</groupId>
-            <artifactId>bizlog-sdk</artifactId>
-        </dependency>
-
     </dependencies>
 
 </project>

+ 14 - 10
yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogAutoConfiguration.java

@@ -1,19 +1,23 @@
 package cn.iocoder.yudao.framework.operatelog.config;
 
+import cn.iocoder.yudao.framework.operatelog.core.aop.OperateLogAspect;
+import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkService;
+import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkServiceImpl;
+import cn.iocoder.yudao.module.system.api.logger.OperateLogApi;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.context.annotation.Bean;
 
 @AutoConfiguration
 public class YudaoOperateLogAutoConfiguration {
 
-    // TODO @puhui999:这个是不是留着哈?因为老版本还是会留着一段时间的
-    //@Bean
-    //public OperateLogAspect operateLogAspect() {
-    //    return new OperateLogAspect();
-    //}
-    //
-    //@Bean
-    //public OperateLogFrameworkService operateLogFrameworkService(OperateLogApi operateLogApi) {
-    //    return new OperateLogFrameworkServiceImpl(operateLogApi);
-    //}
+    @Bean
+    public OperateLogAspect operateLogAspect() {
+        return new OperateLogAspect();
+    }
+
+    @Bean
+    public OperateLogFrameworkService operateLogFrameworkService(OperateLogApi operateLogApi) {
+        return new OperateLogFrameworkServiceImpl(operateLogApi);
+    }
 
 }

+ 0 - 330
yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/aop/OperateLogV2Aspect.java

@@ -1,330 +0,0 @@
-package cn.iocoder.yudao.framework.operatelogv2.core.aop;
-
-import cn.hutool.core.date.LocalDateTimeUtil;
-import cn.hutool.core.exceptions.ExceptionUtil;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.ObjUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
-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.api.logger.dto.OperateLogV2CreateReqDTO;
-import com.google.common.collect.Maps;
-import com.mzt.logapi.beans.LogRecord;
-import io.swagger.v3.oas.annotations.Operation;
-import jakarta.annotation.Resource;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.extern.slf4j.Slf4j;
-import org.aspectj.lang.ProceedingJoinPoint;
-import org.aspectj.lang.annotation.Around;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.reflect.MethodSignature;
-import org.springframework.core.annotation.AnnotationUtils;
-import org.springframework.validation.BindingResult;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Array;
-import java.time.LocalDateTime;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.Predicate;
-import java.util.stream.IntStream;
-
-import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
-import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.SUCCESS;
-import static cn.iocoder.yudao.framework.operatelogv2.core.enums.OperateLogV2Constants.*;
-
-// TODO @puhui999:这个类,是不是可以删除哈;简化简化
-/**
- * 拦截使用 @Operation 注解, 获取操作类型、开始时间、持续时间、方法相关信息、执行结果等信息
- * 对 mzt-biz-log 日志信息进行增强
- *
- * @author HUIHUI
- */
-@Aspect
-@Slf4j
-public class OperateLogV2Aspect {
-
-    /**
-     * 用于记录操作内容的上下文
-     *
-     * @see OperateLogV2CreateReqDTO#getContent()
-     */
-    private static final ThreadLocal<LogRecord> CONTENT = new ThreadLocal<>();
-    /**
-     * 用于记录拓展字段的上下文
-     *
-     * @see OperateLogV2CreateReqDTO#getExtra()
-     */
-    private static final ThreadLocal<Map<String, Object>> EXTRA = new ThreadLocal<>();
-
-    @Resource
-    private OperateLogApi operateLogApi;
-
-    @Around("@annotation(operation)")
-    public Object around(ProceedingJoinPoint joinPoint, Operation operation) throws Throwable {
-        RequestMethod requestMethod = obtainFirstMatchRequestMethod(obtainRequestMethod(joinPoint));
-        if (requestMethod == RequestMethod.GET) { // 跳过 get 方法
-            return joinPoint.proceed();
-        }
-
-        // 目前,只有管理员,才记录操作日志!所以非管理员,直接调用,不进行记录
-        Integer userType = WebFrameworkUtils.getLoginUserType();
-        if (ObjUtil.notEqual(userType, UserTypeEnum.ADMIN.getValue())) {
-            return joinPoint.proceed();
-        }
-
-        // 记录开始时间
-        LocalDateTime startTime = LocalDateTime.now();
-        try {
-            // 执行原有方法
-            Object result = joinPoint.proceed();
-            // 记录正常执行时的操作日志
-            this.log(joinPoint, operation, startTime, result, null);
-            return result;
-        } catch (Throwable exception) {
-            this.log(joinPoint, operation, startTime, null, exception);
-            throw exception;
-        } finally {
-            clearThreadLocal();
-        }
-    }
-
-    public static void setContent(LogRecord content) {
-        CONTENT.set(content);
-    }
-
-    public static void addExtra(String key, Object value) {
-        if (EXTRA.get() == null) {
-            EXTRA.set(new HashMap<>());
-        }
-        EXTRA.get().put(key, value);
-    }
-
-    public static void addExtra(Map<String, Object> extra) {
-        if (EXTRA.get() == null) {
-            EXTRA.set(new HashMap<>());
-        }
-        EXTRA.get().putAll(extra);
-    }
-
-    private static void clearThreadLocal() {
-        CONTENT.remove();
-        EXTRA.remove();
-    }
-
-    private void log(ProceedingJoinPoint joinPoint, Operation operation,
-                     LocalDateTime startTime, Object result, Throwable exception) {
-        try {
-            // 判断不记录的情况(默认没有值就是记录)
-            if (EXTRA.get() != null && EXTRA.get().get(ENABLE) != null) {
-                return;
-            }
-            if (CONTENT.get() == null) { // 没有值说明没有日志需要记录
-                return;
-            }
-
-            // 真正记录操作日志
-            this.log0(joinPoint, operation, startTime, result, exception);
-        } catch (Throwable ex) {
-            log.error("[log][记录操作日志时,发生异常,其中参数是 joinPoint({}) apiOperation({}) result({}) exception({}) ]",
-                    joinPoint, operation, result, exception, ex);
-        }
-    }
-
-    private void log0(ProceedingJoinPoint joinPoint, Operation operation,
-                      LocalDateTime startTime, Object result, Throwable exception) {
-        OperateLogV2CreateReqDTO reqDTO = new OperateLogV2CreateReqDTO();
-        // 补全通用字段
-        reqDTO.setTraceId(TracerUtils.getTraceId());
-        reqDTO.setStartTime(startTime);
-        // 补充用户信息
-        fillUserFields(reqDTO);
-        // 补全模块信息
-        fillModuleFields(reqDTO, operation);
-        // 补全请求信息
-        fillRequestFields(reqDTO);
-        // 补全方法信息
-        fillMethodFields(reqDTO, joinPoint, startTime, result, exception);
-
-        // 异步记录日志
-        operateLogApi.createOperateLogV2(reqDTO);
-    }
-
-    private static void fillUserFields(OperateLogV2CreateReqDTO reqDTO) {
-        reqDTO.setUserId(WebFrameworkUtils.getLoginUserId());
-        reqDTO.setUserType(WebFrameworkUtils.getLoginUserType());
-    }
-
-    private static void fillModuleFields(OperateLogV2CreateReqDTO reqDTO, Operation operation) {
-        LogRecord logRecord = CONTENT.get();
-        reqDTO.setBizId(Long.parseLong(logRecord.getBizNo())); // 操作模块业务编号
-        reqDTO.setContent(logRecord.getAction());// 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。
-
-        // type 属性
-        reqDTO.setType(logRecord.getType()); // 大模块类型如 crm 客户
-        // subType 属性
-        if (logRecord.getSubType() != null) {
-            reqDTO.setSubType(logRecord.getSubType());// 操作名称如 转移客户
-        }
-        if (StrUtil.isEmpty(reqDTO.getSubType()) && operation != null) {
-            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) {
-        // 获得 Request 对象
-        HttpServletRequest request = ServletUtils.getRequest();
-        if (request == null) {
-            return;
-        }
-        // 补全请求信息
-        reqDTO.setRequestMethod(request.getMethod());
-        reqDTO.setRequestUrl(request.getRequestURI());
-        reqDTO.setUserIp(ServletUtils.getClientIP(request));
-        reqDTO.setUserAgent(ServletUtils.getUserAgent(request));
-    }
-
-    private static void fillMethodFields(OperateLogV2CreateReqDTO reqDTO, ProceedingJoinPoint joinPoint, LocalDateTime startTime,
-                                         Object result, Throwable exception) {
-        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
-        reqDTO.setJavaMethod(methodSignature.toString());
-        if (EXTRA.get().get(IS_LOG_ARGS) == null) {
-            reqDTO.setJavaMethodArgs(obtainMethodArgs(joinPoint));
-        }
-        if (EXTRA.get().get(IS_LOG_RESULT_DATA) == null) {
-            reqDTO.setResultData(obtainResultData(result));
-        }
-        reqDTO.setDuration((int) (LocalDateTimeUtil.between(startTime, LocalDateTime.now()).toMillis()));
-        // (正常)处理 resultCode 和 resultMsg 字段
-        if (result instanceof CommonResult) {
-            CommonResult<?> commonResult = (CommonResult<?>) result;
-            reqDTO.setResultCode(commonResult.getCode());
-            reqDTO.setResultMsg(commonResult.getMsg());
-        } else {
-            reqDTO.setResultCode(SUCCESS.getCode());
-        }
-        // (异常)处理 resultCode 和 resultMsg 字段
-        if (exception != null) {
-            reqDTO.setResultCode(INTERNAL_SERVER_ERROR.getCode());
-            reqDTO.setResultMsg(ExceptionUtil.getRootCauseMessage(exception));
-        }
-    }
-
-    @SuppressWarnings("SameParameterValue")
-    private static <T extends Annotation> T getClassAnnotation(ProceedingJoinPoint joinPoint, Class<T> annotationClass) {
-        return ((MethodSignature) joinPoint.getSignature()).getMethod().getDeclaringClass().getAnnotation(annotationClass);
-    }
-
-    private static String obtainMethodArgs(ProceedingJoinPoint joinPoint) {
-        // TODO 提升:参数脱敏和忽略
-        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
-        String[] argNames = methodSignature.getParameterNames();
-        Object[] argValues = joinPoint.getArgs();
-        // 拼接参数
-        Map<String, Object> args = Maps.newHashMapWithExpectedSize(argValues.length);
-        for (int i = 0; i < argNames.length; i++) {
-            String argName = argNames[i];
-            Object argValue = argValues[i];
-            // 被忽略时,标记为 ignore 字符串,避免和 null 混在一起
-            args.put(argName, !isIgnoreArgs(argValue) ? argValue : "[ignore]");
-        }
-        return JsonUtils.toJsonString(args);
-    }
-
-    private static String obtainResultData(Object result) {
-        // TODO 提升:结果脱敏和忽略
-        if (result instanceof CommonResult) {
-            result = ((CommonResult<?>) result).getData();
-        }
-        return JsonUtils.toJsonString(result);
-    }
-
-    private static boolean isIgnoreArgs(Object object) {
-        Class<?> clazz = object.getClass();
-        // 处理数组的情况
-        if (clazz.isArray()) {
-            return IntStream.range(0, Array.getLength(object))
-                    .anyMatch(index -> isIgnoreArgs(Array.get(object, index)));
-        }
-        // 递归,处理数组、Collection、Map 的情况
-        if (Collection.class.isAssignableFrom(clazz)) {
-            return ((Collection<?>) object).stream()
-                    .anyMatch((Predicate<Object>) OperateLogV2Aspect::isIgnoreArgs);
-        }
-        if (Map.class.isAssignableFrom(clazz)) {
-            return isIgnoreArgs(((Map<?, ?>) object).values());
-        }
-        // obj
-        return object instanceof MultipartFile
-                || object instanceof HttpServletRequest
-                || object instanceof HttpServletResponse
-                || object instanceof BindingResult;
-    }
-
-    private static RequestMethod obtainFirstMatchRequestMethod(RequestMethod[] requestMethods) {
-        if (ArrayUtil.isEmpty(requestMethods)) {
-            return null;
-        }
-        // 优先,匹配最优的 POST、PUT、DELETE
-        RequestMethod result = obtainFirstLogRequestMethod(requestMethods);
-        if (result != null) {
-            return result;
-        }
-        // 然后,匹配次优的 GET
-        result = Arrays.stream(requestMethods).filter(requestMethod -> requestMethod == RequestMethod.GET)
-                .findFirst().orElse(null);
-        if (result != null) {
-            return result;
-        }
-        // 兜底,获得第一个
-        return requestMethods[0];
-    }
-
-    private static RequestMethod[] obtainRequestMethod(ProceedingJoinPoint joinPoint) {
-        RequestMapping requestMapping = AnnotationUtils.getAnnotation( // 使用 Spring 的工具类,可以处理 @RequestMapping 别名注解
-                ((MethodSignature) joinPoint.getSignature()).getMethod(), RequestMapping.class);
-        return requestMapping != null ? requestMapping.method() : new RequestMethod[]{};
-    }
-
-    private static RequestMethod obtainFirstLogRequestMethod(RequestMethod[] requestMethods) {
-        if (ArrayUtil.isEmpty(requestMethods)) {
-            return null;
-        }
-        return Arrays.stream(requestMethods).filter(requestMethod ->
-                        requestMethod == RequestMethod.POST
-                                || requestMethod == RequestMethod.PUT
-                                || requestMethod == RequestMethod.DELETE)
-                .findFirst().orElse(null);
-    }
-
-}

+ 0 - 35
yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/enums/OperateLogV2Constants.java

@@ -1,35 +0,0 @@
-package cn.iocoder.yudao.framework.operatelogv2.core.enums;
-
-// TODO @puhui999:这个类,是不是可以删除哈;
-/**
- * 操作日志常量接口
- *
- * @author HUIHUI
- */
-public interface OperateLogV2Constants {
-
-    // ========== 开关字段-如果没有值默认就是记录 ==========
-
-    /**
-     * 是否记录日志
-     */
-    String ENABLE = "enable";
-
-    /**
-     * 是否记录方法参数
-     */
-    String IS_LOG_ARGS = "isLogArgs";
-
-    /**
-     * 是否记录方法结果的数据
-     */
-    String IS_LOG_RESULT_DATA = "isLogResultData";
-
-    // ========== 扩展 ==========
-
-    /**
-     * 扩展信息
-     */
-    String EXTRA_KEY = "extra";
-
-}

+ 0 - 39
yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/service/ILogRecordServiceImpl.java

@@ -1,39 +0,0 @@
-package cn.iocoder.yudao.framework.operatelogv2.core.service;
-
-import cn.iocoder.yudao.framework.operatelogv2.core.aop.OperateLogV2Aspect;
-import com.mzt.logapi.beans.LogRecord;
-import com.mzt.logapi.context.LogRecordContext;
-import com.mzt.logapi.service.ILogRecordService;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * 操作日志 ILogRecordService 实现类
- *
- * 基于 {@link OperateLogV2Aspect} 实现,记录操作日志
- *
- * @author HUIHUI
- */
-@Slf4j
-public class ILogRecordServiceImpl implements ILogRecordService {
-
-    @Override
-    public void record(LogRecord logRecord) {
-        OperateLogV2Aspect.setContent(logRecord); // 操作日志
-        OperateLogV2Aspect.addExtra(LogRecordContext.getVariables()); // 扩展信息
-        // TODO @puhui999:这里是不是调用 operateLogApi 进行记录哈
-    }
-
-    @Override
-    public List<LogRecord> queryLog(String bizNo, String type) {
-        throw new UnsupportedOperationException("不支持该操作,请使用 OperateLogApi 查询!");
-    }
-
-    @Override
-    public List<LogRecord> queryLogByBizNo(String bizNo, String type, String subType) {
-        throw new UnsupportedOperationException("不支持该操作,请使用 OperateLogApi 查询!");
-    }
-
-}

+ 0 - 1
yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/package-info.java

@@ -1 +0,0 @@
-package cn.iocoder.yudao.framework.operatelogv2;

+ 1 - 2
yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -1,2 +1 @@
-cn.iocoder.yudao.framework.operatelog.config.YudaoOperateLogAutoConfiguration
-cn.iocoder.yudao.framework.operatelogv2.config.YudaoOperateLogV2Configuration
+cn.iocoder.yudao.framework.operatelog.config.YudaoOperateLogAutoConfiguration

+ 7 - 0
yudao-framework/yudao-spring-boot-starter-security/pom.xml

@@ -50,6 +50,13 @@
             <artifactId>guava</artifactId>
         </dependency>
 
+        <dependency>
+            <!-- Spring Boot 通用操作日志组件,基于注解实现 -->
+            <!-- 此组件解决的问题是:「谁」在「什么时间」对「什么」做了「什么事」 -->
+            <groupId>io.github.mouzt</groupId>
+            <artifactId>bizlog-sdk</artifactId>
+        </dependency>
+
         <!-- 业务组件 -->
         <dependency>
             <groupId>cn.iocoder.boot</groupId>

+ 3 - 9
yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/config/YudaoOperateLogV2Configuration.java → yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogV2Configuration.java

@@ -1,7 +1,6 @@
-package cn.iocoder.yudao.framework.operatelogv2.config;
+package cn.iocoder.yudao.framework.operatelog.config;
 
-import cn.iocoder.yudao.framework.operatelogv2.core.aop.OperateLogV2Aspect;
-import cn.iocoder.yudao.framework.operatelogv2.core.service.ILogRecordServiceImpl;
+import cn.iocoder.yudao.framework.operatelog.core.service.ILogRecordServiceImpl;
 import com.mzt.logapi.service.ILogRecordService;
 import com.mzt.logapi.starter.annotation.EnableLogRecord;
 import lombok.extern.slf4j.Slf4j;
@@ -9,7 +8,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Primary;
 
-// TODO @puhui999:思考了下,为了减少 starter 数量,在 security 组件里,增加一个 core/operatelog 包,然后 YudaoOperateLogV2Configuration 搞一个过去;
+
 /**
  * mzt-biz-log 配置类
  *
@@ -26,9 +25,4 @@ public class YudaoOperateLogV2Configuration {
         return new ILogRecordServiceImpl();
     }
 
-    @Bean
-    public OperateLogV2Aspect operateLogV2Aspect() {
-        return new OperateLogV2Aspect();
-    }
-
 }

+ 1 - 0
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/package-info.java

@@ -0,0 +1 @@
+package cn.iocoder.yudao.framework.operatelog.core;

+ 83 - 0
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/ILogRecordServiceImpl.java

@@ -0,0 +1,83 @@
+package cn.iocoder.yudao.framework.operatelog.core.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.api.logger.dto.OperateLogV2CreateReqDTO;
+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 java.util.Collections;
+import java.util.List;
+
+/**
+ * 操作日志 ILogRecordService 实现类
+ *
+ * 基于 {@link OperateLogApi} 实现,记录操作日志
+ *
+ * @author HUIHUI
+ */
+@Slf4j
+public class ILogRecordServiceImpl implements ILogRecordService {
+
+    @Resource
+    private OperateLogApi operateLogApi;
+    
+    @Override
+    public void record(LogRecord logRecord) {
+        OperateLogV2CreateReqDTO reqDTO = new OperateLogV2CreateReqDTO();
+        // 补全通用字段
+        reqDTO.setTraceId(TracerUtils.getTraceId());
+        // 补充用户信息
+        fillUserFields(reqDTO);
+        // 补全模块信息
+        fillModuleFields(reqDTO, logRecord);
+        // 补全请求信息
+        fillRequestFields(reqDTO);
+        // 异步记录日志
+        operateLogApi.createOperateLogV2(reqDTO);
+        // TODO 测试结束删除或搞个开关
+        log.info("操作日志 ===> {}", reqDTO);
+    }
+
+    private static void fillUserFields(OperateLogV2CreateReqDTO reqDTO) {
+        reqDTO.setUserId(WebFrameworkUtils.getLoginUserId());
+        reqDTO.setUserType(WebFrameworkUtils.getLoginUserType());
+    }
+
+    public static void fillModuleFields(OperateLogV2CreateReqDTO reqDTO, LogRecord logRecord) {
+        reqDTO.setType(logRecord.getType()); // 大模块类型如 crm 客户
+        reqDTO.setSubType(logRecord.getSubType());// 操作名称如 转移客户
+        reqDTO.setBizId(Long.parseLong(logRecord.getBizNo())); // 操作模块业务编号
+        reqDTO.setAction(logRecord.getAction());// 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。
+        reqDTO.setExtra(logRecord.getExtra()); // 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 ),例如说,记录订单编号,{ orderId: "1"}
+    }
+
+    private static void fillRequestFields(OperateLogV2CreateReqDTO reqDTO) {
+        // 获得 Request 对象
+        HttpServletRequest request = ServletUtils.getRequest();
+        if (request == null) {
+            return;
+        }
+        // 补全请求信息
+        reqDTO.setRequestMethod(request.getMethod());
+        reqDTO.setRequestUrl(request.getRequestURI());
+        reqDTO.setUserIp(ServletUtils.getClientIP(request));
+        reqDTO.setUserAgent(ServletUtils.getUserAgent(request));
+    }
+
+    @Override
+    public List<LogRecord> queryLog(String bizNo, String type) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public List<LogRecord> queryLogByBizNo(String bizNo, String type, String subType) {
+        return Collections.emptyList();
+    }
+
+}

+ 2 - 1
yudao-framework/yudao-spring-boot-starter-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -1,2 +1,3 @@
 cn.iocoder.yudao.framework.security.config.YudaoSecurityAutoConfiguration
-cn.iocoder.yudao.framework.security.config.YudaoWebSecurityConfigurerAdapter
+cn.iocoder.yudao.framework.security.config.YudaoWebSecurityConfigurerAdapter
+cn.iocoder.yudao.framework.operatelog.config.YudaoOperateLogV2Configuration

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

@@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
-import cn.iocoder.yudao.framework.operatelogv2.core.vo.OperateLogV2PageReqVO;
 import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*;
 import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert;
 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
@@ -61,6 +60,7 @@ public class CrmCustomerController {
 
     @PostMapping("/create")
     @Operation(summary = "创建客户")
+    @OperateLog(enable = false) // TODO 关闭原有日志记录
     @PreAuthorize("@ss.hasPermission('crm:customer:create')")
     public CommonResult<Long> createCustomer(@Valid @RequestBody CrmCustomerCreateReqVO createReqVO) {
         return success(customerService.createCustomer(createReqVO, getLoginUserId()));
@@ -68,6 +68,7 @@ public class CrmCustomerController {
 
     @PutMapping("/update")
     @Operation(summary = "更新客户")
+    @OperateLog(enable = false) // TODO 关闭原有日志记录
     @PreAuthorize("@ss.hasPermission('crm:customer:update')")
     public CommonResult<Boolean> updateCustomer(@Valid @RequestBody CrmCustomerUpdateReqVO updateReqVO) {
         customerService.updateCustomer(updateReqVO);
@@ -76,6 +77,7 @@ public class CrmCustomerController {
 
     @DeleteMapping("/delete")
     @Operation(summary = "删除客户")
+    @OperateLog(enable = false) // TODO 关闭原有日志记录
     @Parameter(name = "id", description = "编号", required = true)
     @PreAuthorize("@ss.hasPermission('crm:customer:delete')")
     public CommonResult<Boolean> deleteCustomer(@RequestParam("id") Long id) {
@@ -132,6 +134,7 @@ public class CrmCustomerController {
 
     @PutMapping("/transfer")
     @Operation(summary = "客户转移")
+    @OperateLog(enable = false) // TODO 关闭原有日志记录
     @PreAuthorize("@ss.hasPermission('crm:customer:update')")
     public CommonResult<Boolean> transfer(@Valid @RequestBody CrmCustomerTransferReqVO reqVO) {
         customerService.transferCustomer(reqVO, getLoginUserId());
@@ -140,9 +143,8 @@ public class CrmCustomerController {
 
     @GetMapping("/operate-log-page")
     @Operation(summary = "获得客户操作日志")
-    @Parameter(name = "id", description = "编号", required = true, example = "1024")
     @PreAuthorize("@ss.hasPermission('crm:customer:query')")
-    public CommonResult<PageResult<OperateLogV2RespDTO>> getCustomerOperateLog(OperateLogV2PageReqVO reqVO) {
+    public CommonResult<PageResult<OperateLogV2RespDTO>> getCustomerOperateLog(CrmCustomerOperateLogPageReqVO reqVO) {
         reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页
         reqVO.setBizType(CRM_CUSTOMER);
         return success(operateLogApi.getOperateLogPage(BeanUtils.toBean(reqVO, OperateLogV2PageReqDTO.class)));
@@ -151,6 +153,7 @@ public class CrmCustomerController {
     // TODO @Joey:单独建一个属于自己业务的 ReqVO;因为前端如果模拟请求,是不是可以更新其它字段了;
     @PutMapping("/lock")
     @Operation(summary = "锁定/解锁客户")
+    @OperateLog(enable = false) // TODO 关闭原有日志记录
     @PreAuthorize("@ss.hasPermission('crm:customer:update')")
     public CommonResult<Boolean> lockCustomer(@Valid @RequestBody CrmCustomerUpdateReqVO updateReqVO) {
         customerService.lockCustomer(updateReqVO);
@@ -161,6 +164,7 @@ public class CrmCustomerController {
 
     @PutMapping("/put-pool")
     @Operation(summary = "数据放入公海")
+    @OperateLog(enable = false) // TODO 关闭原有日志记录
     @Parameter(name = "id", description = "客户编号", required = true, example = "1024")
     @PreAuthorize("@ss.hasPermission('crm:customer:update')")
     public CommonResult<Boolean> putCustomerPool(@RequestParam("id") Long id) {

+ 3 - 4
yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/vo/OperateLogV2PageReqVO.java → yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerOperateLogPageReqVO.java

@@ -1,13 +1,12 @@
-package cn.iocoder.yudao.framework.operatelogv2.core.vo;
+package cn.iocoder.yudao.module.crm.controller.admin.customer.vo;
 
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
-// TODO @puhui999:这个最好每个模块自己弄哈,放这里有点怪可能
-@Schema(description = "管理后台 - 操作日志分页 Request VO")
+@Schema(description = "管理后台 - crm 客户操作日志分页 Request VO")
 @Data
-public class OperateLogV2PageReqVO extends PageParam {
+public class CrmCustomerOperateLogPageReqVO extends PageParam {
 
     @Schema(description = "模块数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
     private Long bizId;

+ 4 - 10
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/parse/CrmIndustryParseFunction.java → yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmIndustryParseFunction.java

@@ -1,5 +1,6 @@
-package cn.iocoder.yudao.module.crm.framework.operatelog.parse;
+package cn.iocoder.yudao.module.crm.framework.operatelog.core;
 
+import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
 import com.mzt.logapi.service.IParseFunction;
@@ -8,7 +9,6 @@ import org.springframework.stereotype.Component;
 
 import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY;
 
-// TODO @puhui999:还是放在 core 包下哈;
 /**
  * 自定义函数-通过行业编号获取行业信息
  *
@@ -30,8 +30,7 @@ public class CrmIndustryParseFunction implements IParseFunction {
 
     @Override
     public String apply(Object value) {
-//        if (ObjUtil.isEmpty(value)) TODO @puhui999 可以直接替代哈;
-        if (value == null) {
+        if (ObjUtil.isEmpty(value)) {
             return "";
         }
         if (StrUtil.isEmpty(value.toString())) {
@@ -39,12 +38,7 @@ public class CrmIndustryParseFunction implements IParseFunction {
         }
 
         // 获取行业信息
-        // TODO @puhui999:这里可以不用 try catch 哇?
-        try {
-            return DictFrameworkUtils.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, value.toString());
-        } catch (Exception ignored) {
-        }
-        return "";
+        return DictFrameworkUtils.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, value.toString());
     }
 
 }

+ 5 - 7
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/parse/CrmLevelParseFunction.java → yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmLevelParseFunction.java

@@ -1,5 +1,6 @@
-package cn.iocoder.yudao.module.crm.framework.operatelog.parse;
+package cn.iocoder.yudao.module.crm.framework.operatelog.core;
 
+import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
 import com.mzt.logapi.service.IParseFunction;
@@ -29,7 +30,7 @@ public class CrmLevelParseFunction implements IParseFunction {
 
     @Override
     public String apply(Object value) {
-        if (value == null) {
+        if (ObjUtil.isEmpty(value)) {
             return "";
         }
         if (StrUtil.isEmpty(value.toString())) {
@@ -37,10 +38,7 @@ public class CrmLevelParseFunction implements IParseFunction {
         }
 
         // 获取客户等级信息
-        try {
-            return DictFrameworkUtils.getDictDataLabel(CRM_CUSTOMER_LEVEL, value.toString());
-        } catch (Exception ignored) {
-        }
-        return "";
+        return DictFrameworkUtils.getDictDataLabel(CRM_CUSTOMER_LEVEL, value.toString());
     }
+
 }

+ 5 - 7
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/parse/CrmSourceParseFunction.java → yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/core/CrmSourceParseFunction.java

@@ -1,5 +1,6 @@
-package cn.iocoder.yudao.module.crm.framework.operatelog.parse;
+package cn.iocoder.yudao.module.crm.framework.operatelog.core;
 
+import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
 import com.mzt.logapi.service.IParseFunction;
@@ -29,7 +30,7 @@ public class CrmSourceParseFunction implements IParseFunction {
 
     @Override
     public String apply(Object value) {
-        if (value == null) {
+        if (ObjUtil.isEmpty(value)) {
             return "";
         }
         if (StrUtil.isEmpty(value.toString())) {
@@ -37,10 +38,7 @@ public class CrmSourceParseFunction implements IParseFunction {
         }
 
         // 获取客户来源信息
-        try {
-            return DictFrameworkUtils.getDictDataLabel(CRM_CUSTOMER_SOURCE, value.toString());
-        } catch (Exception ignored) {
-        }
-        return "";
+        return DictFrameworkUtils.getDictDataLabel(CRM_CUSTOMER_SOURCE, value.toString());
     }
+
 }

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

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.crm.service.customer;
 import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 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.CrmCustomerPageReqVO;
 import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO;
@@ -53,7 +52,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#customerId}}", success = "创建了客户")
+    @LogRecord(type = CRM_CUSTOMER, subType = "创建客户", bizNo = "{{#customerId}}", success = "创建了客户")
     public Long createCustomer(CrmCustomerCreateReqVO createReqVO, Long userId) {
         // 插入
         CrmCustomerDO customer = CrmCustomerConvert.INSTANCE.convert(createReqVO);
@@ -71,7 +70,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
     // TODO @puhui999:测试下,能不能打出用户数据的变更。啊哈,可以打完微信发我下;
     @Override
     @Transactional(rollbackFor = Exception.class)
-    @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#updateReqVO.id}}", success = "更新了客户{_DIFF{#updateReqVO}}")
+    @LogRecord(type = CRM_CUSTOMER, subType = "更新客户", bizNo = "{{#updateReqVO.id}}", success = "更新了客户{_DIFF{#updateReqVO}}", extra = "{{#extra}}")
     @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
     public void updateCustomer(CrmCustomerUpdateReqVO updateReqVO) {
         // 校验存在
@@ -83,14 +82,15 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
 
         // __DIFF 函数传递了一个参数,传递的参数是修改之后的对象,这种方式需要在方法内部向 LogRecordContext 中 put 一个变量,代表是之前的对象,这个对象可以是null
         LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldCustomerDO, CrmCustomerUpdateReqVO.class));
+        // TODO 扩展信息测试
         HashMap<String, Object> extra = new HashMap<>();
         extra.put("tips", "随便记录一点啦");
-        LogRecordContext.putVariable(OperateLogV2Constants.EXTRA_KEY, extra);
+        LogRecordContext.putVariable("extra", extra);
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#id}}", success = "删除了客户")
+    @LogRecord(type = CRM_CUSTOMER, subType = "删除客户", bizNo = "{{#id}}", success = "删除了客户")
     @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER)
     public void deleteCustomer(Long id) {
         // 校验存在
@@ -141,7 +141,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#reqVO.id}}", success = TRANSFER_CUSTOMER_LOG_SUCCESS)
+    @LogRecord(type = CRM_CUSTOMER, subType = "客户转移", bizNo = "{{#reqVO.id}}", success = TRANSFER_CUSTOMER_LOG_SUCCESS)
     @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER)
     public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) {
         // 1. 校验客户是否存在
@@ -158,7 +158,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
     }
 
     @Override
-    @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#updateReqVO.id}}", success = "锁定了客户")
+    @LogRecord(type = CRM_CUSTOMER, subType = "锁定/解锁客户", bizNo = "{{#updateReqVO.id}}", success = "锁定了客户")
     public void lockCustomer(CrmCustomerUpdateReqVO updateReqVO) {
         // 校验存在
         validateCustomerExists(updateReqVO.getId());
@@ -172,7 +172,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#id}}", success = "将客户放入了公海")
+    @LogRecord(type = CRM_CUSTOMER, subType = "客户放入公海", bizNo = "{{#id}}", success = "将客户放入了公海")
     @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER)
     public void putCustomerPool(Long id) {
         // 1. 校验存在

+ 2 - 39
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogV2CreateReqDTO.java

@@ -5,9 +5,6 @@ import jakarta.validation.constraints.NotEmpty;
 import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 
-import java.time.LocalDateTime;
-import java.util.Map;
-
 /**
  * 系统操作日志 Create Req BO
  *
@@ -56,12 +53,12 @@ public class OperateLogV2CreateReqDTO {
      * 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。
      */
     @NotEmpty(message = "操作内容不能为空")
-    private String content;
+    private String action;
     /**
      * 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 )
      * 例如说,记录订单编号,{ orderId: "1"}
      */
-    private Map<String, Object> extra;
+    private String extra;
 
     /**
      * 请求方法名
@@ -84,38 +81,4 @@ public class OperateLogV2CreateReqDTO {
     @NotEmpty(message = "浏览器 UA 不能为空")
     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;
-
 }

+ 2 - 44
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogV2RespDTO.java

@@ -2,9 +2,6 @@ package cn.iocoder.yudao.module.system.api.logger.dto;
 
 import lombok.Data;
 
-import java.time.LocalDateTime;
-import java.util.Map;
-
 /**
  * 系统操作日志 Resp DTO
  *
@@ -44,11 +41,11 @@ public class OperateLogV2RespDTO {
     /**
      * 操作内容
      */
-    private String content;
+    private String action;
     /**
      * 拓展字段
      */
-    private Map<String, Object> extra;
+    private String extra;
 
     /**
      * 请求方法名
@@ -67,43 +64,4 @@ public class OperateLogV2RespDTO {
      */
     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;
-
-    /**
-     * 创建时间
-     */
-    private LocalDateTime createTime;
-
 }

+ 3 - 15
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApiImpl.java

@@ -2,11 +2,11 @@ package cn.iocoder.yudao.module.system.api.logger;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
 import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2CreateReqDTO;
 import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2PageReqDTO;
 import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2RespDTO;
+import cn.iocoder.yudao.module.system.convert.logger.OperateLogConvert;
 import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogV2DO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 import cn.iocoder.yudao.module.system.service.logger.OperateLogService;
@@ -17,10 +17,8 @@ import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import java.util.List;
-import java.util.Map;
 
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
-import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 
 /**
  * 操作日志 API 实现类
@@ -56,17 +54,7 @@ public class OperateLogApiImpl implements OperateLogApi {
 
         // 获取用户
         List<AdminUserDO> userList = adminUserService.getUserList(convertSet(operateLogPage.getList(), OperateLogV2DO::getUserId));
-        return BeanUtils.toBean(operateLogPage, OperateLogV2RespDTO.class).setList(setUserInfo(operateLogPage.getList(), userList));
-    }
-
-    // TODO @puhui999:这种 convert 还是放到 convert 类里,
-    private static List<OperateLogV2RespDTO> setUserInfo(List<OperateLogV2DO> logList, List<AdminUserDO> userList) {
-        Map<Long, AdminUserDO> userMap = convertMap(userList, AdminUserDO::getId);
-        return convertList(logList, item -> {
-            OperateLogV2RespDTO respDTO = BeanUtils.toBean(item, OperateLogV2RespDTO.class);
-            findAndThen(userMap, item.getUserId(), user -> respDTO.setUserName(user.getNickname()));
-            return respDTO;
-        });
+        return OperateLogConvert.INSTANCE.convertPage(operateLogPage, userList);
     }
 
 }

+ 19 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/logger/OperateLogConvert.java

@@ -1,10 +1,13 @@
 package cn.iocoder.yudao.module.system.convert.logger;
 
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2RespDTO;
 import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogRespVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogV2DO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
@@ -12,6 +15,9 @@ import org.mapstruct.factory.Mappers;
 import java.util.List;
 import java.util.Map;
 
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
+
 @Mapper
 public interface OperateLogConvert {
 
@@ -25,4 +31,17 @@ public interface OperateLogConvert {
         });
     }
 
+    default PageResult<OperateLogV2RespDTO> convertPage(PageResult<OperateLogV2DO> operateLogPage, List<AdminUserDO> userList) {
+        return BeanUtils.toBean(operateLogPage, OperateLogV2RespDTO.class).setList(setUserInfo(operateLogPage.getList(), userList));
+    }
+
+    private static List<OperateLogV2RespDTO> setUserInfo(List<OperateLogV2DO> logList, List<AdminUserDO> userList) {
+        Map<Long, AdminUserDO> userMap = convertMap(userList, AdminUserDO::getId);
+        return CollectionUtils.convertList(logList, item -> {
+            OperateLogV2RespDTO respDTO = BeanUtils.toBean(item, OperateLogV2RespDTO.class);
+            findAndThen(userMap, item.getUserId(), user -> respDTO.setUserName(user.getNickname()));
+            return respDTO;
+        });
+    }
+
 }

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

@@ -1,19 +1,13 @@
 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 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
  *
@@ -25,16 +19,6 @@ import java.util.Map;
 @EqualsAndHashCode(callSuper = true)
 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;
-
     /**
      * 日志主键
      */
@@ -70,20 +54,18 @@ public class OperateLogV2DO extends BaseDO {
      * 操作模块业务编号
      */
     private Long bizId;
-    // TODO @puhui999:content 改成 action,extra 换成 String。注释就直接用 mzt,和它完全对应好了。
     /**
-     * 操作内容,记录整个操作的明细
+     * 日志内容,记录整个操作的明细
      *
      * 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。
      */
-    private String content;
+    private String action;
     /**
      * 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 )
      *
      * 例如说,记录订单编号,{ orderId: "1"}
      */
-    @TableField(typeHandler = JacksonTypeHandler.class)
-    private Map<String, Object> extra;
+    private String extra;
 
     /**
      * 请求方法名
@@ -102,44 +84,4 @@ public class OperateLogV2DO extends BaseDO {
      */
     private String userAgent;
 
-    // TODO @puhui999:微信已经讨论,下面的字段都不要哈;
-    /**
-     * 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;
-
 }

+ 3 - 6
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/parse/AdminUserParseFunction.java → yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AdminUserParseFunction.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.system.framework.operatelog.parse;
+package cn.iocoder.yudao.module.system.framework.operatelog.core;
 
 import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.StrUtil;
@@ -9,7 +9,6 @@ import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 
-// TODO @puhui999:这个微信讨论下,function 叫啥好哈;
 /**
  * 自定义函数-通过用户编号获取用户信息
  *
@@ -27,15 +26,12 @@ public class AdminUserParseFunction implements IParseFunction {
         return "getAdminUserById";
     }
 
-    // TODO @puhui999:这个方法的实现优化下哈;
     @Override
     public String apply(Object value) {
-        if (value == null) {
-            //log.warn("(getAdminUserById) 解析异常参数为 null");
+        if (ObjUtil.isEmpty(value)) {
             return "";
         }
         if (StrUtil.isEmpty(value.toString())) {
-            //log.warn("(getAdminUserById) 解析异常参数为空");
             return "";
         }
 
@@ -52,4 +48,5 @@ public class AdminUserParseFunction implements IParseFunction {
         }
         return nickname;
     }
+
 }

+ 3 - 3
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/parse/AreaParseFunction.java → yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/core/AreaParseFunction.java

@@ -1,12 +1,12 @@
-package cn.iocoder.yudao.module.system.framework.operatelog.parse;
+package cn.iocoder.yudao.module.system.framework.operatelog.core;
 
+import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
 import com.mzt.logapi.service.IParseFunction;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 
-// TODO @puhui999:还是放在 core 包下哈;
 /**
  * 自定义函数-通过区域编号获取区域信息
  *
@@ -28,7 +28,7 @@ public class AreaParseFunction implements IParseFunction {
 
     @Override
     public String apply(Object value) {
-        if (value == null) {
+        if (ObjUtil.isEmpty(value)) {
             return "";
         }
         if (StrUtil.isEmpty(value.toString())) {

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

@@ -71,8 +71,6 @@ public class OperateLogServiceImpl implements OperateLogService {
     @Override
     public void createOperateLogV2(OperateLogV2CreateReqDTO createReqBO) {
         OperateLogV2DO log = BeanUtils.toBean(createReqBO, 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);
     }
 

+ 5 - 6
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java

@@ -21,15 +21,14 @@ import cn.iocoder.yudao.module.system.service.social.SocialUserService;
 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
 import com.xingyuv.captcha.model.common.ResponseModel;
 import com.xingyuv.captcha.service.CaptchaService;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.mock.mockito.MockBean;
-import org.springframework.context.annotation.Import;
-
 import jakarta.annotation.Resource;
 import jakarta.validation.ConstraintViolationException;
 import jakarta.validation.Validation;
 import jakarta.validation.Validator;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Import;
 
 import static cn.hutool.core.util.RandomUtil.randomEle;
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
@@ -237,7 +236,7 @@ public class AdminAuthServiceImplTest extends BaseDbUnitTest {
         // mock 方法(绑定的用户编号)
         Long userId = 1L;
         when(socialUserService.getSocialUserByCode(eq(UserTypeEnum.ADMIN.getValue()), eq(reqVO.getType()),
-                eq(reqVO.getCode()), eq(reqVO.getState()))).thenReturn(new SocialUserRespDTO(randomString(), userId));
+                eq(reqVO.getCode()), eq(reqVO.getState()))).thenReturn(new SocialUserRespDTO(randomString(), randomString(), randomString(), userId));
         // mock(用户)
         AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(userId));
         when(userService.getUser(eq(userId))).thenReturn(user);