深入理解 Spring Boot 中日期时间格式化:@DateTimeFormat 与 @JsonFormat 完整实践

简介: 在 Spring Boot 开发中,处理前后端日期交互是一个常见问题。本文通过 **@DateTimeFormat** 和 **@JsonFormat** 两个注解,详细讲解了如何解析前端传来的日期字符串以及以指定格式返回日期数据。文章从实际案例出发,结合代码演示两者的使用场景与注意事项,解决解析失败、时区偏差等问题,并提供全局配置与局部注解的实践经验。帮助开发者高效应对日期时间格式化需求,提升开发效率。

在开发 Spring Boot 应用时,我们经常会遇到一个问题:如何在与前端交互时,既能正确解析前端传来的日期字符串,又能以指定格式把日期数据返回给前端。其实,要解决这个问题并不难,关键在于两个非常有用的注解—— @DateTimeFormat@JsonFormat。今天就让我们以博客的形式,深入聊聊这两个注解的来龙去脉,并通过详细的代码案例,从浅入深讲解它们的用法和注意细节。


ChatGPT Image 2025年4月8日 03\_13\_10.png

为什么需要格式化日期时间?

在前后端开发中,日期和时间一直都是一个容易出错的点。前端可能会以不同的格式(比如 2025-04-08 14:30:152025/04/08 或者 ISO 8601 标准的 2025-04-08T14:30:15)发送数据,而后端在反序列化时必须清楚如何解析才能转换成 Java 的日期类型(如 LocalDateTimeLocalDateDate)。同样,当我们的后端需要返回数据时,为了让前端能够方便地展示也需要确定特定的日期格式。Spring Boot 刚好为我们提供了两个注解来分别应对这两个环节:

  • @DateTimeFormat 用于【数据绑定】阶段,即接收前端传来的字符串,并将其转换为 Java 时间对象。
  • @JsonFormat 用于【序列化】阶段,即当对象返回给前端时,把 Java 时间对象转换为指定格式的字符串。

一、@DateTimeFormat:精准解析前端传入的日期数据

@DateTimeFormat 可以应用在 Controller 方法参数、表单对象字段或者实体类的属性上。当前端传来的日期字符串与我们定义的 pattern 匹配时,Spring 会自动将其转换成对应的日期类型。

示例代码

假如我们有一个用户注册的请求,前端传来用户的生日信息。我们可以构建如下的 DTO 类:

import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;

/**
 * 用户数据传输对象,用于接收前端传来的参数
 */
public class UserDTO {
   

    // 用户姓名
    private String name;

    /**
     * 用户生日
     * 说明: 当前端传过来的字符串类似 "2025-04-08 14:30:15" 时,
     * 使用 @DateTimeFormat 注解指定的 pattern 将会被用来解析成 LocalDateTime 对象
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime birthday;

    // 省略 getter 和 setter 方法
}

在 Controller 中,我们可以直接使用这个 DTO 对象接收前端数据:

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/user")
public class UserController {
   

    @PostMapping("/register")
    public String registerUser(@RequestBody UserDTO userDTO) {
   
        // userDTO.getBirthday() 已经自动解析成 LocalDateTime 类型
        // 这里可以添加你的业务逻辑处理,比如保存到数据库
        return "用户注册成功!";
    }
}

注意

  • @DateTimeFormat 只能影响反序列化,即把字符串转换为 Java 时间对象,而不会影响返回给前端的格式化。
  • 如果前端发送的时间格式与 pattern 不一致,会导致解析失败并报 400 错误。

二、@JsonFormat:定义返回给前端的日期格式

当你准备好将数据返回给前端时,希望看到的日期格式与前端的要求或者 UI 设计一致。这时就需要利用 @JsonFormat 注解来对日期进行格式化。通常,我们会同时在同一字段上添加两个注解,从而分别控制数据输入和输出。

示例代码

我们修改上述 DTO 类,新增一个 createTime 字段,并同时使用 @DateTimeFormat@JsonFormat 注解:

import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;

/**
 * 用户视图对象,用于数据交互
 */
public class UserVO {
   

    // 用户姓名
    private String name;

    /**
     * 用户生日:只参与数据绑定(输入)时的解析
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime birthday;

    /**
     * 用户创建时间:接收时使用 @DateTimeFormat 解析,返回时通过 @JsonFormat 格式化
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy/MM/dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime createTime;

    // getter 与 setter 方法
}

在这个例子中:

  • 当我们接收前端传来的 "birthday": "2025-04-08 14:30:15" 字符串时,会使用 @DateTimeFormat 转化为 LocalDateTime 对象。
  • 当系统返回 createTime 字段时,通过 @JsonFormat 指定的 "yyyy/MM/dd HH:mm:ss" 格式将其序列化,比如返回 "2025/04/08 15:22:10"
  • timezone = "GMT+8" 确保了时区正确,避免因默认时区导致的时间偏差问题。

三、完整示例:从前端数据接收、业务处理到返回结果

为了让你直观地理解整个流程,我们把 Controller、Service 和 DTO 结合起来,构建一个完整的示例。这里我们设计一个新建用户的功能,既包含接收前端传来的日期字符串,也包含生成并返回格式化后的创建时间。

1. 数据传输对象 UserDTO

import org.springframework.format.annotation.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;

/**
 * 用户数据传输对象,用于接收前端数据与返回结果的格式化
 */
public class UserDTO {
   

