RESTful开发时经常会遇到参数传入日期类型及返回的日期类型值,日期和时间戳如果没有适当和一致地处理,就会给人带来头痛的问题,我这里建议大家使用统一格式化的时间字符串yyyy-MM-dd HH:mm:ss,为什么建议这个呢?这样看起来比较直观,前后端联调起来比较高效。
下面我们就细说一下日期类型的参数将如何处理。
GET方法时参数传入日期类型该如何处理 url如下:
1 http ://localhost:8081 /test/time_get?time=2018 -07 -09  10 :38 :57 
 
Controller代码:
1 2 3 4 5 6 7 8 import  java.util.Date;     @RequestMapping(value = "/time_get", method = RequestMethod.GET)   @ResponseBody   public  Response<Date> time_get (Date time)  {      logger.info("time:{}" , time);       return  Response.createResponse(time);   }   
 
在这种情况下日期参数是无法成功的传入到controller方法里,会爆出如下的异常:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 org.springframework.core.convert.ConversionFailedException: Failed to  convert from type  java.lang.String to  type  java.util.Date for  value '2018 -07 -09  10 :38 :57 '; nested exception  is java.lang.IllegalArgumentException   at org.springframework.core.convert.support.ObjectToObjectConverter . convert(ObjectToObjectConverter . java:81 ) ~[spring -core -4.0 .0. RELEASE.jar :4.0 .0. RELEASE]     at org.springframework.core.convert.support.ConversionUtils . invokeConverter(ConversionUtils.java :35)  ~[spring -core -4.0 .0. RELEASE.jar :4.0 .0. RELEASE]     at org.springframework.core.convert.support.GenericConversionService . convert(GenericConversionService . java:178 ) ~[spring -core -4.0 .0. RELEASE.jar :4.0 .0. RELEASE]     at org.springframework.beans.TypeConverterDelegate . convertIfNecessary(TypeConverterDelegate.java :161)  ~[spring -beans -4.0 .0. RELEASE.jar :4.0 .0. RELEASE]     at org.springframework.beans.TypeConverterDelegate . convertIfNecessary(TypeConverterDelegate.java :93)  ~[spring -beans -4.0 .0. RELEASE.jar :4.0 .0. RELEASE]     at org.springframework.beans.TypeConverterSupport .do Convert(TypeConverterSupport.java :64)  ~[spring -beans -4.0 .0. RELEASE.jar :4.0 .0. RELEASE]      ...  43  common frames omitted  Caused by: java.lang.IllegalArgumentException: null    at java.util.Date . parse(Date . java:615 ) ~[na :1.7 .0_45 ]     at java.util.Date.<init>(Date . java:272 ) ~[na :1.7 .0_45 ]     at sun.reflect.NativeConstructorAccessorImpl .new Instance0(Native Method)  ~[na :1.7 .0_45 ]     at sun.reflect.NativeConstructorAccessorImpl .new Instance(NativeConstructorAccessorImpl.java :57)  ~[na :1.7 .0_45 ]     at sun.reflect.DelegatingConstructorAccessorImpl .new Instance(DelegatingConstructorAccessorImpl.java :45)  ~[na :1.7 .0_45 ]     at java.lang.reflect.Constructor .new Instance(Constructor.java :526)  ~[na :1.7 .0_45 ]     at org.springframework.core.convert.support.ObjectToObjectConverter . convert(ObjectToObjectConverter . java:76 ) ~[spring -core -4.0 .0. RELEASE.jar :4.0 .0. RELEASE]      ...  48  common frames omitted  
 
那如何解决上面的问题?使用@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")加到日期参数之前,像下面那样使用一样。
Controller代码:
1 2 3 4 5 6 7 8 import  java.util.Date;       @RequestMapping(value = "/time_get", method = RequestMethod.GET)   @ResponseBody   public  Response<Date> time_get (@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")  Date time)  {      logger.info("time:{}" , time);       return  Response.createResponse(time);   }  
 
提示:年月日:pattern=”yyyy-MM-dd”,年月日时分秒:pattern=”yyyy-MM-dd HH:mm:ss”
 
请求体:
1 2 GET  /test/time_get1?time=2018 -07 -09  11 :31 :00  HTTP/1 .1   Host : localhost:8081 
 
后端接收到的信息,debug截图:
POST方法时参数传入日期类型该如何处理 当使用@RequestBody接受一个VO对象时@DateTimeFormat就会失效,因为我们走的是Json序列化与反序列化,@DateTimeFormat只会生效与object序列化、反序列化。
前端String转后端Date有两种方法:
方法一:自定义converter 如果使用的Spring可以自定义messageConvert或者增强MappingJackson2HttpMessageConverter中的ObjectMapper
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import  java.text.SimpleDateFormat;  import  java.util.ArrayList;  import  java.util.List;     import  org.springframework.context.annotation.Bean;  import  org.springframework.context.annotation.Configuration;  import  org.springframework.http.converter.HttpMessageConverter;  import  org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;  import  org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;  import  org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;     import  com.fasterxml.jackson.databind.DeserializationFeature;  import  com.fasterxml.jackson.databind.ObjectMapper;     @Configuration   public  class  WebConfig  extends  WebMvcConfigurationSupport  {      @Override        protected  void  configureMessageConverters (List<HttpMessageConverter<?>> converters)  {           List<HttpMessageConverter<?>> messageConverters = new  ArrayList <HttpMessageConverter<?>>();           addDefaultHttpMessageConverters(messageConverters);           for  (int  i  =  0 ; i < messageConverters.size(); i++) {               HttpMessageConverter<?> mc = messageConverters.get(i);               if  (mc instanceof  MappingJackson2HttpMessageConverter) {                   ObjectMapper  objectMapper  =  new  ObjectMapper ();                                    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );                                    objectMapper.setDateFormat(new  SimpleDateFormat ("yyyy-MM-dd HH:mm:ss" ));                   ((MappingJackson2HttpMessageConverter) mc).setObjectMapper(objectMapper);               }               converters.add(mc);           }       }   }  
 
