Spring Boot 使用自定义 JsonDeserializer 同时支持多种日期格式

使用自定义 JsonDeserializer 同时支持多种日期格式

  • 背景
  • [1. 为什么 @JsonFormat 无法解决这个问题?](#1. 为什么 @JsonFormat 无法解决这个问题?)
  • [2. 自定义日期反序列化器](#2. 自定义日期反序列化器)
    • [2.1 编写自定义解析器](#2.1 编写自定义解析器)
  • [3. 让字段使用自定义解析器](#3. 让字段使用自定义解析器)
  • [4. 使用效果](#4. 使用效果)
  • [5. 方案的优点总结](#5. 方案的优点总结)
  • [6. 什么时候应该使用这个方案?](#6. 什么时候应该使用这个方案?)
  • [7. 总结](#7. 总结)

背景

在实际业务开发中,后端经常遇到一个尴尬的问题:

  • 有前端传 "2025-11-15 10:00:00"

  • 有些前端只传 "2025-11-15"

而后端字段是一个 Date 类型,默认 Jackson 只能按一个格式解析,这就导致:

yaml 复制代码
Invalid JSON input: Cannot deserialize value of type java.util.Date

这篇文章将介绍一种干净优雅的方式:通过自定义 Jackson 反序列化器,让一个字段同时支持多种日期格式。

1. 为什么 @JsonFormat 无法解决这个问题?

假设你写了:

java 复制代码
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;

那么 Jackson 只允许格式:

yaml 复制代码
2025-11-15 10:00:00

如果前端传:

yaml 复制代码
2025-11-15

仍然会报错。

原因:
@JsonFormat 不支持多模式解析

只能配置一个格式,无法 fallback。

因此想兼容多格式,必须上 自定义反序列化器

2. 自定义日期反序列化器

2.1 编写自定义解析器

创建一个类 MultiDateDeserializer

java 复制代码
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MultiDateDeserializer extends JsonDeserializer<Date> {

    private static final String[] patterns = new String[]{
            "yyyy-MM-dd HH:mm:ss",
            "yyyy-MM-dd"
    };

    @Override
    public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        if (StrUtil.isEmpty(p.getText())) {
            return null;
        }
        String value = p.getText().trim();

        for (String pattern : patterns) {
            try {
                return new SimpleDateFormat(pattern).parse(value);
            } catch (Exception ignored) {
            }
        }
        throw new RuntimeException("日期格式不合法: " + value);
    }
}

✔ 支持多个格式

yyyy-MM-dd HH:mm:ss

yyyy-MM-dd

✔ 自动容错

只要符合其中一个格式就自动解析。

3. 让字段使用自定义解析器

在 DTO 中直接指定:

java 复制代码
@JsonDeserialize(using = MultiDateDeserializer.class)
private Date startTime;

此时,这个字段已经具备以下能力:

前端入参 能否解析 示例
完整时间 2025-11-15 10:00:00
仅日期 2025-11-15
其它格式 2025/11/15

当格式不合法时后端会明确抛出错误,防止脏数据进入系统。

4. 使用效果

前端传:

json 复制代码
{
  "startTime": "2025-11-15"
}

或:

json 复制代码
{
  "startTime": "2025-11-15 10:00:00"
}

Spring Boot 都能优雅解析成 java.util.Date

再也不会出现:

java 复制代码
InvalidFormatException: expected format "yyyy-MM-dd HH:mm:ss"

5. 方案的优点总结

  1. 向后兼容

    老接口无需改动。

  2. 不影响其它字段

    只对指定字段生效,不会影响全局日期解析。

  3. 代码可维护性高

    添加更多格式非常方便,只需要在数组里多加一条。

  4. 错误提示明确

    解析失败时能清晰抛出异常,便于排查问题。

6. 什么时候应该使用这个方案?

如果你的项目出现以下情况,这个方案就特别适合:

  • 不同前端传参格式不一致

  • 老系统与新系统混用日期格式

  • 字段本质上是一个 Date,需要兼容多种输入方式

  • 想保持 DTO 字段仍然是 Date,而不是 String 或 LocalDateTime

如果你的项目中这种日期字段更多,也可以把此反序列化器注册为 全局解析器,统一管理。

7. 总结

Spring Boot 默认的 Jackson 日期解析是单格式 的,无法兼容复杂的前端情况。

通过自定义 JsonDeserializer,我们可以让某个字段支持多种日期格式,同时保持后端代码整洁、可维护。

这是一个非常实用的小技巧,几乎所有团队都会遇到这样的需求,建议收藏和长期使用。

相关推荐
sinat_2554878121 小时前
教授提供的有用链接 — 20·学习笔记
java
Java面试题总结21 小时前
2026Java面试八股文合集(持续更新)
java·spring·面试·职场和发展·java面试·java八股文
一勺菠萝丶21 小时前
芋道框架 - API 前缀区分机制
java·linux·python
kcuwu.21 小时前
Python判断及循环
android·java·python
前进的李工1 天前
LangChain使用之Model IO(提示词模版之ChatPromptTemplate)
java·前端·人工智能·python·langchain·大模型
ywf12151 天前
Spring Integration + MQTT
java·后端·spring
liuyao_xianhui1 天前
优选算法_两数之和_位运算_C++
java·开发语言·数据结构·c++·算法·链表·动态规划
李白的粉1 天前
基于springboot的知识管理系统
java·spring boot·毕业设计·课程设计·知识管理系统·源代码
大傻^1 天前
Spring AI 2.0 多模型提供商配置:OpenAI、Gemini、Anthropic 与 Ollama 深度集成
java·人工智能·spring·springai
爱丽_1 天前
JVM 堆参数怎么设:先建立内存基线,再谈性能优化
java·jvm·性能优化