Spring Boot 全局时间格式化:Date 和 LocalDateTime 统一配置实战

简介: Java后端时间格式化痛点:`Date`与`LocalDateTime`混用导致全局配置失效。本文详解3种实战方案——`@JsonFormat`(局部)、`@JsonComponent`(推荐,支持全局+注解覆盖)、`@Configuration`手动配置`ObjectMapper`,代码可直接复用,解决时区、序列化/反序列化、版本兼容等常见坑。(239字)

做 Java 后端开发,时间格式化是高频痛点。接口返回的时间字段,前端要 yyyy-MM-dd HH:mm:ss,你总不能每个 DTO 字段都加 @JsonFormat 注解。更麻烦的是项目里 java.util.Date 和 java.time.LocalDateTime 混用,配了一种另一种不生效。

这篇把 3 种全局配置方式整理一遍,代码直接复制就能用。

问题场景

先看一个典型的 DTO:

@Data
public class OrderDTO {
   
    private LocalDateTime createTime;
    private Date updateTime;
}

接口返回结果里,时间字段默认是时间戳或 ISO 格式,前端展示不友好。如果你在 application.properties 里配了:

spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8

你会发现只对 Date 生效,LocalDateTime 还是原样。这就是问题所在。

方式一:@JsonFormat 注解(局部方案)

最直接的方式,每个字段加注解:

@Data
public class OrderDTO {
   
    @JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

    @JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private Date updateTime;
}

优点:简单粗暴,每个字段可以自定义格式。
缺点:不是全局方案,字段多了注解满天飞,维护成本高。

适合:个别字段需要特殊格式的场景。

方式二:@JsonComponent(推荐)

这是我个人最推荐的方式。自定义一个全局配置类,同时处理 Date 和 LocalDateTime:

@JsonComponent
public class DateFormatConfig {
   

    @Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}")
    private String pattern;

    /**
     * Date 类型全局时间格式化
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilder() {
   
        return builder -> {
   
            TimeZone tz = TimeZone.getTimeZone("GMT+8");
            SimpleDateFormat df = new SimpleDateFormat(pattern);
            df.setTimeZone(tz);
            builder.failOnEmptyBeans(false)
                   .failOnUnknownProperties(false)
                   .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                   .dateFormat(df);
        };
    }

    /**
     * LocalDateTime 类型全局时间格式化
     */
    @Bean
    public LocalDateTimeSerializer localDateTimeSerializer() {
   
        return new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern));
    }

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
   
        return builder -> builder.serializerByType(LocalDateTime.class, localDateTimeSerializer());
    }
}

关键点:

  • Date 类型通过 Jackson2ObjectMapperBuilderCustomizer 配置 SimpleDateFormat
  • LocalDateTime 通过自定义 LocalDateTimeSerializer 处理
  • 时区统一设为 GMT+8,避免服务器时区不一致导致时间差

和 @JsonFormat 的配合:如果你有个别字段想用不同格式,直接在那个字段上加 @JsonFormat,注解优先级高于全局配置。这样大部分字段统一格式,少数特殊字段单独覆盖,灵活性最高。

方式三:@Configuration 手动配置 ObjectMapper

这种方式和方式二效果一样,但更底层——手动创建 ObjectMapper 并注册模块:

@Configuration
public class DateFormatConfig2 {
   

    @Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}")
    private String pattern;

    public static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Bean
    @Primary
    public ObjectMapper serializingObjectMapper() {
   
        ObjectMapper objectMapper = new ObjectMapper();
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
        objectMapper.registerModule(javaTimeModule);
        return objectMapper;
    }

    // Date 序列化
    @Component
    public class DateSerializer extends JsonSerializer<Date> {
   
        @Override
        public void serialize(Date date, JsonGenerator gen, SerializerProvider provider) throws IOException {
   
            gen.writeString(dateFormat.format(date));
        }
    }

    // Date 反序列化
    @Component
    public class DateDeserializer extends JsonDeserializer<Date> {
   
        @Override
        public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
   
            try {
   
                return dateFormat.parse(p.getValueAsString());
            } catch (ParseException e) {
   
                throw new RuntimeException("日期解析失败", e);
            }
        }
    }

    // LocalDateTime 序列化
    public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
   
        @Override
        public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
   
            gen.writeString(value.format(DateTimeFormatter.ofPattern(pattern)));
        }
    }

    // LocalDateTime 反序列化
    public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
   
        @Override
        public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
   
            return LocalDateTime.parse(p.getValueAsString(), DateTimeFormatter.ofPattern(pattern));
        }
    }
}

注意:这种方式手动注册了 ObjectMapper 并标记 @Primary,会覆盖 Spring Boot 的自动配置。用了这种方式后,字段上的 @JsonFormat 注解将不再生效——全局配置说了算。

三种方式对比

方式 适用类型 灵活性 推荐度
@JsonFormat 单个字段 最高,每字段自定义 局部特殊场景
@JsonComponent Date + LocalDateTime 高,全局+注解覆盖 最推荐
@Configuration Date + LocalDateTime 中,全局统一 需要完全掌控时用

