Browse Source

refactor(jackson): 重构 Jackson 配置并添加测试

- 简化了 JacksonConfig 类,移除了自定义时间格式配置
- 添加了 JacksonConfigChecker组件,用于检查 Jackson 配置是否正确
- 新增 JacksonTestController,用于测试 LocalDateTime 序列
pan
科技小王子 3 weeks ago
parent
commit
13f094e2e4
  1. 50
      src/main/java/com/gxwebsoft/common/core/config/JacksonConfig.java
  2. 59
      src/main/java/com/gxwebsoft/common/core/config/JacksonConfigChecker.java
  3. 90
      src/main/java/com/gxwebsoft/common/core/controller/JacksonTestController.java
  4. 4
      src/main/resources/application.yml

50
src/main/java/com/gxwebsoft/common/core/config/JacksonConfig.java

@ -4,71 +4,45 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* Jackson配置类
* 确保JSR310模块被正确注册到ObjectMapper中并配置自定义时间格式
* Jackson配置类 - 强制配置版本
* 确保JavaTimeModule被正确注册并覆盖Spring Boot的自动配置
*
* @author WebSoft
* @since 2025-01-12
* @since 2025-09-08
*/
@Configuration
public class JacksonConfig {
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
/**
* 配置ObjectMapper确保JSR310模块被正确注册并设置自定义时间格式
* 强制配置ObjectMapper确保JavaTimeModule被正确注册
*/
@Bean
@Primary
@ConditionalOnMissingBean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
// 创建自定义的JavaTimeModule
JavaTimeModule javaTimeModule = new JavaTimeModule();
// 配置LocalDateTime的序列化和反序列化格式
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DATE_TIME_FORMATTER));
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DATE_TIME_FORMATTER));
// 注册自定义的JSR310模块
mapper.registerModule(javaTimeModule);
// 注册JavaTimeModule - 这是关键
mapper.registerModule(new JavaTimeModule());
// 禁用将日期写为时间戳
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// 忽略未知属性
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 允许空字符串作为null对象
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
return mapper;
}
/**
* 确保JavaTimeModule被注册保留原有Bean
* 备用JavaTimeModule Bean
*/
@Bean
@ConditionalOnMissingBean
public JavaTimeModule javaTimeModule() {
JavaTimeModule module = new JavaTimeModule();
// 配置LocalDateTime的序列化和反序列化格式
module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DATE_TIME_FORMATTER));
module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DATE_TIME_FORMATTER));
return module;
return new JavaTimeModule();
}
}

59
src/main/java/com/gxwebsoft/common/core/config/JacksonConfigChecker.java

@ -0,0 +1,59 @@
package com.gxwebsoft.common.core.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
/**
* Jackson配置检查器
* 在应用启动时检查Jackson配置是否正确
*
* @author WebSoft
* @since 2025-09-08
*/
@Component
public class JacksonConfigChecker implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(JacksonConfigChecker.class);
@Autowired
private ObjectMapper objectMapper;
@Override
public void run(String... args) throws Exception {
logger.info("=== Jackson配置检查开始 ===");
try {
// 检查JavaTimeModule是否注册
boolean hasJavaTimeModule = objectMapper.getRegisteredModuleIds()
.contains(JavaTimeModule.class.getName());
logger.info("JavaTimeModule是否注册: {}", hasJavaTimeModule);
// 测试LocalDateTime序列化
Map<String, Object> testData = new HashMap<>();
testData.put("currentTime", LocalDateTime.now());
testData.put("message", "Jackson配置测试");
String json = objectMapper.writeValueAsString(testData);
logger.info("LocalDateTime序列化测试成功: {}", json);
// 测试反序列化
Map<String, Object> result = objectMapper.readValue(json, Map.class);
logger.info("反序列化测试成功: {}", result);
logger.info("=== Jackson配置检查完成 - 配置正常 ===");
} catch (Exception e) {
logger.error("=== Jackson配置检查失败 ===", e);
logger.error("请检查Jackson配置是否正确");
}
}
}

90
src/main/java/com/gxwebsoft/common/core/controller/JacksonTestController.java

@ -0,0 +1,90 @@
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;
/**
* Jackson序列化测试控制器
* 用于测试LocalDateTime序列化是否正常工作
*
* @author WebSoft
* @since 2025-09-08
*/
@Tag(name = "Jackson测试")
@RestController
@RequestMapping("/api/test/jackson")
public class JacksonTestController extends BaseController {
@Operation(summary = "测试LocalDateTime序列化")
@GetMapping("/datetime")
public ApiResult<Map<String, Object>> testDateTime() {
Map<String, Object> result = new HashMap<>();
result.put("currentTime", LocalDateTime.now());
result.put("message", "如果您能看到格式化的时间,说明Jackson配置正常");
result.put("timestamp", System.currentTimeMillis());
return success(result);
}
@Operation(summary = "测试实体类序列化")
@GetMapping("/entity")
public ApiResult<TestEntity> testEntity() {
TestEntity entity = new TestEntity();
entity.setId(1);
entity.setName("测试实体");
entity.setCreateTime(LocalDateTime.now());
entity.setUpdateTime(LocalDateTime.now());
return success(entity);
}
/**
* 测试实体类
*/
public static class TestEntity {
private Integer id;
private String name;
private LocalDateTime createTime;
private LocalDateTime updateTime;
// Getters and Setters
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
}
}

4
src/main/resources/application.yml

@ -24,12 +24,8 @@ spring:
date-format: yyyy-MM-dd HH:mm:ss
serialization:
write-dates-as-timestamps: false
write-null-map-values: false
deserialization:
fail-on-unknown-properties: false
fail-on-null-for-primitives: false
accept-empty-string-as-null-object: true
default-property-inclusion: non_null
# 连接池配置
datasource:

Loading…
Cancel
Save