diff --git a/pom.xml b/pom.xml index c99717e461a1ab112703cb2f799447bb88b147c1..3f208eb6dff1ff21873b7498b2b084d2e33691be 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,7 @@ 1.18.28 31.1-jre 3.12.0 + 2.15.2 @@ -68,6 +69,18 @@ commons-lang3 ${commons-lang3.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + diff --git a/weblog-module-common/pom.xml b/weblog-module-common/pom.xml index f0b3996eaa9592412289696642f6ebab1959a2be..926bebb316e57e798a6e3d467d47bfd03530fbc8 100644 --- a/weblog-module-common/pom.xml +++ b/weblog-module-common/pom.xml @@ -32,6 +32,22 @@ spring-boot-starter-test test + + + org.springframework.boot + spring-boot-starter-aop + + + + + com.fasterxml.jackson.core + jackson-databind + + + + com.fasterxml.jackson.core + jackson-core + diff --git a/weblog-module-common/src/main/java/com/qianyong/weblog/common/aspect/ApiOperationLog.java b/weblog-module-common/src/main/java/com/qianyong/weblog/common/aspect/ApiOperationLog.java new file mode 100644 index 0000000000000000000000000000000000000000..cd622f8c60b28215224f1d2f6c775e050568fc2e --- /dev/null +++ b/weblog-module-common/src/main/java/com/qianyong/weblog/common/aspect/ApiOperationLog.java @@ -0,0 +1,15 @@ +package com.qianyong.weblog.common.aspect; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +@Documented +public @interface ApiOperationLog { + + /** + * 操作描述 + * @return + */ + String description() default ""; +} diff --git a/weblog-module-common/src/main/java/com/qianyong/weblog/common/aspect/ApiOperationLogAspect.java b/weblog-module-common/src/main/java/com/qianyong/weblog/common/aspect/ApiOperationLogAspect.java new file mode 100644 index 0000000000000000000000000000000000000000..c6ba4f5ed76611680aa86ed2bf038c6326dedc52 --- /dev/null +++ b/weblog-module-common/src/main/java/com/qianyong/weblog/common/aspect/ApiOperationLogAspect.java @@ -0,0 +1,109 @@ +package com.qianyong.weblog.common.aspect; + +import com.qianyong.weblog.common.utils.JsonUtil; +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.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.MDC; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.UUID; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Created with IntelliJ IDEA. + * + * @author :xiaoduoduo + * @date :2025/07/20 + * @description:定义日志切面类 + * @version:1.0 + */ +@Aspect +@Component +@Slf4j +public class ApiOperationLogAspect { + /** 以自定义 @ApiOperationLog 注解为切点,凡是添加 @ApiOperationLog 的方法,都会执行环绕中的代码 */ + @Pointcut("@annotation(com.qianyong.weblog.common.aspect.ApiOperationLog)") + public void apiOperationLog() {} + + /** + * 环绕 + * @param joinPoint + * @return + * @throws Throwable + */ + @Around("apiOperationLog()") + public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { + try { + // 请求开始时间 + long startTime = System.currentTimeMillis(); + + // MDC + MDC.put("traceId", UUID.randomUUID().toString()); + + // 获取被请求的类和方法 + 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, JsonUtil.toJsonString(result)); + + return result; + } finally { + MDC.clear(); + } + } + + /** + * 获取注解的描述信息 + * @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 toJsonStr() { + return arg -> JsonUtil.toJsonString(arg); + } + +} diff --git a/weblog-module-common/src/main/java/com/qianyong/weblog/common/utils/JsonUtil.java b/weblog-module-common/src/main/java/com/qianyong/weblog/common/utils/JsonUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..65e3f3d42c260af29adc252127bb8af85f372626 --- /dev/null +++ b/weblog-module-common/src/main/java/com/qianyong/weblog/common/utils/JsonUtil.java @@ -0,0 +1,27 @@ +package com.qianyong.weblog.common.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; + +/** + * Created with IntelliJ IDEA. + * + * @author :xiaoduoduo + * @date :2025/07/20 + * @description:创建 JSON 工具类 + * @version:1.0 + */ +@Slf4j +public class JsonUtil { + + private static final ObjectMapper INSTANCE = new ObjectMapper(); + + public static String toJsonString(Object obj) { + try { + return INSTANCE.writeValueAsString(obj); + } catch (JsonProcessingException e) { + return obj.toString(); + } + } +} diff --git a/weblog-web/src/main/java/com/qianyong/weblogweb/WeblogWebApplication.java b/weblog-web/src/main/java/com/qianyong/weblog/web/WeblogWebApplication.java similarity index 56% rename from weblog-web/src/main/java/com/qianyong/weblogweb/WeblogWebApplication.java rename to weblog-web/src/main/java/com/qianyong/weblog/web/WeblogWebApplication.java index 4f52910fb924f78db3c78acea499dd0712acddfc..91df272c311aff55abb5931cd765cb685fbba4c1 100644 --- a/weblog-web/src/main/java/com/qianyong/weblogweb/WeblogWebApplication.java +++ b/weblog-web/src/main/java/com/qianyong/weblog/web/WeblogWebApplication.java @@ -1,9 +1,12 @@ -package com.qianyong.weblogweb; +package com.qianyong.weblog.web; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; @SpringBootApplication + +@ComponentScan({"com.qianyong.weblog.*"}) // 多模块项目中,必需手动指定扫描 com.quanxiaoha.weblog 包下面的所有类 public class WeblogWebApplication { public static void main(String[] args) { diff --git a/weblog-web/src/main/java/com/qianyong/weblog/web/controller/TestController.java b/weblog-web/src/main/java/com/qianyong/weblog/web/controller/TestController.java new file mode 100644 index 0000000000000000000000000000000000000000..6f7a2269d9d75514bc4b0beff9faab8bf3689e2e --- /dev/null +++ b/weblog-web/src/main/java/com/qianyong/weblog/web/controller/TestController.java @@ -0,0 +1,27 @@ +package com.qianyong.weblog.web.controller; + +import com.qianyong.weblog.common.aspect.ApiOperationLog; +import com.qianyong.weblog.web.model.User; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +/** + * Created with IntelliJ IDEA. + * + * @author :xiaoduoduo + * @date :2025/07/20 + * @description: + * @version:1.0 + */ +@RestController +@Slf4j +public class TestController { + @PostMapping("/test") + @ApiOperationLog(description = "测试接口") + public User test(@RequestBody User user) { + // 返参 + return user; + } +} diff --git a/weblog-web/src/main/java/com/qianyong/weblog/web/model/User.java b/weblog-web/src/main/java/com/qianyong/weblog/web/model/User.java new file mode 100644 index 0000000000000000000000000000000000000000..cab37b4534302fa61311b2c4f9951660e0329015 --- /dev/null +++ b/weblog-web/src/main/java/com/qianyong/weblog/web/model/User.java @@ -0,0 +1,19 @@ +package com.qianyong.weblog.web.model; + +import lombok.Data; + +/** + * Created with IntelliJ IDEA. + * + * @author :xiaoduoduo + * @date :2025/07/20 + * @description: + * @version:1.0 + */ +@Data +public class User { + // 用户名 + private String username; + // 性别 + private Integer sex; +} diff --git a/weblog-web/src/main/resources/application.yml b/weblog-web/src/main/resources/application.yml index c9c207c9062b0f1d98b532c0930e5d035c122c0b..c82c460f38df3fd02d2f26835d8ddab78e5824fa 100644 --- a/weblog-web/src/main/resources/application.yml +++ b/weblog-web/src/main/resources/application.yml @@ -1,6 +1,6 @@ spring: profiles: # 默认激活 dev 环境 - # active: dev - active: prod + active: dev + # active: prod diff --git a/weblog-web/src/test/java/com/qianyong/weblogweb/WeblogWebApplicationTests.java b/weblog-web/src/test/java/com/qianyong/weblog/web/WeblogWebApplicationTests.java similarity index 94% rename from weblog-web/src/test/java/com/qianyong/weblogweb/WeblogWebApplicationTests.java rename to weblog-web/src/test/java/com/qianyong/weblog/web/WeblogWebApplicationTests.java index e5e17adbe7b08d31829712e3207fb7fa4d88b939..aca88d84fd8a8d374f64f373913ec7d7287434fb 100644 --- a/weblog-web/src/test/java/com/qianyong/weblogweb/WeblogWebApplicationTests.java +++ b/weblog-web/src/test/java/com/qianyong/weblog/web/WeblogWebApplicationTests.java @@ -1,4 +1,4 @@ -package com.qianyong.weblogweb; +package com.qianyong.weblog.web; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test;