美文网首页
SpringMVC如何正确接收时间

SpringMVC如何正确接收时间

作者: 土豆肉丝盖浇饭 | 来源:发表于2020-11-29 20:32 被阅读0次

    前言

    一般我们对前端提供的http接口为以下三种方式

    • GET请求
    • POST请求,表单提交
    • POST请求,JSON提交

    从SpringMVC的处理来看

    第一种方式通过@RequestParam或者@PathVariable来接收
    第二种方式通过@RequestParam来接收
    第三种方式通过@RequestBody来接收

    为什么第一二种方式都可以使用@RequestParam来接收参数??

    因为这两种方式,在sevlet规范中,都是通过getParameter方法获取对应的参数

    截屏2020-11-29 下午7.00.17.png截屏2020-11-29 下午7.00.17.png

    重点! For HTTP servlets, parameters are contained in the query string or posted form data.

    对于springmvc,更精确的来讲

    @RequestParam对应RequestParamMethodArgumentResolver处理器
    @PathVariable对应PathVariableMethodArgumentResolver处理器
    @RequestBody对应RequestResponseBodyMethodProcessor处理器

    这些处理器主要逻辑为,提取参数,转换参数。

    针对@RequestParam和@PathVariable提取到的参数都是String字符串,因此使用到了Spring的转换服务
    ConversionService进行转换,最终调用到DateFormatter这个类。

    对于RequestBody,提取到的参数也是String字符串,不过这个字符串是Json类型的,因此使用到了HttpMessageConverter。

    在SpringBoot中针对Json的转换,默认使用了MappingJackson2HttpMessageConverter。

    使用

    通过@RequestParam接收

    GET请求

    @GetMapping("/dateFromRequestParam")
    public String dateFromRequestParam(@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date date){
      return SIMPLE_DATE_FORMAT.format(date);
    }
    

    测试代码

    curl http://localhost:8080/dateFromRequestParam\?date\=2020-10-10%2010:10:10
    

    POST请求+表单提交

    @PostMapping("/dateFromRequestParam")
    public String dateFromRequestParam2(@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date date){
      return SIMPLE_DATE_FORMAT.format(date);
    }
    

    测试代码

    curl -X POST  http://localhost:8080/dateFromRequestParam -d 'date=2020-10-12 10:10:10'
    

    通过@RequestParam方式接受参数的时候,这个注解也是可以省略的,如果你要控制一个参数必传的话,请加上这个注解

    通过@PathVariable接受

    @GetMapping("/dateFromPathVariable/{date}")
    public String dateFromPathVariable(@PathVariable("date") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date date){
        return SIMPLE_DATE_FORMAT.format(date);
    }
    

    测试代码

    curl http://localhost:8080/dateFromPathVariable/2020-10-10%2010:10:10
    

    通过@RequestBody接收

    POST请求+JSON提交

    @PostMapping("/dateFromJson")
    public String dateFromJson(@RequestBody Input param){
      return SIMPLE_DATE_FORMAT.format(param.getDate());
    }
    
    @Data
    public static class Input{
    
      @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
      private Date date;
    
    }
    

    代码

     curl -X POST -H 'Content-Type: application/json' http://localhost:8080/dateFromJson -d '{"date":"2020-10-12 10:10:10"}'
    

    时区问题

    使用Date类型接受时间字符串十分简单,最麻烦的问题的时差问题。

    明明前端给了你10点钟,为什么变成了18点钟。

    因为上述两种方式对于时区的处理是不一样的,针对@RequestBod,他底层使用了Jackson,因为Jackson默认的时区配置为UTC,也就是0时区。

    截屏2020-11-29 下午7.42.26.png截屏2020-11-29 下午7.42.26.png

    因此你通过0时区接受了时间2020-10-10 10:00:00 , 而在保存数据库,或者你输出的时候,使用的都是我们当前机器所在的时区,也就是东8区,因此会加8个小时。

    因此针对jackson框架,我们需要指定为东八区,

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    

    而对于@RequestParam这种由spring内置转换器处理的时间,底层使用的是SimpleDateFormat,默认使用的操作系统的时区,所以我们无需对时区进行配置。

    @DateTimeFormat的错误使用

    在我们的业务代码中,我发现了一些以下的错误代码

    比如

    @Data
    public static class Input{
    
        @DateTimeFormat(pattern = "yyyy-MM-dd")
        private Date date;
    
    }
    

    用它来接收前端传过来的{"date":"2020:10:10"}

    拜托,@DateTimeFormat是spring的注解,针对Jackson根本不会失效

    只因为Jackson默认的反序列化支持2种格式的时间字符串,yyyy-MM-ddyyyy-MM-dd'T'HH:mm:ss.SSSZ

    并且时区上也是存在问题的。

    只不过因为刚好你的业务代码是忽略后面的Time,你才逃过一劫。

    参考

    https://www.jianshu.com/p/307ad48978d6

    相关文章

      网友评论

          本文标题:SpringMVC如何正确接收时间

          本文链接:https://www.haomeiwen.com/subject/hmakwktx.html