当前位置: 首页 > news >正文

SpringBoot项目里时间传参总乱套?手把手教你用@JsonFormat和@DateTimeFormat搞定前后端日期格式

SpringBoot时间传参乱码?@JsonFormat与@DateTimeFormat终极解决方案

1. 问题场景:前后端日期格式的"鸡同鸭讲"

上周团队新来的实习生小王遇到了一个典型问题:前端提交的订单创建时间2023-08-15 14:30:00,到后端变成了Wed Aug 15 14:30:00 CST 2023这种原始格式,而返回给前端时又成了1657895400000这样的时间戳。这种"格式变形记"在RESTful API开发中屡见不鲜,根本原因在于:

  • HTTP协议本身不定义日期格式标准,导致各系统自行其是
  • Java的Date对象与JSON字符串存在天然鸿沟,需要显式转换规则
  • 时区问题如同隐形炸弹,GMT、UTC、CST等时区混用会导致8小时的时间差
// 典型的问题实体类 public class Order { private Date createTime; // 裸奔的Date字段 // getters & setters }

当这个Order对象通过SpringBoot的@RestController返回时,Jackson会默认将Date序列化为时间戳;而前端提交JSON时,又期望接收yyyy-MM-dd格式的字符串。这种双向格式不匹配就是乱码的根源。

2. 注解双雄:各司其职的格式化方案

2.1 @JsonFormat:JSON序列化的守门人

这是Jackson库的核心注解,专门解决Java对象与JSON互转时的格式问题。它的典型配置:

@JsonFormat( pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8", shape = JsonFormat.Shape.STRING ) private Date createTime;

关键参数说明:

参数必要性示例值作用
pattern必选"yyyy-MM-dd"定义日期显示格式
timezone强烈建议"GMT+8"避免时区导致的8小时误差
shape可选Shape.STRING强制转为字符串而非时间戳

注意:在SpringBoot 2.x+版本中,默认已包含Jackson依赖。若项目异常,检查pom.xml是否包含:

<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency>

2.2 @DateTimeFormat:HTTP参数的转换器

Spring框架提供的这个注解,专门处理URL参数和表单数据的日期转换:

@PostMapping("/orders") public ResponseEntity<?> createOrder( @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date orderDate) { // 业务逻辑 }

常见使用场景对比:

场景适用注解示例
REST接口返回值@JsonFormat{"createTime":"2023-08-15"}
GET请求参数@DateTimeFormat/orders?date=2023-08-15
POST表单提交@DateTimeFormatdate=2023-08-15
JSON请求体@JsonFormat{"date":"2023-08-15"}

3. 实战组合拳:完整解决方案

3.1 实体类的最佳实践

@Data public class OrderDTO { @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; // 其他字段... }

这种双注解组合能覆盖:

  • 前端 → 后端:表单提交、URL参数、JSON请求体
  • 后端 → 前端:JSON响应数据

3.2 控制层的典型配置

@RestController @RequestMapping("/api/orders") public class OrderController { // 处理URL参数 @GetMapping public List<Order> queryOrders( @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate, @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) { return orderService.findByDateRange(startDate, endDate); } // 处理JSON请求体 @PostMapping public Order createOrder(@RequestBody OrderDTO dto) { return orderService.save(dto); } }

3.3 全局配置的增强方案

对于企业级应用,建议补充以下配置:

  1. Jackson全局配置(application.yml):
spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8
  1. 自定义日期转换器
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar(); registrar.setUseIsoFormat(true); registrar.registerFormatters(registry); } }

4. 避坑指南:常见问题解析

4.1 时区问题的"八小时魔咒"

现象:数据库存的是2023-08-15 00:00:00,前端显示变成2023-08-14 16:00:00

解决方案

  1. 确保所有注解和配置统一时区(建议GMT+8
  2. 数据库连接字符串添加时区参数:
    jdbc:mysql://localhost:3306/db?serverTimezone=Asia/Shanghai

4.2 格式不匹配的解析异常

错误日志

Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'

排查步骤

  1. 检查前端传递的格式是否与pattern定义一致
  2. 验证注解是否应用在正确的字段上
  3. 测试直接使用curl发送请求排除前端问题

4.3 日期比较的隐藏风险

// 错误的比较方式 if (new Date().equals(order.getCreateTime())) {...} // 正确做法 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); if (formatter.format(LocalDate.now()).equals(formatter.format(order.getCreateTime()))) {...}

5. 高阶技巧:LocalDateTime的现代方案

对于新项目,推荐使用Java 8的日期API:

public class Order { @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; // 不需要@DateTimeFormat // 因为LocalDateTime默认支持ISO格式 }

优势对比:

特性java.util.DateLocalDateTime
线程安全
时区处理需要显式指定内置时区无关
API设计过时现代流畅式API
精度毫秒纳秒
// 日期运算示例 LocalDateTime now = LocalDateTime.now(); LocalDateTime tomorrow = now.plusDays(1); Duration duration = Duration.between(now, tomorrow);
http://www.zskr.cn/news/1438915.html

相关文章:

  • 从Verilog到布线:你的代码是如何‘塞’进FPGA里LUT的?一个综合过程的完整拆解
  • 开源能源监测系统助力住宅供暖转型
  • 告别Log混乱!用CAPL的setLogFileName函数实现自动化测试日志的精准归档
  • 别再只用YOLOv8做检测了!手把手教你集成BotSORT实现足球比赛球员轨迹跟踪
  • 全域可视可控|核电外来人员无感安防新架构
  • 实测对比:YOLOv8n与YOLOv8m在Jetson Orin Nano上的训练速度与内存占用(附解决Killed报错方法)
  • Java程序设计(第3版)第四章——错误:未初始化变量
  • 从434个自动化故事构建知识体系:DevOps、RPA与工业自动化的实践指南
  • 为什么yolov8部署在rdkx5上之后检测不到结果
  • 人形机器人技术架构解析:从感知到执行的AI闭环与挑战
  • Java Programming Chapter 4——Error: Variable not initialized.
  • 超越总收入差距:用Dagum基尼分解分析区域发展不平衡(Python实战)
  • 从‘空转’到‘满血’:实战解决TensorFlow/PyTorch训练时GPU功率低Util高的坑
  • Cortex-A9 ACP接口ARUSERS与AWUSERS信号解析
  • 2026年咸阳市黄金回收靠谱门店推荐 黄金+K金+白银+铂金回收门店TOP5排行榜+联系方式 - 盛世金银回收
  • 2026年湘潭市黄金回收靠谱门店推荐 黄金+K金+白银+铂金回收门店TOP5排行榜+联系方式 - 盛世金银回收
  • HPC构建系统:GPU加速与并行编程优化指南
  • 别再踩坑了!STM32H7的MPU内存属性配置详解(附DMA与Cache协作最佳实践)
  • 用SpikingJelly的泊松编码器给Lena图像‘打码’:一个脉冲神经网络入门实验
  • 2026年襄阳市黄金回收靠谱门店推荐 黄金+K金+白银+铂金回收门店TOP5排行榜+联系方式 - 盛世金银回收
  • 【鸿蒙原生应用开发--ArkUI--016】Guess-number 猜数字游戏开发教程
  • ESP32-C3开发踩坑记:我把Panic Handler从‘无限重启’改成‘原地挂起’,调试效率翻倍了
  • R语言实战:用`caret`和`tidymodels`一键计算MSE,搞定模型交叉验证
  • 2026年孝感市黄金回收靠谱门店推荐 黄金+K金+白银+铂金回收门店TOP5排行榜+联系方式 - 盛世金银回收
  • 告别MATLAB依赖!手把手教你用App Designer打包独立桌面软件(含Runtime组件)
  • 别再用document.querySelector硬怼了!Edge视频加速报TypeError的深层原因与三种破解思路
  • 告别一步一卡顿:用ACT算法让你的机械臂模仿学习更丝滑(附LeRobot实战代码)
  • OpenClaw:模块化AI智能体框架的设计、实现与工程实践
  • 数据科学实战:从数据挖掘到决策智能的完整知识体系
  • 别再手动调ARR了!用STM32H7的DDS方案实现高精度波形输出,实测对比来了