当前位置: 首页 > 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.jsqmd.com/news/927584/

相关文章:

  • 保姆级教程:用Altium Designer 23从零画一块Type-C小板(附立创EDA导库技巧)
  • 从Verilog到布线:你的代码是如何‘塞’进FPGA里LUT的?一个综合过程的完整拆解
  • 开源能源监测系统助力住宅供暖转型
  • 告别Log混乱!用CAPL的setLogFileName函数实现自动化测试日志的精准归档
  • 基于GPT与Pytest的API自动化测试生成实践
  • HPC容器化部署的性能优化与跨平台兼容性挑战
  • 别再只用YOLOv8做检测了!手把手教你集成BotSORT实现足球比赛球员轨迹跟踪
  • 全域可视可控|核电外来人员无感安防新架构
  • 机器学习完全指南:从理论基石到前沿实践的系统化解析
  • 【系统学AI】18 AI Native设计原则(2026版):10大原则+反模式+落地清单
  • 实测对比:YOLOv8n与YOLOv8m在Jetson Orin Nano上的训练速度与内存占用(附解决Killed报错方法)
  • 实习20-DeepResearch项目
  • Multisim仿真避坑指南:差分放大电路偏移计算,你的结果为啥总对不上?
  • 2026年武威市黄金回收靠谱门店推荐 黄金+K金+白银+铂金回收门店TOP5排行榜+联系方式 - 盛世金银回收
  • 避坑指南:STM32G473 BootLoader开发中,中断向量表偏移与Flash布局的那些“坑”
  • YOLOv8/5实战:用Shape-IoU损失函数提升小目标检测精度(附代码)
  • Java程序设计(第3版)第四章——错误:未初始化变量
  • 从‘光’到‘色’的魔法:拆解Unity渐变纹理Shader,理解Half Lambert与颜色映射的底层逻辑
  • 从434个自动化故事构建知识体系:DevOps、RPA与工业自动化的实践指南
  • 人形机器人技术架构解析:从感知到执行的AI闭环与挑战
  • 用C#和MQTTnet在WinForm里搞个物联网消息中心,附完整源码
  • C语言指针精讲(二)∶加深对指针使用,理解传址调用
  • DIY一个高精度非接触测温仪:基于Arduino与MLX90614的完整项目教程
  • 2026年西安市黄金回收靠谱门店推荐 黄金+K金+白银+铂金回收门店TOP5排行榜+联系方式 - 盛世金银回收
  • 为什么yolov8部署在rdkx5上之后检测不到结果
  • Java Programming Chapter 4——Error: Variable not initialized.
  • 从‘空转’到‘满血’:实战解决TensorFlow/PyTorch训练时GPU功率低Util高的坑
  • 超越总收入差距:用Dagum基尼分解分析区域发展不平衡(Python实战)
  • Cortex-A9 ACP接口ARUSERS与AWUSERS信号解析
  • 单点修改、区间求和(模板)、区间修改,单点查询(模板)