几个容易踩的坑

  1. 时区问题:服务器部署在云上,默认时区可能是 UTC,不设 GMT+8 会差 8 小时。
  2. 反序列化也要配:只配了序列化(返回给前端),没配反序列化(接收前端传的时间),传参时还是会报错。
  3. LocalDate 和 LocalTime:如果项目里用到了 LocalDate、LocalTime,也要单独配对应的 serializer。
  4. Spring Boot 版本差异:Spring Boot 2.x 和 3.x 的 Jackson 配置类路径有变化,注意对应版本的依赖。

写在最后

时间格式化这种小细节,看似不起眼,但每个项目都要配一遍。把这份配置类存下来,新项目直接复制,省得每次重新查。

参考原文可以看这里——查看原文了解更多细节。

项目里时间格式化你是怎么配的?评论区交流。

相关文章
|
3天前
|
人工智能 弹性计算 自然语言处理
DeepSeek个人站点一键部署实测
阿里云推出DeepSeek个人AI站点一键部署方案:无需代码、5分钟上线,支持DeepSeek满血版等多模型切换。免环境配置、免CUDA折腾,新用户享云服务器优惠,轻松拥有专属AI对话站点。(239字)
|
5天前
|
人工智能 IDE 开发工具
建议 Qoder 原生支持 Agent 轨迹复盘、过程评测与改进闭环
Qoder、AI Coding、Agent、轨迹复盘、过程评测、研发效能
120 3
|
10天前
|
自然语言处理 API 开发工具
阿里云百炼 API Key 开发指南:申请密钥、配置权限、多语言接口快速调用
配置凭证优先操作系统环境变量,提供了Linux、macOS、Windows多平台命令示例,同时提供curl、Python两套可直接运行的调用代码,也支持各类第三方AI工具接入。需要注意地域隔离、普通密钥和Token Plan专属密钥的差异,遇到401鉴权、环境变量不生效等问题,对照排错清单定位原因。密钥安全是开发当中不可忽视的环节,一旦泄露会带来额度被盗刷风险,线上业务尽量使用RAM子账号、IP白名单、临时密钥,定期清理废弃密钥,做好用量监控,保障大模型业务安全稳定运行。
267 3
|
5月前
|
弹性计算 安全 应用服务中间件
云服务器部署实战:ECS上从零搭建生产级Web服务全记录
本文手把手教你将本地Web项目部署到阿里云ECS服务器:从安全组配置、SSH初始化、Nginx反向代理,到应用进程管理(systemd)、安全加固(fail2ban/防火墙)及日志监控,全程覆盖Linux云服务器生产级部署要点,助新手快速实现“代码→公网服务”闭环。
|
5月前
|
存储 人工智能 Serverless
Serverless AI Agent 实战:用阿里云 AgentRun + Google ADK 搭建多智能体协同工作流
本文详解如何在阿里云AgentRun上快速搭建基于Google A2A协议的多Agent竞品分析系统:搜索、分析、报告三个专业Agent通过Serverless架构协同工作,内置百炼大模型与NAS共享存储,开箱即用、按量计费,显著降低多Agent落地门槛。
|
5月前
|
人工智能 运维 物联网
零门槛玩转 AI 生图:用阿里云函数计算一键部署 ComfyUI,5 分钟生成你的专属毛绒萌宠
阿里云函数计算推出一键部署ComfyUI方案,内置Flux模型与毛绒萌宠LoRA,支持超写实毛绒玩具风格AI生图。Serverless GPU按量付费、免运维、不开机不花钱,单张图低至0.02元,5分钟极速部署,零门槛体验前沿AIGC。
|
5月前
|
人工智能 Serverless API
手把手教你用阿里云函数计算部署 AI 绘图服务:Flux + ComfyUI 完整实操指南
本文介绍如何用阿里云函数计算(FC)零运维部署AI生图服务,以Flux模型为例,涵盖NAS挂载、GPU配置、API调用及成本优化。免服务器管理,按需付费,冷启动后5秒出图,单张成本仅0.02–0.2元。新用户享免费额度,15分钟快速上手。
|
5月前
|
人工智能 自然语言处理 API
用 Token Plan 低成本接入 Qwen3.7,我是怎么把 AI 成本压到 4.5 折的
阿里云百炼Token Plan以统一Credits支持Qwen3.7-Max/Plus等15款主流模型灵活切换,兼顾高性能与低成本;内置RAG、Prompt调试与应用发布能力,小团队可零基建快速落地知识库问答系统。
|
6月前
|
人工智能 自然语言处理 NoSQL
大模型应用成本管控:基于 Token Plan 的多模型路由网关设计实践
本文介绍一种LLM应用成本管控方案:通过网关层实现“模型路由+订阅配额管理”,根据任务复杂度(如关键词、长度)动态调度至轻量/旗舰模型,并用Redis实现月度Token额度控制与自动降级。实践后成本降低约60%,保障预算确定性与服务稳定性。(239字)
|
6月前
|
存储 人工智能 安全
企业内部 AI 助理落地:从架构设计到私有化的完整实践
为满足数据合规要求,公司基于OpenClaw框架私有化部署AI助理平台,支持知识库问答、工单辅助及Web/钉钉/企微多端接入;采用Qwen-7B本地模型+百炼API混合推理,结合BGE向量库与意图路由策略,在保障安全前提下实现降本增效。(239字)

热门文章

最新文章