diff --git a/.vscode/java-formatter.xml b/.vscode/java-formatter.xml new file mode 100644 index 0000000..ba43e02 --- /dev/null +++ b/.vscode/java-formatter.xml @@ -0,0 +1,380 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.vscode/java.code-snippets b/.vscode/java.code-snippets new file mode 100644 index 0000000..1b98bc4 --- /dev/null +++ b/.vscode/java.code-snippets @@ -0,0 +1,74 @@ +{ + // Place your xiaoyishu 工作区 snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and + // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope + // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is + // used to trigger the snippet and the body will be expanded and inserted. Possible variables are: + // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. + // Placeholders with the same ids are connected. + // Example: + // "Print to console": { + // "scope": "javascript,typescript", + // "prefix": "log", + // "body": [ + // "console.log('$1');", + // "$2" + // ], + // "description": "Log output to console" + // } + "类注释": { + "prefix": "ccj", + "body": [ + "/**", + " *", + " * @Title: ${TM_FILENAME_BASE}", + " * @Description: ${1:}", + " * @Author: ${2:}", + " * @Date: ${CURRENT_YEAR}/${CURRENT_MONTH}/${CURRENT_DATE}", + " */" + ], + "description": "生成类注释" + }, + "接口注释": { + "prefix": "icj", + "body": [ + "/**", + " *", + " * @Title: ${TM_FILENAME_BASE}", + " * @Description: ${1:}", + " * @Author: ${2:}", + " * @Date: ${CURRENT_YEAR}/${CURRENT_MONTH}/${CURRENT_DATE}", + " */" + ], + "description": "生成接口注释" + }, + "注解注释": { + "prefix": "acj", + "body": [ + "/**", + " *", + " * @Title: ${TM_FILENAME_BASE}", + " * @Description: ${1:}", + " * @Author: ${2:}", + " * @Date: ${CURRENT_YEAR}/${CURRENT_MONTH}/${CURRENT_DATE}", + " */" + ], + "description": "生成注解注释" + }, + "字符串常量": { + "prefix": "prfs", + "body": ["private final static String ${1:NAME} = \"${1:NAME}\";"], + "description": "生成字符串常量" + }, + "Long常量": { + "prefix": "prfl", + "body": ["private final static Long ${1:NAME} = ${1:NAME}L;"], + "description": "生成Long常量" + }, + "Generate serialVersionUID": { + "prefix": "serial", // 输入 "serial" 触发模板 + "body": [ + "private static final long serialVersionUID = ${:${generateSerialVersionUID}}L;" + ], + "description": "生成 Serializable 类的 serialVersionUID" + } +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6c31703 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "maven.executable.options": "-s D:\\Programs\\Dev\\maven\\conf\\settings-aliyun.xml", + "java.format.settings.url": ".vscode/java-formatter.xml", + "java.compile.nullAnalysis.mode": "automatic" +} \ No newline at end of file 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 index 71fc4e5..f9d1ae3 100644 --- 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 @@ -3,6 +3,10 @@ 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 top.crushtj.xiaoyishu.auth.vo.User; + +import java.time.LocalDateTime; + import org.springframework.web.bind.annotation.GetMapping; /** @@ -18,8 +22,13 @@ public class TestController { @GetMapping("/test") @ApiOperationLog(description = "测试接口") - public Response testController() { - return Response.success("Hello World!"); + public Response testController() { + return Response.success(User.builder() + .id(1L) + .name("ayi") + .age(18) + .createTime(LocalDateTime.now()) + .build()); } } diff --git a/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/vo/User.java b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/vo/User.java new file mode 100644 index 0000000..e12563f --- /dev/null +++ b/xiaoyi-auth/src/main/java/top/crushtj/xiaoyishu/auth/vo/User.java @@ -0,0 +1,26 @@ +package top.crushtj.xiaoyishu.auth.vo; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +import lombok.Builder; +import lombok.Data; + +/** + * + * @Title: User + * @Description: 测试用户类 + * @Author: ayi + * @Date: 2025/11/26 + */ + +@Data +@Builder +public class User implements Serializable { + private Long id; + private String name; + private Integer age; + private LocalDateTime createTime; + +} diff --git a/xiaoyi-framework/xiaoyi-common/src/main/java/top/crushtj/framework/common/constant/DateConstants.java b/xiaoyi-framework/xiaoyi-common/src/main/java/top/crushtj/framework/common/constant/DateConstants.java new file mode 100644 index 0000000..440aba6 --- /dev/null +++ b/xiaoyi-framework/xiaoyi-common/src/main/java/top/crushtj/framework/common/constant/DateConstants.java @@ -0,0 +1,14 @@ +package top.crushtj.framework.common.constant; + +/** + * @Title: DateConstants + * @Description: 日期常量 + * @Author: ayi + * @Date: 2025/11/26 + */ +public interface DateConstants { + /** + * 年-月-日 时:分:秒 + */ + String Y_M_D_H_M_S_FORMAT = "yyyy-MM-dd HH:mm:ss"; +} 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 index e32b4b9..1b31b1f 100644 --- 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 @@ -1,11 +1,17 @@ package top.crushtj.framework.common.utils; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + 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 com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import lombok.SneakyThrows; +import top.crushtj.framework.common.constant.DateConstants; /** * @@ -20,9 +26,16 @@ public class JsonUtils { 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 的序列化问题 - } + // JavaTimeModule 用于指定序列化和反序列化规则 + JavaTimeModule javaTimeModule = new JavaTimeModule(); + + // 支持 LocalDateTime + javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DateConstants.Y_M_D_H_M_S_FORMAT))); + javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DateConstants.Y_M_D_H_M_S_FORMAT))); + + OBJECT_MAPPER.registerModules(javaTimeModule); // 解决 LocalDateTime 的序列化问题 + } /** * 将对象转换为 JSON 字符串 * 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 index 0f2c6af..02cf60d 100644 --- 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 @@ -20,15 +20,14 @@ import top.crushtj.framework.common.utils.JsonUtils; public class ApiOperationLogAspect { /** 以自定义 @ApiOperationLog 注解为切点,凡是添加 @ApiOperationLog 的方法,都会执行环绕中的代码 */ @Pointcut("@annotation(top.crushtj.framework.biz.operationlog.aspect.ApiOperationLog)") - public void apiOperationLog() { - } + public void apiOperationLog() {} /** * 环绕 * - * @param joinPoint - * @return - * @throws Throwable + * @param joinPoint 连接点 + * @return 方法执行结果 + * @throws Throwable 方法执行过程中抛出的异常 */ @Around("apiOperationLog()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { @@ -36,25 +35,20 @@ public class ApiOperationLogAspect { long startTime = System.currentTimeMillis(); // 获取被请求的类和方法 - String className = joinPoint.getTarget() - .getClass() - .getSimpleName(); - String methodName = joinPoint.getSignature() - .getName(); + 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 argsJsonStr = Arrays.stream(args).map(toJsonStr()).collect(Collectors.joining(", ")); // 功能描述信息 String description = getApiOperationLogDescription(joinPoint); // 打印请求相关参数 - log.info("====== 请求开始: [{}], 入参: {}, 请求类: {}, 请求方法: {} =================================== ", description, - argsJsonStr, className, methodName); + log.info("\n\n请求开始: [{}], 请求参数: {}, 请求类: {}, 请求方法: {}\n", description, argsJsonStr, className, + methodName); // 执行切点方法 Object result = joinPoint.proceed(); @@ -63,7 +57,7 @@ public class ApiOperationLogAspect { long executionTime = System.currentTimeMillis() - startTime; // 打印出参等相关信息 - log.info("====== 请求结束: [{}], 耗时: {}ms, 出参: {} =================================== ", description, executionTime, + log.info("\n\n请求结束: [{}], 耗时: {}ms, 响应参数: {}\n", description, executionTime, JsonUtils.toJsonString(result)); return result; @@ -72,8 +66,8 @@ public class ApiOperationLogAspect { /** * 获取注解的描述信息 * - * @param joinPoint - * @return + * @param joinPoint 连接点 + * @return 注解的描述信息 */ private String getApiOperationLogDescription(ProceedingJoinPoint joinPoint) { // 1. 从 ProceedingJoinPoint 获取 MethodSignature @@ -92,7 +86,7 @@ public class ApiOperationLogAspect { /** * 转 JSON 字符串 * - * @return + * @return 入参的 JSON 字符串 */ private Function toJsonStr() { return JsonUtils::toJsonString;