refactor(jackson): 重构 Jackson 配置并添加测试
- 简化了 JacksonConfig 类,移除了自定义时间格式配置 - 添加了 JacksonConfigChecker组件,用于检查 Jackson 配置是否正确 - 新增 JacksonTestController,用于测试 LocalDateTime 序列
This commit is contained in:
@@ -4,71 +4,45 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
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.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Primary;
|
import org.springframework.context.annotation.Primary;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Jackson配置类
|
* Jackson配置类 - 强制配置版本
|
||||||
* 确保JSR310模块被正确注册到ObjectMapper中,并配置自定义时间格式
|
* 确保JavaTimeModule被正确注册并覆盖Spring Boot的自动配置
|
||||||
*
|
*
|
||||||
* @author WebSoft
|
* @author WebSoft
|
||||||
* @since 2025-01-12
|
* @since 2025-09-08
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
public class JacksonConfig {
|
public class JacksonConfig {
|
||||||
|
|
||||||
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 配置ObjectMapper,确保JSR310模块被正确注册并设置自定义时间格式
|
* 强制配置ObjectMapper,确保JavaTimeModule被正确注册
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@Primary
|
@Primary
|
||||||
@ConditionalOnMissingBean
|
|
||||||
public ObjectMapper objectMapper() {
|
public ObjectMapper objectMapper() {
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
// 创建自定义的JavaTimeModule
|
// 注册JavaTimeModule - 这是关键
|
||||||
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
mapper.registerModule(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);
|
|
||||||
|
|
||||||
// 禁用将日期写为时间戳
|
// 禁用将日期写为时间戳
|
||||||
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||||
|
|
||||||
// 忽略未知属性
|
// 忽略未知属性
|
||||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
|
||||||
// 允许空字符串作为null对象
|
|
||||||
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
|
|
||||||
|
|
||||||
return mapper;
|
return mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 确保JavaTimeModule被注册(保留原有Bean)
|
* 备用JavaTimeModule Bean
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
|
||||||
public JavaTimeModule javaTimeModule() {
|
public JavaTimeModule javaTimeModule() {
|
||||||
JavaTimeModule module = new JavaTimeModule();
|
return new JavaTimeModule();
|
||||||
|
|
||||||
// 配置LocalDateTime的序列化和反序列化格式
|
|
||||||
module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DATE_TIME_FORMATTER));
|
|
||||||
module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DATE_TIME_FORMATTER));
|
|
||||||
|
|
||||||
return module;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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配置是否正确");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,12 +24,8 @@ spring:
|
|||||||
date-format: yyyy-MM-dd HH:mm:ss
|
date-format: yyyy-MM-dd HH:mm:ss
|
||||||
serialization:
|
serialization:
|
||||||
write-dates-as-timestamps: false
|
write-dates-as-timestamps: false
|
||||||
write-null-map-values: false
|
|
||||||
deserialization:
|
deserialization:
|
||||||
fail-on-unknown-properties: false
|
fail-on-unknown-properties: false
|
||||||
fail-on-null-for-primitives: false
|
|
||||||
accept-empty-string-as-null-object: true
|
|
||||||
default-property-inclusion: non_null
|
|
||||||
|
|
||||||
# 连接池配置
|
# 连接池配置
|
||||||
datasource:
|
datasource:
|
||||||
|
|||||||
Reference in New Issue
Block a user