在一个请求中存在一个时间字段,但是前端传过来的值格式有问题,由此引出本文。
@Data
@NoArgsConstructor
@ApiModel(value = "时间参数")
public class DateInsert {
@ApiModelProperty(value = "时间A")
private Date a;
@ApiModelProperty(value = "时间B")
private Date b;
}
{
"a":"2020-12-20T02:08:39.000Z",
"b":"2020-12-27 07:28:36"
}
本文的问题是,日期格式数据前端可能会传输两种过来(格式化好的以及带T的),a、b两个字段实际上是同一个字段,此处目的是同时实现两种格式数据接收。(注意,这两个字段数据类型、注解等一致)
package com.single.cong.config;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
/** 解决返回值乱码问题 */
@Bean
public HttpMessageConverter<String> responseBodyStringConverter() {
StringHttpMessageConverter converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
return converter;
}
/** 修改StringHttpMessageConverter默认配置 */
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(responseBodyStringConverter());
// 日期序列化配置
JavaTimeModule javaTimeModule = new JavaTimeModule();
/** 序列化配置,针对java8 时间 **/
javaTimeModule.addSerializer(LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addSerializer(LocalDate.class,
new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
/** 反序列化配置,针对java8 时间 **/
javaTimeModule.addDeserializer(LocalDateTime.class,
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDate.class,
new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addDeserializer(LocalTime.class,
new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
// Date序列化和反序列化
javaTimeModule.addSerializer(Date.class, new JsonSerializer<Date>() {
@Override
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formattedDate = formatter.format(date);
jsonGenerator.writeString(formattedDate);
}
});
javaTimeModule.addDeserializer(Date.class, new JsonDeserializer<Date>() {
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException, JsonProcessingException {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = jsonParser.getText();
// 处理数据在这里
try {
if (date.contains("T")) {
date = date.replaceAll("T", " ").substring(0, 19);
// 特殊格式数据,进行日期转换
return format.parse(date);
} else {
// 正常数据日期转换
return format.parse(date);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
/**
* 将Long,BigInteger序列化的时候,转化为String,某些类里面的Long类型数据超长造成精度缺失可以在属性上使用@JsonSerialize注解
*/
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule).registerModule(javaTimeModule);
// objectMapper.registerModule(simpleModule);
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
messageConverter.setObjectMapper(objectMapper);
converters.add(messageConverter);
}
}
注意:date = date.replaceAll("T", " ").substring(0, 19);
单纯是将字符串处理一下然后再格式化,没什么说的,但是要注意,如果使用此种方式,那么系统里面所有的Date类型的数据序列化都会先走一个判断,如果系统中参数格式不固定可以使用这种方式,但是肯定会带来性能上的问题。JsonDeserializer
package com.single.cong.config;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MyDateSerialize extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
log.info("参数数据为:[{}]", jsonParser.getText());
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = jsonParser.getText();
try {
if (date.contains("T")) {
date = date.replaceAll("T", " ").substring(0, 19);
// 特殊格式数据,进行日期转换
return format.parse(date);
} else {
// 正常数据日期转换
return format.parse(date);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
使用:@Data
@NoArgsConstructor
@ApiModel(value = "时间参数")
public class DateInsert {
@JsonDeserialize(using = MyDateSerialize.class)
@ApiModelProperty(value = "时间A")
private Date a;
@ApiModelProperty(value = "时间B")
private Date b;
}
这样就只需要对有问题的字段单独设置自定义的序列化方式,至于其他的字段不变。Date
转为LocalDateTime
类型,我查了一下,都在说LocalDateTime
性能好,线程安全,所以建议以后还是使用LocalDateTime
吧。我在解决这个问题的时候看到网上很多文章写得自定义日期转换器Converter,但是不知道为什么我按照别人说的文章写了但是没用,最后还是用的上面这两个方法。