日志切面组件

This commit is contained in:
2025-11-21 15:28:59 +08:00
parent 26265bfd0e
commit 3eddcf59ad
20 changed files with 306 additions and 13 deletions
+1
View File
@@ -17,6 +17,7 @@
<modules>
<module>xiaoyi-common</module>
<module>xiaoyi-spring-boot-starter-biz-operationlog</module>
</modules>
</project>
+16
View File
@@ -20,6 +20,22 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- Jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<!-- 解决 Jackson Java 8 新日期 API 的序列化问题 -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,36 @@
package top.crushtj.framework.common.utils;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.SneakyThrows;
/**
*
* @Title: JsonUtils
* @Description: JSON 工具类
* @Author: ayi
* @Date: 2025/11/21
*/
public class JsonUtils {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
static {
OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
OBJECT_MAPPER.registerModules(new JavaTimeModule()); // 解决 LocalDateTime 的序列化问题
}
/**
* 将对象转换为 JSON 字符串
*
* @param obj 要转换的对象
* @return JSON 字符串
*/
@SneakyThrows
public static String toJsonString(Object obj) {
return OBJECT_MAPPER.writeValueAsString(obj);
}
}
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>top.crushtj</groupId>
<artifactId>xiaoyi-framework</artifactId>
<version>${revision}</version>
</parent>
<artifactId>xiaoyi-spring-boot-starter-biz-operationlog</artifactId>
<name>${project.artifactId}</name>
<description>平台基础设施层:操作日志记录器</description>
<dependencies>
<dependency>
<groupId>top.crushtj</groupId>
<artifactId>xiaoyi-common</artifactId>
</dependency>
<!-- AOP 切面 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,100 @@
package top.crushtj.framework.biz.operationlog;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import lombok.extern.slf4j.Slf4j;
import top.crushtj.framework.biz.operationlog.aspect.ApiOperationLog;
import top.crushtj.framework.common.utils.JsonUtils;
@Slf4j
@Aspect
public class ApiOperationLogAspect {
/** 以自定义 @ApiOperationLog 注解为切点,凡是添加 @ApiOperationLog 的方法,都会执行环绕中的代码 */
@Pointcut("@annotation(top.crushtj.framework.biz.operationlog.aspect.ApiOperationLog)")
public void apiOperationLog() {
}
/**
* 环绕
*
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("apiOperationLog()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 请求开始时间
long startTime = System.currentTimeMillis();
// 获取被请求的类和方法
String className = joinPoint.getTarget()
.getClass()
.getSimpleName();
String methodName = joinPoint.getSignature()
.getName();
// 请求入参
Object[] args = joinPoint.getArgs();
// 入参转 JSON 字符串
String argsJsonStr = Arrays.stream(args)
.map(toJsonStr())
.collect(Collectors.joining(", "));
// 功能描述信息
String description = getApiOperationLogDescription(joinPoint);
// 打印请求相关参数
log.info("====== 请求开始: [{}], 入参: {}, 请求类: {}, 请求方法: {} =================================== ", description,
argsJsonStr, className, methodName);
// 执行切点方法
Object result = joinPoint.proceed();
// 执行耗时
long executionTime = System.currentTimeMillis() - startTime;
// 打印出参等相关信息
log.info("====== 请求结束: [{}], 耗时: {}ms, 出参: {} =================================== ", description, executionTime,
JsonUtils.toJsonString(result));
return result;
}
/**
* 获取注解的描述信息
*
* @param joinPoint
* @return
*/
private String getApiOperationLogDescription(ProceedingJoinPoint joinPoint) {
// 1. 从 ProceedingJoinPoint 获取 MethodSignature
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
// 2. 使用 MethodSignature 获取当前被注解的 Method
Method method = signature.getMethod();
// 3. 从 Method 中提取 LogExecution 注解
ApiOperationLog apiOperationLog = method.getAnnotation(ApiOperationLog.class);
// 4. 从 LogExecution 注解中获取 description 属性
return apiOperationLog.description();
}
/**
* 转 JSON 字符串
*
* @return
*/
private Function<Object, String> toJsonStr() {
return JsonUtils::toJsonString;
}
}
@@ -0,0 +1,26 @@
package top.crushtj.framework.biz.operationlog.aspect;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @Title: ApiOperationLog
* @Description: 自定义注解,用于标记需要记录操作日志的方法
* @Author: ayi
* @Date: 2025/11/21
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface ApiOperationLog {
/**
* API 功能描述
*
* @return
*/
String description() default "";
}
@@ -0,0 +1,15 @@
package top.crushtj.framework.biz.operationlog.config;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import top.crushtj.framework.biz.operationlog.ApiOperationLogAspect;
@AutoConfiguration
public class ApiOperationLogAutoConfiguration {
@Bean
public ApiOperationLogAspect apiOperationLogAspect() {
return new ApiOperationLogAspect();
}
}
@@ -0,0 +1 @@
top.crushtj.framework.biz.operationlog.config.ApiOperationLogAutoConfiguration