Spring Reactive全局日期配置失效 JSON序列化仍返回时间戳
Spring Reactive 全局Date序列化不生效问题解决方案
问题根因
Spring 响应式栈(WebFlux)和传统Spring MVC的序列化组件加载逻辑存在差异:
- 传统Spring MVC使用
MappingJackson2HttpMessageConverter做JSON序列化,会默认读取spring.jackson.*前缀的配置绑定到全局ObjectMapper - WebFlux使用
Jackson2JsonEncoder做序列化,当通过RouterFunction定义接口、调用bodyValue()输出响应时,如果没有显式给编解码器指定自定义的ObjectMapper,框架会初始化独立的默认ObjectMapper实例,该实例默认开启WRITE_DATES_AS_TIMESTAMPS特性,不会读取application.properties中的Jackson配置,也不会使用JacksonAutoConfiguration预配置的ObjectMapper Bean,因此全局配置不生效。
已尝试方案无效原因
- 引入
com.fasterxml.jackson.datatype:jackson-datatype-joda依赖无作用:该依赖仅用于序列化Joda Time的日期类型,不处理JDK原生java.util.Date的序列化逻辑 spring.jackson.serialization.write-dates-as-timestamps=false配置未被WebFlux序列化组件加载,仅对Spring上下文持有的ObjectMapper生效,没有传递到实际执行序列化的Jackson2JsonEncoder中- 逐字段添加
@JsonFormat生效是因为注解优先级高于序列化器默认配置,但无法解决全局统一配置的需求;全量替换Date为LocalDateTime需要大量重构,成本较高。
正确全局配置方案
无需修改现有实体类、无需逐字段加注解、无需替换Date类型,两步即可实现全局格式化:
- 移除不必要的
jackson-datatype-joda依赖(无实际作用) - 添加WebFlux配置类,自定义全局ObjectMapper并绑定到WebFlux编解码器:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.DateSerializer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.web.reactive.config.WebFluxConfigurer; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; @Configuration public class GlobalWebFluxConfig implements WebFluxConfigurer { @Bean public ObjectMapper customObjectMapper() { ObjectMapper objectMapper = new ObjectMapper(); // 关闭日期序列化为时间戳的配置 objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // 配置Date类型全局序列化格式 SimpleModule dateModule = new SimpleModule(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 指定东八区时区,避免时间偏差 dateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); dateModule.addSerializer(Date.class, new DateSerializer(false, dateFormat)); objectMapper.registerModule(dateModule); return objectMapper; } @Override public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) { ObjectMapper objectMapper = customObjectMapper(); // 将自定义ObjectMapper注入WebFlux的JSON编解码器,保证序列化时使用自定义配置 configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper)); configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper)); } }
配置完成后重启应用,所有接口返回的Date类型、Optional<Date>类型字段都会统一序列化为yyyy-MM-dd HH:mm:ss格式,不会再返回时间戳。
提示:如果项目中已有其他ObjectMapper自定义配置,直接注入现有ObjectMapper实例补充日期序列化规则即可,不要重复创建ObjectMapper Bean避免覆盖原有配置。
内容的提问来源于stack exchange,提问作者Tom Walker
相关产品推荐
相关产品推荐

