SpringBoot中后台无法接受前台日期字符串 yyyy-MM-dd HH:mm:ss

  • 问题描述 SpringBoot项目中当前台通过ajax传入日期字符串如:2018-10-01 00:00:00至后台 Date 字段时,部分异常信息如下:

org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not deserialize value of type java.util.Date from String "2018-10-01 00:00:00": not a valid representation (error: Failed to parse Date value '2018-10-01 00:00:00': Can not parse date "2018-10-01 00:00:00Z": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSS'Z'', parsing fails (leniency? null)) at [Source: java.io.PushbackInputStream@57e813aa; line: 1, column: 132] (through reference chain: com.shenma.romp.service.dro.CouponActivityDro["startTime"]); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not deserialize value of type java.util.Date from String "2018-10-11 00:00:00": not a valid representation (error: Failed to parse Date value '2018-10-11 00:00:00': Can not parse date "2018-10-11 00:00:00Z": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSS'Z'', parsing fails (leniency? null)) at [Source: java.io.PushbackInputStream@57e813aa; line: 1, column: 132] (through reference chain: com.shenma.romp.service.dro.CouponActivityDro["startTime"]) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:240) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:225) at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:201) at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:150) at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:128) at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:158) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)

  • 根源 从异常信息中我们可以看出,是在AbstractJackson2HttpMessageConverter类中调用了readJavaType方法之后抛的异常,最终在类DeserializationContext 中找到问题

public Date parseDate(String dateStr) throws IllegalArgumentException{ try { DateFormat df = getDateFormat(); return df.parse(dateStr); } catch (ParseException e) { throw new IllegalArgumentException(String.format("Failed to parse Date value '%s': %s", dateStr,e.getMessage())); }}

再往下 DateFormat 来源于 MapperConfig

public final DateFormat getDateFormat() { return _base.getDateFormat(); }

SpringMvc是通过AbstractJackson2HttpMessageConverter类来整合jackson的,该类维护jackson的ObjectMapper,而ObjectMapper又是通过MapperConfig来进行配置的,所有本异常就是因为ObjectMapper中的DateFormat无法对yyyy-MM-dd HH:mm:ss格式的字符串进行转换所导致的

  • 问题处理 首先我们先使用装饰模式来创建一个支持yyyy-MM-dd HH:mm:ss格式的DateFormat如下 `public class MyDateFormat extends DateFormat {

    private static final long serialVersionUID = -4580955831439573829L;

    private DateFormat dateFormat;

    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public MyDateFormat(DateFormat dateFormat) { this.dateFormat = dateFormat; }

    @Override public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { return dateFormat.format(date, toAppendTo, fieldPosition); }

    @Override public Date parse(String source, ParsePosition pos) { Date date = null; try { date = simpleDateFormat.parse(source, pos); } catch (Exception e) {

      	date = dateFormat.parse(source, pos);
      }
      return date;
    

    }

    @Override public Date parse(String source) throws ParseException { Date date = null; try { date = simpleDateFormat.parse(source); } catch (Exception e) {

      	date = dateFormat.parse(source);
      }
      return date;
    

    }

    @Override public Object clone() { Object format = dateFormat.clone(); return new MyDateFormat((DateFormat) format); }

}接下来的任务就是让ObjectMapper使用我的这个DateFormat了,在config类中定义如下@Configuration public class JacksonHttpMessageConvertersConfig {

@Autowired
private Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder;

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
	ObjectMapper mapper = jackson2ObjectMapperBuilder.build();
	
	DateFormat dateFormat = mapper.getDateFormat();
	mapper.setDateFormat(new MyDateFormat(dateFormat));
	
	MappingJackson2HttpMessageConverter mappingJsonpHttpMessageConverter = new MappingJackson2HttpMessageConverter(mapper);		
	
	return mappingJsonpHttpMessageConverter;
}

}` 配置了上述代码之后,问题成功解决。

  • 为什么往spring容器中注入MappingJackson2HttpMessageConverter,springMvc就会用这个Converter呢? 查看springboot的源代码如下 `@Configuration class JacksonHttpMessageConvertersConfiguration {

    @Configuration @ConditionalOnClass(ObjectMapper.class) @ConditionalOnBean(ObjectMapper.class) @ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "jackson", matchIfMissing = true) protected static class MappingJackson2HttpMessageConverterConfiguration {

      @Bean
      @ConditionalOnMissingBean(value = MappingJackson2HttpMessageConverter.class, ignoredType = {
      		"org.springframework.hateoas.mvc.TypeConstrainedMappingJackson2HttpMessageConverter",
      		"org.springframework.data.rest.webmvc.alps.AlpsJsonHttpMessageConverter" })
      public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(
      		ObjectMapper objectMapper) {
      	return new MappingJackson2HttpMessageConverter(objectMapper);
      }
    

    } }` 当spring容器中没有MappingJackson2HttpMessageConverter这个实例的时候才会被创建

【说明】该解决方案来源于网上资源

转载于:https://my.oschina.net/u/3694704/blog/2243415

你可能感兴趣的:(SpringBoot中后台无法接受前台日期字符串 yyyy-MM-dd HH:mm:ss)