• Spring @DateTimeFormat日期格式化时注解浅析分享


    总结写前面

    关于它 @DateTimeFormat

    1. 可以接收解析前端传入字符时间数据;
    2. 不能格式化接收的字符时间类型数据,需要的转换格式得配置;
    3. 入参格式必须与后端注解格式保持一致,否则会报错;

    为什么用

    场景:跟前端交互时,接收字符类型的时间值,就需要使用 @DateTimeFormat 注解来解析,否则就会报错;

    @RestController
    @RequestMapping("/demo")
    public class DemoTestController {
        @PostMapping("/testOne")
        public DemoTest testOne(DemoTest demoTest){
            return demoTest;
        }
    }
    
    @Data
    public class DemoTest {
        private Date nowTime;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    请求示例结果:

    Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors<EOL>Field error in object 'demoTest' on field 'nowTime': rejected value [2022-11-20 16:42:26,2022-11-20 16:42:01]; codes [typeMismatch.demoTest.nowTime,typeMismatch.nowTime,typeMismatch.java.util.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [demoTest.nowTime,nowTime]; arguments []; default message [nowTime]]; default message [Failed to convert property value of type 'java.lang.String[]' to required type 'java.util.Date' for property 'nowTime'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.util.Date] for value '2022-11-20 16:42:26'; nested exception is java.lang.IllegalArgumentException]]
    
    • 1

    怎么用

    场景一

    接收非 JSON 格式请求参数。

    @RestController
    @RequestMapping("/demo")
    public class DemoTestController {
         @PostMapping("/testOne")
        public DemoTest testOne(DemoTest demoTest){
            return demoTest;
        }
    }
    
    @Data
    public class DemoTest {
        @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private Date nowTime;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    请求示例结果:

    从结果可以看出,@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 可以保证接收解析前端传入的字符时间参数,但是并不能完成时间格式化操作,如果需要获取想要的时间格式,是需要自己手动转换的。

    场景二

    接收 JSON 格式请求数据,与场景一的区别是请求的数据格式:

    • 场景一:form-data
    • 场景二:JSON
    @RestController
    @RequestMapping("/demo")
    public class DemoTestController {
        @PostMapping("/testTwo")
        public DemoTest testTwo(DemoTest demoTest){
            return demoTest;
        }
    }
    
    @Data
    public class DemoTest {
        @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private Date nowTime;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    请求示例结果:

    • 请求:POST

    • 数据格式:JSON
      在这里插入图片描述

    从结果可以看出,返回数据 nowTime 是空的,因为这里的Controller层没有使用 @RequestBody 去接收 JSON 格式的数据,而 Spring 默认的转换器类型是不包含 JSON 的(有兴趣的可以看下 org.springframework.core.convert.support 包,这里面包含Spring支持的默认转换器)。

    场景三

    场景三跟场景二的区别就是,在 Controller 层方法入参配合使用 @RequestBody 去接收 JSON 格式,使用该注解会自动调用对应的JSON转换器。

    @RestController
    @RequestMapping("/demo")
    public class DemoTestController {
        @PostMapping("/testThree")
        public DemoTest testThree(@RequestBody DemoTest demoTest){
            return demoTest;
        }
    }
    
    @Data
    public class DemoTest {
        @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private Date nowTime;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    请求示例结果:

    • 请求:POST

    • 数据格式:JSON在这里插入图片描述

    这里可以看到,请求报错400,导致400的原因比较多,这里只说明一下场景三,场景三中使用 @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 注解格式与请求入参格式不一致,所以会导致请求报错;

    在这里插入图片描述

    大概意思就是说,Spring 框架在尝试转换参数的过程中,没有找到合适接收格式导致转换失败。(注意!注意!注意!讲三遍,所以前端入参格式必须与后端约定格式保持一致,否则会报错)。

    场景四

    场景四的目的是为了解决场景一中时间格式化的问题。

    关于 @JsonFormat 注解,可以看看我的另一篇blog中有做分享,感兴趣的大佬可以去看看,附上传送门:@JsonFormat 和 @DateTimeFormat 时间格式化注解详解(不看血亏)

    @RestController
    @RequestMapping("/demo")
    public class DemoTestController {
        @PostMapping("/testThree")
        public DemoTest testThree(@RequestBody DemoTest demoTest){
            return demoTest;
        }
    }
    
    @Data
    public class DemoTest {
        @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
        @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private Date nowTime;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    请求示例结果:

    • 请求:POST

    • 数据格式:form-data在这里插入图片描述

    场景五

    方式一

    针对场景四的数据请求格式是 form-data,场景五来说明 JSON 同样适用。

    @RestController
    @RequestMapping("/demo")
    public class DemoTestController {
        @PostMapping("/testThree")
        public DemoTest testThree(@RequestBody DemoTest demoTest){
            return demoTest;
        }
    }
    
    @Data
    public class DemoTest {
        @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
        @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private Date nowTime;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    请求示例结果:

    • 请求:POST

    • 数据格式:JSON
      在这里插入图片描述

    方式二

    可以继承 Spring 提供的org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer 来进行全局配置。

    @RestController
    @RequestMapping("/demo")
    public class DemoTestController {
        @PostMapping("/testThree")
        public DemoTest testThree(@RequestBody DemoTest demoTest){
            return demoTest;
        }
    }
    
    @Data
    public class DemoTest {
        @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private Date nowTime;
    }
    
    @Configuration
    public class CustomsDateConvert implements Jackson2ObjectMapperBuilderCustomizer {
        @Override
        public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
            String dateFormat = "yyyy-MM-dd HH";
            // 针对于Date类型,文本格式化
            jacksonObjectMapperBuilder.simpleDateFormat(dateFormat);
            // 针对于JDK新时间类。序列化时带有T的问题,自定义格式化字符串
            JavaTimeModule javaTimeModule = new JavaTimeModule();
            javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateFormat)));
            javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(dateFormat)));
            jacksonObjectMapperBuilder.modules(javaTimeModule);
        }
    }
    
    /**
     * 解决Jackson2ObjectMapperBuilderCustomizer失效问题
     */
    @Configuration
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
    public class ConvertConfiguration implements WebMvcConfigurer {
    
        @Autowired(required = false)
        private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter;
    
        @Override
        public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
            converters.removeIf(converter -> converter instanceof MappingJackson2HttpMessageConverter);
            if (Objects.isNull(mappingJackson2HttpMessageConverter)) {
                converters.add(0, new MappingJackson2HttpMessageConverter());
            } else {
                converters.add(0, mappingJackson2HttpMessageConverter);
            }
    
        }
    }
    
    • 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
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    请求示例结果:

    • 请求:POST

    • 数据格式:JSON
      在这里插入图片描述


    感 谢 各 位 大 佬 的 阅 读,随 手 点 赞,日 薪 过 万~! !!
  • 相关阅读:
    力扣 895. 最大频率栈
    7-sqlalchemy快速使用和原生操作、对象映射类型和增删查改、增加和基于对象的跨表查询、scoped线程安全、g对象、基本增查改和高级查询
    计算机网络(自顶向下方法)-应用层
    调用接口数据是富文本,改变图片大小
    处理问题,心态崩了?论一个程序员的基本素养
    食品行业报告:豆粕市场现状研究分析与发展前景预测
    VirtualBox(内有Centos 7 示例安装)
    LiveCharts.Wpf 的使用
    网络信号最好的坐标 (暴力leetcode1620)-------------------c++实现
    (七)Alian 的 Spring Cloud Config 配置中心(客户端)
  • 原文地址:https://blog.csdn.net/zhuzicc/article/details/127956849