记录springboot 项目 中LocalDateTime序列化失效问题的解决方案:
1、遇到的问题
比如下面的配置:
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
# 默认策略,任何情况都执行序列化
default-property-inclusion: always
但是使用 JsonFormat并未达到我想要的效果
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
由于项目部署地和开发地不是同一个时区, 测试的时候发现页面显示的时间和数据库不一致,即:我们在哪里部署,当地的数据库和页面就保持一致。所以,不能直接设置时区(根据当前部署的OS自动设置)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",locale = "zh", timezone = "GMT+8")
private Date endTime;
2、解决方案
2.1 出参序列化
定义注解 LocalDateTimeFormat
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = LocalDateTimeFormatSerialize.class)
public @interface LocalDateTimeFormat {
String pattern() ;
}
定义序列化类
import cn.hutool.core.date.LocalDateTimeUtil;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.IOException;
import java.util.Date;
import java.util.Objects;
/**
* @author : qinjinyuan
* @desc : localDateTime format
* @date : 2023/12/06 20:08
*/
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class LocalDateTimeFormatSerialize extends JsonSerializer implements ContextualSerializer {
private String pattern;
@Override
public void serialize(Object objValue, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
if (Objects.isNull(objValue)) {
jsonGenerator.writeString("");
return;
}
Date value = (Date) objValue;
jsonGenerator.writeString(LocalDateTimeUtil.format(LocalDateTimeUtil.of(value), pattern));
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
if (Objects.nonNull(beanProperty)) {
if (Objects.equals(beanProperty.getType().getRawClass(), Date.class)) {
LocalDateTimeFormat anno = beanProperty.getAnnotation(LocalDateTimeFormat.class);
if (Objects.isNull(anno)) {
anno = beanProperty.getContextAnnotation(LocalDateTimeFormat.class);
}
if (Objects.nonNull(anno)) {
this.pattern = anno.pattern();
return new LocalDateTimeFormatSerialize(pattern);
}
}
return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
}
return serializerProvider.findNullValueSerializer(null);
}
}
DTO中使用栗子
@LocalDateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "创建时间")
private Date createTime;
2.2 入参反序列化Deserializer
定义类CustomerDateDeserializer (字符串 -> LocalDateTime)
package com.sikaryofficial.common.core.annotation;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.jackson.JsonComponent;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Date;
/**
* @author : qinjinyuan
* @desc : 自定义反序列化器,格式化时间
* @date : 2023/12/14 9:53
*/
@Slf4j
@JsonComponent
public class CustomerDateDeserializer extends JsonDeserializer<Date> {
/**
* @param jsonParser
* @param deserializationContext
* @return
* @throws IOException
* @throws JacksonException
*/
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
if(CharSequenceUtil.isBlank(jsonParser.getText())){
return null;
}
LocalDateTime localDateTime = LocalDateTimeUtil.parse(jsonParser.getText(), "yyyy-MM-dd HH:mm:ss");
return new DateTime(localDateTime);
}
}
request 中使用栗子
@ApiModelProperty(value = "开始日期", example = "yyyy-MM-dd HH:mm:ss")
@JsonDeserialize(using = CustomerDateDeserializer.class)
private Date startTime;
@ApiModelProperty(value = "结束时间", example = "yyyy-MM-dd HH:mm:ss")
@JsonDeserialize(using = CustomerDateDeserializer.class)
private Date endTime;
3、小结
LocalDateTime 是JDK8推出, 时区是根据操作系统来进行设置,方便我们使用跟时区有关系的时间; spring 内置 Jackson, 如果通过配置无法解决类似问题,可以采用我的方案。