diff --git a/.gitignore b/.gitignore
index 3c1b776..af96345 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,10 +5,7 @@ target/
.kotlin
### IntelliJ IDEA ###
-.idea/modules.xml
-.idea/jarRepositories.xml
-.idea/compiler.xml
-.idea/libraries/
+.idea
*.iws
*.iml
*.ipr
@@ -18,7 +15,6 @@ target/
.classpath
.factorypath
.project
-.settings
.springBeans
.sts4-cache
@@ -34,4 +30,5 @@ build/
### Mac OS ###
-.DS_Store
\ No newline at end of file
+.DS_Store
+/.idea/
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..4e8eac9
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1 @@
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
\ No newline at end of file
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/.vscode/java-formatter.xml b/.vscode/java-formatter.xml
index ba43e02..9901b6b 100644
--- a/.vscode/java-formatter.xml
+++ b/.vscode/java-formatter.xml
@@ -376,5 +376,8 @@
+
+
+
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 82c8f32..735a4f2 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -7,6 +7,7 @@
"editor.accessibilitySupport": "auto",
"editor.fontFamily": "JetBrains Mono",
"java.compile.nullAnalysis.mode": "automatic",
- "java.configuration.updateBuildConfiguration": "interactive",
- "java.format.settings.url": ".vscode/java-formatter.xml"
+ "java.configuration.updateBuildConfiguration": "automatic",
+ "java.format.settings.url": ".vscode/java-formatter.xml",
+ "commentTranslate.targetLanguage": "zh-CN"
}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 2e7f7c1..0c0a8fd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,11 +38,23 @@
3.0.2
2022.0.0.0
2022.0.0
+ 2.16.1
+
+ top.crushtj
+ xiaoyi-common
+ ${revision}
+
+
+
+ top.crushtj
+ xiaoyi-spring-boot-starter-biz-operationlog
+ ${revision}
+
org.springframework.boot
@@ -77,6 +89,18 @@
${lombok.version}
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.version}
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${jackson.version}
+
diff --git a/xiaoyi-auth/pom.xml b/xiaoyi-auth/pom.xml
index a365dac..673794d 100644
--- a/xiaoyi-auth/pom.xml
+++ b/xiaoyi-auth/pom.xml
@@ -18,6 +18,15 @@
小壹书:认证服务(负责处理用户登录、注册、账号注销等)
+
+ top.crushtj
+ xiaoyi-common
+
+
+
+ top.crushtj
+ xiaoyi-spring-boot-starter-biz-operationlog
+
org.springframework.boot
spring-boot-starter-web
diff --git a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/controller/TestController.java b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/controller/TestController.java
new file mode 100644
index 0000000..71fc4e5
--- /dev/null
+++ b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/controller/TestController.java
@@ -0,0 +1,25 @@
+package top.crushtj.xiaoyishu.auth.controller;
+
+import org.springframework.web.bind.annotation.RestController;
+import top.crushtj.framework.biz.operationlog.aspect.ApiOperationLog;
+import top.crushtj.framework.common.response.Response;
+import org.springframework.web.bind.annotation.GetMapping;
+
+/**
+ *
+ * @Title: TestController
+ * @Description: 测试控制器
+ * @Author: ayi
+ * @Date: 2025/11/21
+ */
+
+@RestController
+public class TestController {
+
+ @GetMapping("/test")
+ @ApiOperationLog(description = "测试接口")
+ public Response testController() {
+ return Response.success("Hello World!");
+ }
+
+}
diff --git a/xiaoyi-auth/src/main/resources/application-dev.yml b/xiaoyi-auth/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..fce073c
--- /dev/null
+++ b/xiaoyi-auth/src/main/resources/application-dev.yml
@@ -0,0 +1,6 @@
+spring:
+ application:
+ name: xiaoyi-auth
+ output:
+ ansi:
+ enabled: always
\ No newline at end of file
diff --git a/xiaoyi-auth/src/main/resources/application.yml b/xiaoyi-auth/src/main/resources/application.yml
index fce073c..ec870c1 100644
--- a/xiaoyi-auth/src/main/resources/application.yml
+++ b/xiaoyi-auth/src/main/resources/application.yml
@@ -1,6 +1,4 @@
spring:
- application:
- name: xiaoyi-auth
- output:
- ansi:
- enabled: always
\ No newline at end of file
+ profiles:
+ active:
+ - dev
\ No newline at end of file
diff --git a/xiaoyi-framework/pom.xml b/xiaoyi-framework/pom.xml
index dc271da..1c5236f 100644
--- a/xiaoyi-framework/pom.xml
+++ b/xiaoyi-framework/pom.xml
@@ -17,6 +17,7 @@
xiaoyi-common
+ xiaoyi-spring-boot-starter-biz-operationlog
\ No newline at end of file
diff --git a/xiaoyi-framework/xiaoyi-common/pom.xml b/xiaoyi-framework/xiaoyi-common/pom.xml
index ffff923..f613212 100644
--- a/xiaoyi-framework/xiaoyi-common/pom.xml
+++ b/xiaoyi-framework/xiaoyi-common/pom.xml
@@ -20,6 +20,22 @@
org.projectlombok
lombok
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+
+
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+
\ No newline at end of file
diff --git a/xiaoyi-framework/xiaoyi-common/src/main/java/top/crushtj/.gitkeep b/xiaoyi-framework/xiaoyi-common/src/main/java/top/crushtj/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/xiaoyi-framework/xiaoyi-common/src/main/java/top/crushtj/framework/common/utils/JsonUtils.java b/xiaoyi-framework/xiaoyi-common/src/main/java/top/crushtj/framework/common/utils/JsonUtils.java
new file mode 100644
index 0000000..e32b4b9
--- /dev/null
+++ b/xiaoyi-framework/xiaoyi-common/src/main/java/top/crushtj/framework/common/utils/JsonUtils.java
@@ -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);
+ }
+}
diff --git a/xiaoyi-framework/xiaoyi-spring-boot-starter-biz-operationlog/pom.xml b/xiaoyi-framework/xiaoyi-spring-boot-starter-biz-operationlog/pom.xml
new file mode 100644
index 0000000..5a337a8
--- /dev/null
+++ b/xiaoyi-framework/xiaoyi-spring-boot-starter-biz-operationlog/pom.xml
@@ -0,0 +1,28 @@
+
+
+ 4.0.0
+
+ top.crushtj
+ xiaoyi-framework
+ ${revision}
+
+
+ xiaoyi-spring-boot-starter-biz-operationlog
+ ${project.artifactId}
+ 平台基础设施层:操作日志记录器
+
+
+
+ top.crushtj
+ xiaoyi-common
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+
\ No newline at end of file
diff --git a/xiaoyi-framework/xiaoyi-spring-boot-starter-biz-operationlog/src/main/java/top/crushtj/framework/biz/operationlog/ApiOperationLogAspect.java b/xiaoyi-framework/xiaoyi-spring-boot-starter-biz-operationlog/src/main/java/top/crushtj/framework/biz/operationlog/ApiOperationLogAspect.java
new file mode 100644
index 0000000..0f2c6af
--- /dev/null
+++ b/xiaoyi-framework/xiaoyi-spring-boot-starter-biz-operationlog/src/main/java/top/crushtj/framework/biz/operationlog/ApiOperationLogAspect.java
@@ -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