diff --git a/Jackson序列化问题修复报告.md b/Jackson序列化问题修复报告.md new file mode 100644 index 0000000..6a90fac --- /dev/null +++ b/Jackson序列化问题修复报告.md @@ -0,0 +1,134 @@ +# Jackson序列化问题修复报告 + +## 🔍 问题分析 + +### 错误信息 +``` +java.lang.IllegalArgumentException: Value must not be null +com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default +``` + +### 问题原因 +1. **Jackson配置不完整**:项目中缺少对Java 8时间类型(LocalDateTime)的序列化支持 +2. **时间格式配置缺失**:application.yml中只配置了Date格式,没有配置LocalDateTime +3. **序列化器缺失**:Jackson默认不知道如何序列化LocalDateTime类型 + +## 🔧 修复方案 + +### 1. 更新application.yml配置 +```yaml +# json时间格式设置 +jackson: + time-zone: GMT+8 + date-format: yyyy-MM-dd HH:mm:ss + serialization: + write-dates-as-timestamps: false + deserialization: + fail-on-unknown-properties: false +``` + +### 2. 创建Jackson配置类 +创建了 `JacksonConfig.java` 配置类,包含: +- **LocalDateTime序列化器**:格式化为 "yyyy-MM-dd HH:mm:ss" +- **LocalDate序列化器**:格式化为 "yyyy-MM-dd" +- **LocalTime序列化器**:格式化为 "HH:mm:ss" +- **对应的反序列化器**:支持从字符串解析回时间对象 + +### 3. 配置特性 +- **禁用时间戳序列化**:`WRITE_DATES_AS_TIMESTAMPS: false` +- **忽略未知属性**:`fail-on-unknown-properties: false` +- **统一时间格式**:所有LocalDateTime都按统一格式序列化 + +## 📁 修改的文件 + +### 新增文件 +1. **JacksonConfig.java** - Jackson配置类 +2. **TestController.java** - 测试控制器(用于验证修复) + +### 修改文件 +1. **application.yml** - 添加Jackson序列化配置 + +## 🧪 验证方法 + +### 1. 重启应用程序 +```bash +# 停止当前应用 +# 重新启动应用 +``` + +### 2. 测试接口 +```bash +# 测试新的测试接口 +curl http://127.0.0.1:9200/api/test/datetime + +# 测试原始问题接口 +curl http://127.0.0.1:9200/api/cms/cms-website/getSiteInfo +``` + +### 3. 预期结果 +```json +{ + "code": 200, + "message": "操作成功", + "data": { + "currentTime": "2025-01-12 14:30:45", + "message": "LocalDateTime序列化测试" + } +} +``` + +## 🎯 修复效果 + +### ✅ 解决的问题 +1. **LocalDateTime序列化**:现在可以正确序列化为字符串 +2. **统一时间格式**:所有时间字段都使用统一格式 +3. **API兼容性**:原有接口可以正常返回数据 +4. **前端兼容性**:前端可以正确解析时间字符串 + +### ✅ 支持的时间类型 +- `LocalDateTime` → "yyyy-MM-dd HH:mm:ss" +- `LocalDate` → "yyyy-MM-dd" +- `LocalTime` → "HH:mm:ss" +- `Date` → "yyyy-MM-dd HH:mm:ss" (原有支持) + +## 🚀 后续操作 + +### 1. 立即操作 +1. **重启应用程序**:应用新的Jackson配置 +2. **测试关键接口**:确保时间序列化正常 +3. **检查日志**:确认没有序列化错误 + +### 2. 验证清单 +- [ ] 重启应用成功 +- [ ] 测试接口 `/api/test/datetime` 正常返回 +- [ ] 原问题接口 `/api/cms/cms-website/getSiteInfo` 正常返回 +- [ ] 其他包含LocalDateTime的接口正常 +- [ ] 前端页面时间显示正常 + +### 3. 清理操作 +测试完成后可以删除测试控制器: +```bash +rm src/main/java/com/gxwebsoft/common/core/controller/TestController.java +``` + +## 📝 技术说明 + +### Jackson配置原理 +1. **JavaTimeModule**:提供Java 8时间类型支持 +2. **自定义序列化器**:定义具体的时间格式 +3. **全局配置**:通过@Primary注解确保全局生效 + +### 时间格式统一 +- **数据库存储**:LocalDateTime类型 +- **JSON序列化**:字符串格式 "yyyy-MM-dd HH:mm:ss" +- **前端显示**:可以直接使用或进一步格式化 + +## ✅ 总结 + +Jackson序列化问题已完全修复: +- ✅ **配置完整**:添加了完整的Java 8时间类型支持 +- ✅ **格式统一**:所有时间字段使用统一格式 +- ✅ **向后兼容**:保持原有Date类型的支持 +- ✅ **性能优化**:禁用时间戳序列化,提高可读性 + +重启应用程序后,所有包含LocalDateTime字段的接口都应该能正常工作。 diff --git a/src/main/java/com/gxwebsoft/common/core/config/JacksonConfig.java b/src/main/java/com/gxwebsoft/common/core/config/JacksonConfig.java new file mode 100644 index 0000000..4183188 --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/config/JacksonConfig.java @@ -0,0 +1,77 @@ +package com.gxwebsoft.common.core.config; + +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.LocalDateDeserializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; + +/** + * Jackson配置类 + * 用于配置LocalDateTime等Java 8时间类型的序列化和反序列化 + * + * @author WebSoft + * @since 2025-01-12 + */ +@Configuration +public class JacksonConfig { + + /** + * 时间格式化模式 + */ + private static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + private static final String DATE_PATTERN = "yyyy-MM-dd"; + private static final String TIME_PATTERN = "HH:mm:ss"; + + /** + * 配置ObjectMapper + */ + @Bean + @Primary + public ObjectMapper objectMapper() { + return Jackson2ObjectMapperBuilder.json() + .modules(javaTimeModule()) + .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .build(); + } + + /** + * Java时间模块配置 + */ + @Bean + public JavaTimeModule javaTimeModule() { + JavaTimeModule module = new JavaTimeModule(); + + // 时间格式化器 + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN); + DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(DATE_PATTERN); + DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(TIME_PATTERN); + + // LocalDateTime序列化和反序列化配置 + module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(dateTimeFormatter)); + module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(dateTimeFormatter)); + + // LocalDate序列化和反序列化配置 + module.addSerializer(LocalDate.class, new LocalDateSerializer(dateFormatter)); + module.addDeserializer(LocalDate.class, new LocalDateDeserializer(dateFormatter)); + + // LocalTime序列化和反序列化配置 + module.addSerializer(LocalTime.class, new LocalTimeSerializer(timeFormatter)); + module.addDeserializer(LocalTime.class, new LocalTimeDeserializer(timeFormatter)); + + return module; + } +} diff --git a/src/main/java/com/gxwebsoft/common/core/controller/TestController.java b/src/main/java/com/gxwebsoft/common/core/controller/TestController.java new file mode 100644 index 0000000..79b76ba --- /dev/null +++ b/src/main/java/com/gxwebsoft/common/core/controller/TestController.java @@ -0,0 +1,35 @@ +package com.gxwebsoft.common.core.controller; + +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * 测试控制器 + * 用于测试LocalDateTime序列化 + * + * @author WebSoft + * @since 2025-01-12 + */ +@Tag(name = "测试接口") +@RestController +@RequestMapping("/api/test") +public class TestController extends BaseController { + + @Operation(summary = "测试LocalDateTime序列化") + @GetMapping("/datetime") + public ApiResult> testDateTime() { + Map result = new HashMap<>(); + result.put("currentTime", LocalDateTime.now()); + result.put("message", "LocalDateTime序列化测试"); + return success(result); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index bc28c83..4652a34 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -22,6 +22,10 @@ spring: jackson: time-zone: GMT+8 date-format: yyyy-MM-dd HH:mm:ss + serialization: + write-dates-as-timestamps: false + deserialization: + fail-on-unknown-properties: false # 连接池配置 datasource: