diff --git a/weblog-springboot-008/pom.xml b/weblog-springboot-008/pom.xml
new file mode 100644
index 0000000..a5bfef8
--- /dev/null
+++ b/weblog-springboot-008/pom.xml
@@ -0,0 +1,118 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+
+ 2.6.3
+
+
+
+ com.quanxiaoha
+ weblog-springboot
+ ${revision}
+ weblog-springboot
+
+ 前后端分离博客 Weblog By 犬小哈
+
+
+ pom
+
+
+
+
+ weblog-web
+
+ weblog-module-admin
+
+ weblog-module-common
+
+
+
+
+
+
+ 0.0.1-SNAPSHOT
+ 1.8
+ UTF-8
+
+ ${java.version}
+ ${java.version}
+
+
+ 1.18.28
+ 31.1-jre
+ 3.12.0
+ 2.15.2
+
+
+
+
+
+
+ com.quanxiaoha
+ weblog-module-admin
+ ${revision}
+
+
+
+ com.quanxiaoha
+ weblog-module-common
+ ${revision}
+
+
+
+
+ com.google.guava
+ guava
+ ${guava.version}
+
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.version}
+
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
+
+
+
+
+ aliyunmaven
+ aliyun
+ https://maven.aliyun.com/repository/public
+
+
+
diff --git a/weblog-springboot-008/weblog-module-admin/.gitignore b/weblog-springboot-008/weblog-module-admin/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/weblog-springboot-008/weblog-module-admin/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/weblog-springboot-008/weblog-module-admin/pom.xml b/weblog-springboot-008/weblog-module-admin/pom.xml
new file mode 100644
index 0000000..8256d34
--- /dev/null
+++ b/weblog-springboot-008/weblog-module-admin/pom.xml
@@ -0,0 +1,38 @@
+
+
+ 4.0.0
+
+
+ com.quanxiaoha
+ weblog-springboot
+ ${revision}
+
+
+ com.quanxiaoha
+ weblog-module-admin
+ weblog-module-admin
+ weblog-admin (负责管理后台相关功能)
+
+
+
+ com.quanxiaoha
+ weblog-module-common
+
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
\ No newline at end of file
diff --git a/weblog-springboot-008/weblog-module-admin/src/test/java/com/quanxiaoha/weblog/admin/WeblogModuleAdminApplicationTests.java b/weblog-springboot-008/weblog-module-admin/src/test/java/com/quanxiaoha/weblog/admin/WeblogModuleAdminApplicationTests.java
new file mode 100644
index 0000000..dab9a4b
--- /dev/null
+++ b/weblog-springboot-008/weblog-module-admin/src/test/java/com/quanxiaoha/weblog/admin/WeblogModuleAdminApplicationTests.java
@@ -0,0 +1,13 @@
+package com.quanxiaoha.weblog.admin;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class WeblogModuleAdminApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/weblog-springboot-008/weblog-module-common/.gitignore b/weblog-springboot-008/weblog-module-common/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/weblog-springboot-008/weblog-module-common/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/weblog-springboot-008/weblog-module-common/pom.xml b/weblog-springboot-008/weblog-module-common/pom.xml
new file mode 100644
index 0000000..8c1cd90
--- /dev/null
+++ b/weblog-springboot-008/weblog-module-common/pom.xml
@@ -0,0 +1,49 @@
+
+
+ 4.0.0
+
+ com.quanxiaoha
+ weblog-springboot
+ ${revision}
+
+
+ com.quanxiaoha
+ weblog-module-common
+ weblog-module-common
+ weblog-module-common (此模块用于存放一些通用的功能)
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+
+
diff --git a/weblog-springboot-008/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLog.java b/weblog-springboot-008/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLog.java
new file mode 100644
index 0000000..38eeb0f
--- /dev/null
+++ b/weblog-springboot-008/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLog.java
@@ -0,0 +1,17 @@
+package com.quanxiaoha.weblog.common.aspect;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+@Documented
+public @interface ApiOperationLog {
+ /**
+ * API 功能描述
+ *
+ * @return
+ */
+ String description() default "";
+
+}
+
diff --git a/weblog-springboot-008/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLogAspect.java b/weblog-springboot-008/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLogAspect.java
new file mode 100644
index 0000000..ef199b4
--- /dev/null
+++ b/weblog-springboot-008/weblog-module-common/src/main/java/com/quanxiaoha/weblog/common/aspect/ApiOperationLogAspect.java
@@ -0,0 +1,102 @@
+
+package com.quanxiaoha.weblog.common.aspect;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.quanxiaoha.weblog.common.utils.JsonUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.*;
+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.quanxiaoha.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