    // 用户姓名
    private String name;

    /**
     * 用户生日,前端通过 JSON 字符串传递,
     * 使用 @DateTimeFormat 进行解析
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime birthday;

    /**
     * 用户创建时间,后台生成,并且在返回时格式化展示
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime createTime;

    // Constructors、getter 与 setter 方法
}

2. Service 层处理用户数据

import org.springframework.stereotype.Service;
import java.time.LocalDateTime;

@Service
public class UserService {
   

    /**
     * 模拟创建用户的业务逻辑
     * @param userDTO 接收前端传来的用户数据
     * @return 返回处理后的用户数据,其中包含创建时间
     */
    public UserDTO createUser(UserDTO userDTO) {
   
        // 模拟保存到数据库操作,此处只做简单处理
        // 手动设置创建时间为当前系统时间
        userDTO.setCreateTime(LocalDateTime.now());

        // 可能还会做一些校验、赋值、日志记录等操作

        return userDTO;
    }
}

3. Controller 层暴露 REST 接口

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class UserController {
   

    @Autowired
    private UserService userService;

    /**
     * 新建用户接口
     * 接收 JSON 数据,并返回格式化后的用户信息
     * 前端请求例子:
     * POST /api/users
     * {
     *   "name": "张三",
     *   "birthday": "2025-05-08 10:10:10"
     * }
     */
    @PostMapping("/users")
    public UserDTO createUser(@RequestBody UserDTO userDTO) {
   
        // userDTO.getBirthday() 会使用 @DateTimeFormat 解析成 LocalDateTime 对象
        // 在 Service 层中,生成 createTime 字段
        UserDTO savedUser = userService.createUser(userDTO);
        // 返回的 savedUser 中,createTime 将通过 @JsonFormat 格式化为指定格式
        return savedUser;
    }
}

在这个完整示例中:

  1. 前端以以下 JSON 数据请求用户创建接口:

    {
         
        "name": "张三",
        "birthday": "2025-05-08 10:10:10"
    }
    
  2. Spring Boot 根据 @DateTimeFormat 解析 birthday 并封装到 UserDTO 中。

  3. Service 层自动设置 createTime 为当前时间,传回 Controller。

  4. Controller 返回时,Jackson 处理 createTime 字段时会应用 @JsonFormat 指定的格式,确保前端看到正确的时间格式。


四、常见问题与实践经验

在实际开发中,你可能会遇到以下一些问题:

  1. 返回格式不对:\
    如果你在实体上只使用了 @DateTimeFormat 而没有添加 @JsonFormat,那么返回的 JSON 可能仍然使用 ISO-8601 格式(例如 "2025-04-08T14:30:15")。解决方法是确保需要格式化的字段上同时加上 @JsonFormat 注解。
  2. 解析失败:\
    当前端传入的字符串格式和 @DateTimeFormat 定义的 pattern 不一致时,会出现解析错误。务必确保前端传输的日期格式和后端预期格式完全匹配;或者使用 ISO 枚举例如 @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) 以提高容错率。
  3. 时区问题:\
    由于不同环境的默认时区可能不同,建议在 @JsonFormat 中明确指定 timezone,比如 timezone = "GMT+8",以防服务器默认时区导致时间显示偏差。
  4. 全局配置 vs 局部注解:\
    为了避免每个实体类都写重复的注解,部分团队会在全局配置 Jackson 序列化/反序列化的日期格式。但有时某些字段需要特殊格式时,直接在字段上添加注解即可。两者可以灵活搭配使用。

五、总结

这篇文章详细讲解了如何使用 @DateTimeFormat@JsonFormat 来解决 Spring Boot 应用中日期时间格式化的常见问题。

