JDK8 的LocalDate 系列日期API ,比Date 或者 Calendar 都好用很多,但是在SpringMvc 自动装配会有点小问题
会导致抛出类似异常
default message [Failed to convert property value of type 'java.lang.String' to required type 'java.time.LocalDateTime' for property 'createDate';
nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type ... for value '2017-11-03';
nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value
解决方法 1 注意 @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") form 或者url 传过来的 日期必须严格根据此 格式,实在没有的,需要在前端补全格式,否则依然会抛出以上异常
@JsonDeserialize(using = LocalDateTimeDeserializer.class) //application/json @JsonSerialize(using = LocalDateTimeSerializer.class) //application/json
//LocalDateTime @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") //application/x-www-form-urlencoded private LocalDateTime createDate;
//LocalDate
@DateTimeFormat(pattern = "yyyy-MM-dd") //application/x-www-form-urlencoded
private LocalDate createDate;
解决方法 2 此方法只处理json 不能处理 application/x-www-form-urlencoded 也就是说 @ModelAttribute 的时候还是需要 @DateTimeFormat 注解
继承 WebMvcConfigurerAdapter
private static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> { private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Override public void serialize(LocalDateTime value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeString(dateTimeFormatter.format(value)); } } private static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> { @Override public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { String result = StringDeserializer.instance.deserialize(jsonParser, deserializationContext); return LocalDateTimeUtil.UDateToLocalDateTime(DateUtil.parseDate(DateUtil.C_TIME_PATTON_DEFAULT,result)); } }
@Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { for (HttpMessageConverter converter : converters) { if (converter instanceof MappingJackson2HttpMessageConverter) { ObjectMapper objectMapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer()); module.addDeserializer(LocalDateTime.class,new LocalDateTimeDeserializer()); objectMapper.registerModule(module); } } }
2018年3月12日 15:09:28 对 解决方法 2 的补充 在继承WebMvcConfigurerAdapter的配置类中注册转换器 可以支持application/x-www-form-urlencoded 的自动装配
@Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new DateConverter()); registry.addConverter(new LocalDateConverter()); registry.addConverter(new LocalDateTimeConverter()); } public static class DateConverter implements Converter<String, Date> { @Override public Date convert(String source) { if (!NumberUtils.isDigits(source)) return null; Long milli = NumberUtils.createLong(source); return new Date(milli); } } public static class LocalDateTimeConverter implements Converter<String, LocalDateTime> { @Override public LocalDateTime convert(String source) { if (!NumberUtils.isDigits(source)) return null; Long milli = NumberUtils.createLong(source); return LocalDateTime.ofEpochSecond(milli, 0, ZoneOffset.UTC); } } public static class LocalDateConverter implements Converter<String, LocalDate> { @Override public LocalDate convert(String source) { if (!NumberUtils.isDigits(source)) return null; Long milli = NumberUtils.createLong(source); return LocalDateTime.ofEpochSecond(milli, 0, ZoneOffset.UTC).toLocalDate(); } }