在一个请求中存在一个时间字段,但是前端传过来的值格式有问题,由此引出本文。
问题:
- 后端接收:
@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类型的时候因为参数的格式问题一直导致序列化失败,所以本文其实最终只做了一件事情:在反序列化之前将参数处理成正常格式。 - 更多
在解决这个问题的过程中有几位网友建议将Date转为LocalDateTime类型,我查了一下,都在说LocalDateTime性能好,线程安全,所以建议以后还是使用LocalDateTime吧。
疑问
我在解决这个问题的时候看到网上很多文章写得自定义日期转换器Converter,但是不知道为什么我按照别人说的文章写了但是没用,最后还是用的上面这两个方法。
7872

被折叠的 条评论
为什么被折叠?



