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 配置类路径有变化,注意对应版本的依赖。

写在最后

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

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

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

相关文章
|
5月前
|
前端开发 Java Nacos
Nacos 注解全解析:7 个核心注解 + 5 个生产踩坑清单(2026 实测)
Nacos 注解用错,是 90% 微服务 Bug 的根源。本文把注册发现、配置热更新的 7 个核心注解、动态刷新原理和 5 个生产踩坑一次讲透,附可运行代码。
772 2
Nacos 注解全解析:7 个核心注解 + 5 个生产踩坑清单(2026 实测)
|
5天前
|
人工智能 IDE 开发工具
建议 Qoder 原生支持 Agent 轨迹复盘、过程评测与改进闭环
Qoder、AI Coding、Agent、轨迹复盘、过程评测、研发效能
121 3
|
10天前
|
自然语言处理 API 开发工具
阿里云百炼 API Key 开发指南:申请密钥、配置权限、多语言接口快速调用
配置凭证优先操作系统环境变量,提供了Linux、macOS、Windows多平台命令示例,同时提供curl、Python两套可直接运行的调用代码,也支持各类第三方AI工具接入。需要注意地域隔离、普通密钥和Token Plan专属密钥的差异,遇到401鉴权、环境变量不生效等问题,对照排错清单定位原因。密钥安全是开发当中不可忽视的环节,一旦泄露会带来额度被盗刷风险,线上业务尽量使用RAM子账号、IP白名单、临时密钥,定期清理废弃密钥,做好用量监控,保障大模型业务安全稳定运行。
279 3
|
3天前
|
人工智能 弹性计算 自然语言处理
DeepSeek个人站点一键部署实测
阿里云推出DeepSeek个人AI站点一键部署方案:无需代码、5分钟上线,支持DeepSeek满血版等多模型切换。免环境配置、免CUDA折腾,新用户享云服务器优惠,轻松拥有专属AI对话站点。(239字)
|
3天前
|
人工智能 Serverless API
我用阿里云 AI 动画方案跑通了剧本→视频流水线:ComfyUI + 百炼模型实测
本文实测阿里云「AI剧本生成与动画创作」方案,详解其基于函数计算、ComfyUI、百炼多模态模型(Qwen-VL/Max、CosyVoice等)与OSS构建的端到端流水线,覆盖文案→配音→分镜→合成全流程,助创作者低成本、高效率产出卡通/解说类短视频,适合个人及小团队快速验证内容创意。(239字)
|
2月前
|
弹性计算 人工智能 API
阿里云轻量 / ECS/GPU 云服务器 + AI 云产品详解,规格价格与业务实战对比
在数字化项目落地、AI模型开发、网站业务部署的过程中,算力资源的选择直接决定项目稳定性、开发效率以及整体投入成本。很多开发者、初创团队在初次上云时,很容易混淆 阿里云轻量应用服务器 、 阿里云ECS云服务器 、 阿里云 EGS GPU云服务器 以及各类AI云产品的定位,盲目选择高规格实例造成预算浪费,或者选用配置不足的实例导致业务卡顿、模型推理超时。阿里云构建了覆盖从入门轻量业务、企业通用业务,到大模型训练推理的完整全栈算力体系,不同产品在底层架构、资源权限、计费方式、适用场景上有着明显的区别。
140 1
|
4月前
|
人工智能 JavaScript API
从开题到答辩:用百炼 CLI 一条命令跑通论文写作全链路
论文写作正陷于“工具碎片化”困境:查重、AIGC检测、降重、润色、参考文献、LaTeX校对等需切换十余平台。百炼CLI `bl text chat` 以统一长文本对话能力,覆盖开题至答辩9大环节,一次登录、一套计费、可编程批处理,成本低、合规强,助力研究生高效、规范完成学术写作。(239字)
从开题到答辩:用百炼 CLI 一条命令跑通论文写作全链路
|
4月前
|
存储 监控 数据处理
基于 YOLO11 的工业厂区泄漏隐患检测:从数据标注到云上训练工程实践
本文基于YOLO11构建工业厂区泄漏隐患检测系统,涵盖数据标注(1969张960×960图像,单类leakage)、云上存储管理、训练调优(imgsz=960, batch=16)及模型评估全流程,助力实现7×24小时自动化巡检与早期告警。
基于 YOLO11 的工业厂区泄漏隐患检测:从数据标注到云上训练工程实践
|
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落地门槛。