问题复现
当我们使用LocalDateTime 的时候,尤其是在SpringBoot项目中,有哪些注意点呢,一起来看看吧。
假设现在有一个Post请求
@ApiOperation("查询列表")
@PostMapping("queryList")
public ResponseVo queryList(@RequestBody TypeReqVo reqVo){
System.out.println(reqVo.getCreateTime());
return null;
}
TypeReqVo
@Data
public class TypeReqVo {
private LocalDateTime createTime;
}
当我们发一个post请求,看看会怎么样?
直接报错:JSON parse error: Cannot deserialize value of type java.time.LocalDateTime from String "2025-03-04": Failed to deserialize java.time.LocalDateTime:
配置Jackson
解决办法很简单,只需要加一个配置类
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper() {
// 初始化一个 ObjectMapper 对象,用于自定义 Jackson 的行为
ObjectMapper objectMapper = new ObjectMapper();
// 忽略未知属性
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
// 设置凡是为 null 的字段,返参中均不返回,请根据项目组约定是否开启
// objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 设置时区
objectMapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
// JavaTimeModule 用于指定序列化和反序列化规则
JavaTimeModule javaTimeModule = new JavaTimeModule();
// 支持 LocalDateTime、LocalDate、LocalTime
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
// 支持 YearMonth
javaTimeModule.addSerializer(YearMonth.class, new YearMonthSerializer(DateTimeFormatter.ofPattern("yyyy-MM")));
javaTimeModule.addDeserializer(YearMonth.class, new YearMonthDeserializer(DateTimeFormatter.ofPattern("yyyy-MM")));
objectMapper.registerModule(javaTimeModule);
return objectMapper;
}
}
基础配置
FAIL_ON_UNKNOWN_PROPERTIES设置为false可避免反序列化时因未知属性抛出异常,符合接口容错性设计12。FAIL_ON_EMPTY_BEANS设置为false防止空对象序列化失败,适用于包含无属性 Bean 的场景12。时区配置
setTimeZone("Asia/Shanghai")明确指定时区,避免因服务器时区差异导致时间转换错误12。日期时间处理
- 通过
JavaTimeModule自定义LocalDateTime、LocalDate等类型的格式化规则,覆盖默认的 ISO 格式,统一接口返回的日期格式12。- 包含
YearMonth类型的序列化,满足特殊日期格式需求。
因为这两行
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
如果你前端传过来的格式为yyyy-MM-dd,那么后台必须用LocalDate,而不是LocalDateTime,所以,我们要这样传递参数:
{
"createTime": "2025-03-04 00:00:00"
}
发起请求,观察后台日志:
2025-03-04T00:00
成功接收到了,就是打印格式不太好看,但是这个不影响,我直接把这个日期返回出去,看效果。
TypeRespVo
@Data
public class TypeRespVo {
private LocalDateTime createTime;
}
queryList
@ApiOperation("查询列表")
@PostMapping("queryList")
public ResponseVo queryList(@RequestBody TypeReqVo reqVo){
System.out.println(reqVo.getCreateTime());
TypeRespVo respVo = new TypeRespVo();
respVo.setCreateTime(reqVo.getCreateTime());
ResponseVo vo = new ResponseVo();
vo.setData(respVo);
return vo;
}
测试
由此可见,返回的格式也是正确的,这就行了。
与MybatisPlus整合
方法论有了,接下来,我们用LocalDateTime的新特性,结合真实数据库来做测试。
核心代码
queryList
public List<TypeRespVo> queryList(TypeReqVo reqVo) {
if(Objects.nonNull(reqVo.getCreateTimeEnd())) {
LocalDateTime localDateTime = reqVo.getCreateTimeEnd().plusDays(1);
reqVo.setCreateTimeEnd(localDateTime);
}
List<TypeRespVo> types = baseMapper.selectListNew(reqVo);
return types;
}
xml文件
<select id="selectListNew" resultType="com.tms.model.resp.TypeRespVo">
select create_time from type
<where>
<if test="req.createTimeStart !=null">
and create_time >= #{req.createTimeStart}
</if>
<if test="req.createTimeEnd !=null">
and create_time < #{req.createTimeEnd}
</if>
</where>
</select>
测试:
假设传入的两个日期都是具体某一天,所以时分秒都是00,由于代码中会自动加一天(左闭右开),所以查询的还是这一天的时间
PS: 如果前端不想传时分秒,改成yyyy-MM-dd 格式,那么也可以直接用LocalDate。
总结:能不用java.util.Date,就别用了。