  • @DateTimeFormat 主要用于【数据绑定】阶段,将前端传来的字符串转换为 Java 时间对象。
  • @JsonFormat 则用于【序列化】阶段,将 Java 时间对象以特定格式输出给前端。

两者合用可确保前后端无缝对接,既方便了数据输入,也优化了数据输出的格式。希望这篇博客能帮助你在项目中更游刃有余地处理日期时间相关的需求,避免踩坑。

目录
相关文章
|
1月前
|
JSON 前端开发 Java
深入理解 Spring Boot 中日期时间格式化:@DateTimeFormat 与 @JsonFormat 完整实践
在 Spring Boot 开发中,日期时间格式化是前后端交互的常见痛点。本文详细解析了 **@DateTimeFormat** 和 **@JsonFormat** 两个注解的用法,分别用于将前端传入的字符串解析为 Java 时间对象,以及将时间对象序列化为指定格式返回给前端。通过完整示例代码,展示了从数据接收、业务处理到结果返回的全流程,并总结了解决时区问题和全局配置的最佳实践,助你高效处理日期时间需求。
194 0
|
1月前
|
存储 Java 数据库
Spring Boot 注册登录系统:问题总结与优化实践
在Spring Boot开发中,注册登录模块常面临数据库设计、密码加密、权限配置及用户体验等问题。本文以便利店销售系统为例,详细解析四大类问题:数据库字段约束(如默认值缺失)、密码加密(明文存储风险)、Spring Security配置(路径权限不当)以及表单交互(数据丢失与提示不足)。通过优化数据库结构、引入BCrypt加密、完善安全配置和改进用户交互,提供了一套全面的解决方案,助力开发者构建更 robust 的系统。
64 0
|
1月前
|
Java 开发者 微服务
Spring Cloud OpenFeign详解与实践
总结起来说,Spring Cloud OpenFeign提供了一种简单易懂且高效的方式去实现微服务之间通信.它隐藏了许多复杂性,并且允许开发者以声明式方式编写HTTP客户端代码.如果你正在开发基于Spring Cloud 的微服务架构系统,Spring Cloud Open Feign是一个非常好用且强大工具.
157 33
|
2月前
|
前端开发 Java 数据库
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 介绍
本课介绍Spring Boot集成Thymeleaf模板引擎。Thymeleaf是一款现代服务器端Java模板引擎,支持Web和独立环境,可实现自然模板开发,便于团队协作。与传统JSP不同,Thymeleaf模板可以直接在浏览器中打开,方便前端人员查看静态原型。通过在HTML标签中添加扩展属性(如`th:text`),Thymeleaf能够在服务运行时动态替换内容,展示数据库中的数据,同时兼容静态页面展示,为开发带来灵活性和便利性。
79 0
|
2月前
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于 xml 的整合
本教程介绍了基于XML的MyBatis整合方式。首先在`application.yml`中配置XML路径,如`classpath:mapper/*.xml`,然后创建`UserMapper.xml`文件定义SQL映射,包括`resultMap`和查询语句。通过设置`namespace`关联Mapper接口,实现如`getUserByName`的方法。Controller层调用Service完成测试,访问`/getUserByName/{name}`即可返回用户信息。为简化Mapper扫描,推荐在Spring Boot启动类用`@MapperScan`注解指定包路径避免逐个添加`@Mapper`
84 0
|
2月前
|
Java 测试技术 微服务
微服务——SpringBoot使用归纳——Spring Boot中的项目属性配置——少量配置信息的情形
本课主要讲解Spring Boot项目中的属性配置方法。在实际开发中,测试与生产环境的配置往往不同,因此不应将配置信息硬编码在代码中,而应使用配置文件管理,如`application.yml`。例如,在微服务架构下,可通过配置文件设置调用其他服务的地址(如订单服务端口8002),并利用`@Value`注解在代码中读取这些配置值。这种方式使项目更灵活,便于后续修改和维护。
39 0
|
2月前
|
SQL Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— application.yml 中对日志的配置
在 Spring Boot 项目中,`application.yml` 文件用于配置日志。通过 `logging.config` 指定日志配置文件(如 `logback.xml`),实现日志详细设置。`logging.level` 可定义包的日志输出级别,例如将 `com.itcodai.course03.dao` 包设为 `trace` 级别,便于开发时查看 SQL 操作。日志级别从高到低为 ERROR、WARN、INFO、DEBUG,生产环境建议调整为较高级别以减少日志量。本课程采用 yml 格式,因其层次清晰,但需注意格式要求。
176 0
|
2月前
|
缓存 NoSQL Java
基于SpringBoot的Redis开发实战教程
Redis在Spring Boot中的应用非常广泛,其高性能和灵活性使其成为构建高效分布式系统的理想选择。通过深入理解本文的内容,您可以更好地利用Redis的特性,为应用程序提供高效的缓存和消息处理能力。
196 79
|
2月前
|
Java Spring
SpringBoot自动配置原理
本文深入解析了SpringBoot的核心功能——自动配置,重点探讨了`org.springframework.boot.autoconfigure`及相关注解的工作机制。通过分析`@SpringBootApplication`、`@EnableAutoConfiguration`等注解,揭示了SpringBoot如何基于类路径和条件自动装配Bean
103 7
|
2月前
|
JSON 前端开发 Java
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 的使用
本文介绍了 Thymeleaf 在 Spring Boot 项目中的使用方法,包括访问静态页面、处理对象和 List 数据、常用标签操作等内容。通过示例代码展示了如何配置 404 和 500 错误页面,以及如何在模板中渲染对象属性和列表数据。同时总结了常用的 Thymeleaf 标签,如 `th:value`、`th:if`、`th:each` 等,并提供了官方文档链接以供进一步学习。
113 0
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 的使用

热门文章

最新文章