通过上面对json序列化反序列化的配置后日期参数处理就变的简单了,效果如下。
Controller代码:
1 2 3 4 5 6 @RequestMapping(value = "/time_post", method = RequestMethod.POST)   @ResponseBody   public  Response<Date> time_post (@RequestBody  TestVo vo)  {      logger.info("time:{}" , vo.getTime());       return  Response.createResponse(vo.getTime());   }   
 
VO代码:
1 2 3 4 5 6 7 8 9 10 public  class  TestVo  implements  Serializable  {      private  static  final  long  serialVersionUID  =  7435595656552442126L ;       private  Date time;       public  Date getTime ()  {           return  time;       }       public  void  setTime (Date time)  {           this .time = time;       }   }  
 
提示:VO中无需使用@DateTimeFormat,就是一个普通的javabean即可
 
请求体:
1 2 3 4 5 6 POST  /test /time_post HTTP/1.1  Host: localhost:8081   Content-Type : application/json   {       "time" :"2018-07-09 15:31:00"    }  
 
后端接收到的信息,debug截图
1 2 3 4 5 6 7 8 9 10 11 public  class  TestVo  implements  Serializable  {      private  static  final  long  serialVersionUID  =  7435595656552442126L ;       @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")      private  Date time;       public  Date getTime ()  {           return  time;       }       public  void  setTime (Date time)  {           this .time = time;       }   }  
 
注意:使用Jackson进行json序列化反序列化,默认可以处理yyyy-MM-dd这个格式,但是反序列化后的时间会差8小时
 
可在SpringBoot中全局配置:
1 2 3 jackson:     date-format:  yyyy-MM-dd  HH:mm:ss      time-zone:  GMT+8  
 
@JsonFormat无效的原因及解决方案: 1.首先更新@JsonFormat所依赖的jar包版本,旧版本不支持对LocalDateTime类型的序列化,所以会出现不生效的问题,所以先更新版本,如果不解决,就不是这个问题 2.看是否有接口重写了FastJsonHttpMessageConverter产生了冲突
 
PUT方法时参数传入日期类型该如何处理 如果put传参方式与get一样在方法上直接传参(url?time=2018-07-09 10:38:57),那参考get请求参数处理方式即可
如果put传参方式与post一样使用@RequestBody传入json格式数据,那么参考post请求参数处理方式即可
请求体:
1 2 3 4 5 6 PUT /test/ time_put HTTP/1.1    Host: localhost:8081    Content-Type: application/json   {       "time" :"2018-07-09 15:31:00"    } 
 
后端接收到的信息,debug截图
前面都说的是request时日期格式处理方式,那么我们继续说一下response时日期格式如何处理。
Response中日期格式该如何处理 SpringMVC使用@ResponseBody时,日期格式默认显示为时间戳,不管方法直接返回Date类型、或者VO类型时,时间格式都一样返回时间戳,例如这样。
请求体:
1 2 3 4 5 6 POST  /test /time_post1 HTTP/1.1  Host: localhost:8081   Content-Type : application/json   {       "time" :"2018-07-09"    }   
 
响应体:
1 2 3 4 5 6 7 {       "code ": "" ,       "message" : "" ,       "items" : {           "time ": 1531094400000        }   }   
 
那如果我们要以字符串格式返回呢,那该如何处理?
方法一 增加统一的messageConvert处理: 如果使用的spring可以自定义messageConvert或者增强MappingJackson2HttpMessageConverter中的ObjectMapper
代码在 POST方法时参数传入日期类型该如何处理 这个章节
请在VO对象的date字段上加上@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8"),例如下面代码:
VO代码:
1 2 3 4 5 6 7 8 9 10 11 12 public  class  TestVo  implements  Serializable  {   private  static  final  long  serialVersionUID  =  7435595656552442126L ;                @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")        private  Date time;       public  Date getTime ()  {           return  time;       }       public  void  setTime (Date time)  {           this .time = time;       }   }  
 
注意:@JsonFormat(pattern=”yyyy-MM-dd HH:mm:ss”,timezone = “GMT+8”) ,即可将json返回的对象为指定的类型。
 
返回日期格式使用的是”yyyy-MM-dd HH:mm:ss”样式字符串示例:
请求体:
1 2 3 4 5 6 POST  /test /time_post1 HTTP/1.1  Host: localhost:8081   Content-Type : application/json   {       "time" :"2018-07-09 15:31:00"    }   
 
响应体:
1 2 3 4 5 6 7 {       "code ": "" ,       "message" : "" ,       "items" : {           "time ": "2018-07-09 15:31:00"        }   }   
 
总结 POST 请求,我们一般会用@RequestBody接收JSON对象,如果对象里面有日期时间类型数据的话,我们可以使用 @JsonFormat  注解进行格式化,它既可以对出参进行格式化,也可以对入参进行格式化
GET 请求参数都是拼接在URL后面的,则需要使用 @DateTimeFormat  对入参进行格式化,放到@RequestBody修饰的对象里面是无效的