diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 9cdbbc2..dc0d1fa 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -8,8 +8,12 @@
-
+
+
+
+
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 850799d..dea5dca 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -3,8 +3,6 @@
-
-
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 9a39965..17ac4cc 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,12 +1,14 @@
plugins {
java
+ // Spring Boot 插件:声明,但不应用到父工程
id("org.springframework.boot") version "3.5.8" apply false
- id("io.spring.dependency-management") version "1.1.7" apply false
+
+ // Spring 的 dependency-management 插件:父工程和子工程都需要
+ id("io.spring.dependency-management") version "1.1.7"
}
group = "com.hanserwei"
version = "0.0.1-SNAPSHOT"
-description = "weblog-springboot"
java {
toolchain {
@@ -14,12 +16,6 @@ java {
}
}
-buildscript {
- repositories {
- mavenCentral()
- }
-}
-
allprojects {
group = "com.hanserwei"
version = "0.0.1-SNAPSHOT"
@@ -30,15 +26,28 @@ allprojects {
}
subprojects {
+
apply(plugin = "java")
apply(plugin = "io.spring.dependency-management")
java.sourceCompatibility = JavaVersion.VERSION_21
java.targetCompatibility = JavaVersion.VERSION_21
+ // ========= 统一版本管理(类似 Maven dependencyManagement)=========
+ dependencyManagement {
+ imports {
+ // Spring Boot 官方 BOM(最重要,统一管理绝大部分依赖版本)
+ mavenBom("org.springframework.boot:spring-boot-dependencies:3.5.8")
+ }
+ }
+
dependencies {
+
+ // Lombok (compileOnly + annotationProcessor)
compileOnly("org.projectlombok:lombok")
annotationProcessor("org.projectlombok:lombok")
+
+ // 如果你的测试也使用 Lombok
testCompileOnly("org.projectlombok:lombok")
testAnnotationProcessor("org.projectlombok:lombok")
}
diff --git a/weblog-module-common/build.gradle.kts b/weblog-module-common/build.gradle.kts
index 14e8e4a..3a9f1ed 100644
--- a/weblog-module-common/build.gradle.kts
+++ b/weblog-module-common/build.gradle.kts
@@ -8,7 +8,11 @@ dependencies {
implementation("com.google.guava:guava:33.5.0-jre")
// commons-lang3
implementation("org.apache.commons:commons-lang3:3.20.0")
-
// test
testImplementation("org.springframework.boot:spring-boot-starter-test")
+ // jackson
+ implementation("com.fasterxml.jackson.core:jackson-databind")
+ implementation("com.fasterxml.jackson.core:jackson-core")
+ // aop
+ implementation("org.springframework.boot:spring-boot-starter-aop")
}
diff --git a/weblog-module-common/src/main/java/com/hanserwei/common/aspect/ApiOperationLog.java b/weblog-module-common/src/main/java/com/hanserwei/common/aspect/ApiOperationLog.java
new file mode 100644
index 0000000..4b02d8c
--- /dev/null
+++ b/weblog-module-common/src/main/java/com/hanserwei/common/aspect/ApiOperationLog.java
@@ -0,0 +1,15 @@
+package com.hanserwei.common.aspect;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+@Documented
+public @interface ApiOperationLog {
+ /**
+ * API 功能描述
+ *
+ * @return API 功能描述
+ */
+ String description() default "";
+}
diff --git a/weblog-module-common/src/main/java/com/hanserwei/common/aspect/ApiOperationLogAspect.java b/weblog-module-common/src/main/java/com/hanserwei/common/aspect/ApiOperationLogAspect.java
new file mode 100644
index 0000000..7646d31
--- /dev/null
+++ b/weblog-module-common/src/main/java/com/hanserwei/common/aspect/ApiOperationLogAspect.java
@@ -0,0 +1,109 @@
+package com.hanserwei.common.aspect;
+
+import com.hanserwei.common.utils.JsonUtils;
+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;
+
+@Aspect
+@Component
+@Slf4j
+public class ApiOperationLogAspect {
+
+ /**
+ * 以自定义 @ApiOperationLog 注解为切点,凡是添加 @ApiOperationLog 的方法,都会执行环绕中的代码
+ */
+ @Pointcut("@annotation(com.hanserwei.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();
+
+ // 设置追踪ID到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(", "));
+
+ // 获取API操作日志注解中的描述信息
+ 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;
+ } finally {
+ // 清理MDC中的追踪ID
+ MDC.clear();
+ }
+ }
+
+ /**
+ * 获取API操作日志注解的描述信息
+ *
+ * @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 中提取 ApiOperationLog 注解
+ ApiOperationLog apiOperationLog = method.getAnnotation(ApiOperationLog.class);
+
+ // 4. 从 ApiOperationLog 注解中获取 description 属性
+ return apiOperationLog.description();
+ }
+
+ /**
+ * 转换对象为JSON字符串的函数
+ *
+ * @return 转换函数
+ */
+ private Function