背景:
解决前端传入时间参数格式不固定场景,避免接收参数报错时间格式不能序列化。
一、概述
在 Java 后端开发中,处理 JSON 数据时,经常需要对日期时间字段进行反序列化。Java 中常用的日期时间类型是 java.time.LocalDateTime,但前端传入的数据格式可能千差万别,如 "2025-04-05"、"2025-04-05 13:30:00" 或者仅仅是一个时间字符串 "13:30:00"。为了应对这些灵活的时间格式,我们编写了一个自定义的 Jackson 反序列化器 —— FlexibleLocalDateTimeDeserializer
二、设计目标
FlexibleLocalDateTimeDeserializer 的主要目标是:
- 兼容多种时间格式:支持 yyyy-MM-dd、yyyy-MM-dd HH:mm:ss 和 HH:mm:ss。
- 避免反序列化失败:当遇到不规范的时间格式时,提供合理的默认行为或抛出明确错误。
- 与业务数据模型解耦:通过 Jackson 注解绑定到 DTO 字段,无需修改业务逻辑代码即可完成适配。
三、实现细节
通过正则表达式实现格式处理
-
- 包含空格 → 使用完整日期时间格式;
- 匹配日期格式 → 补上 23:59:59;
- 匹配时间格式 → 结合当前日期生成完整时间戳
定义序列化处理工具
import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class FlexibleLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
@Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String value = p.getText();
if (value == null || ObjectUtil.isEmpty( value)) return null;
try {
if (value.contains(" ")) {
return LocalDateTime.parse(value, DATE_TIME_FORMATTER);
} else if (value.matches("\\d{4}-\\d{2}-\\d{2}")) {
String s = LocalDate.parse(value, DATE_FORMATTER).toString() + " 23:59:59";
LocalDateTime parse = LocalDateTime.parse(s, DATE_TIME_FORMATTER);
return parse;
// return LocalDate.parse(value, DATE_FORMATTER).atTime(LocalTime.MAX); // 存数据库为第二天00:00:00
} else if (value.matches("\\d{2}:\\d{2}:\\d{2}")) {
LocalTime time = LocalTime.parse(value, TIME_FORMATTER);
return LocalDateTime.now().with(time);
}
} catch (Exception e) {
throw new RuntimeException("无法解析日期时间:" + value, e);
}
throw new RuntimeException("未知的日期格式:" + value);
}
}
四、实际使用示
在接收前端的dto字段参数加上注解即可。这时候前端传入yyyy-MM-dd、yyyy-MM-dd HH:mm:ss 和 HH:mm:ss格式都可以接收,可自定义填充日期格式。
@JsonFormat(shape = JsonFormat.Shape.STRING)
@JsonDeserialize(using = FlexibleLocalDateTimeDeserializerZero.class)
private LocalDateTime startdate;
@JsonFormat(shape = JsonFormat.Shape.STRING)
@JsonDeserialize(using = FlexibleLocalDateTimeDeserializer.class)
private LocalDateTime enddate;