SpirngMvc--@DateTimeFormat和@JsonFormat的区别详解

1.@DateTimeFormat注解

@DateTimeFormat注解在SpringMvc中一般是用在前端传时间格式字符串,然后后端用Date参数类型直接接收的场景。

一般是在SpringMvc的Controller层中参数前加上@RequestParam或者不加注解使用。

@DateTimeFormat一般用在实体类的字段上,或者是在Controller方法中的某个Date类型的参数前直接加。一般使用patten属性,表示接收的时间字符串格式。


例子1(注:以下例子使用的Content-type都是x-www-form-urlencoded方式):

  @RequestMapping("/test")
    public Date mytest(@DateTimeFormat(pattern ="yyyy-MM-dd HH:mm:ss") Date time1,
                        @RequestParam @DateTimeFormat(pattern ="yyyy-MM-dd HH:mm:ss")Date time2) {
        System.out.println(time1);
        System.out.println(time2);
        return time1;
    }

正常请求:
SpirngMvc--@DateTimeFormat和@JsonFormat的区别详解_第1张图片
结果(全都正常接收到,并且输出到控制台):
在这里插入图片描述

例子2:

User.java (实体类)

public class User {
    private Integer id;
    
    private String nickname;
    
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss" )
    private Date asktime;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", nickname=" + nickname +
                ", asktime=" + asktime +
                '}';
    }
	//Get和Set省略
}

Controller层方法

  @RequestMapping("/test")
    public User mytest(User user) {
        System.out.println(user.toString());
        return user;
    }

请求:
SpirngMvc--@DateTimeFormat和@JsonFormat的区别详解_第2张图片
结果(成功接收):

控制台输出结果:

在这里插入图片描述
请求返回结果:
SpirngMvc--@DateTimeFormat和@JsonFormat的区别详解_第3张图片




错误示范1(不加@DateTimeFormat注解)

	@RequestMapping("/test")
    public Date mytest( Date time1,
                        Date time2) {
        System.out.println(time1);
        System.out.println(time2);
        return time1;
    }

请求:
SpirngMvc--@DateTimeFormat和@JsonFormat的区别详解_第4张图片
结果(出错):
出现报错:Failed to convert value of type ‘java.lang.String’ to required type ‘java.util.Date’,表明不能把String转换成Date类型,也就是数据不能绑定,因为转换出错。

Tip: 如果在请求的时候,时间格式和注解中设置的不一样也会出错,因为无法转换。



错误示范2(在实体类的字段上加@JsonFromat注解替代)

实体类代码修改

   @JsonFromat(pattern = "yyyy-MM-dd HH:mm:ss" )
    private Date asktime;

请求:
SpirngMvc--@DateTimeFormat和@JsonFormat的区别详解_第5张图片
结果:

出错:Failed to convert property value of type ‘java.lang.String’ to required type ‘java.util.Date’ for property ‘asktime’,因为这时候走的不是jackson的反序列化,所以设置@JsonFormat注解并没有用。








2.@JsonFormat注解

@JsonFormat注解一般是在前端使用application/json 传递参数的时候生效,这时候在Date类型的字段上使用该注解,也能直接接收时间格式的字符串,并且转换成设置的格式。

一般是在SpringMvc的Controller层中JAVA类参数前加上@RequestBody使用,因为前端使用Content-Type是application/json 方式,所以要用@RequestBody来接收参数解析并且绑定。这时候反序列化用到的是Jackjson的反序列化,所以@JsonFormat注解生效。

@JsonFormat注解一般只用在实体类的字段上。patten的属性表示时间字符串格式,timezone属性表示时区。

正确例子(注:以下例子使用的Content-type都是application/json方式):

实体类 User.java

public class User {
    
    private Integer id;
    
    private String nickname;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" )
    private Date asktime;
    
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", nickname=" + nickname +
                ", asktime=" + asktime +
                '}';
    }
}

Controller层代码:

    @RequestMapping("/test")
    public User mytest(@RequestBody User user) {
        System.out.println(user.toString());
        return user;
    }

请求以及请求返回结果:
SpirngMvc--@DateTimeFormat和@JsonFormat的区别详解_第6张图片
控制台输出:

在这里插入图片描述




错误例子1(用@DateTimeFormat注解替换)

其他不变,User实体类的asktime字段注解改变:

   @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss" )
    private Date asktime;

请求:

SpirngMvc--@DateTimeFormat和@JsonFormat的区别详解_第7张图片

结果:

报错:Cannot deserialize value of type java.util.Date from String “2005-2-5 11:22:33”: 说明这时候没有设置时间格式的反序列化,导致出错。



错误例子2(不加@JsonFormat注解)

也只改变User实体中的代码

    private Date asktime;

请求:
SpirngMvc--@DateTimeFormat和@JsonFormat的区别详解_第8张图片
结果同上








3.简单说明两个注解原理

@JsonFormat注解生效情况:
接口请求的时候 SpringMvc会根据参数前的注解或者无注解时根据参数的类型选择对应的HandlerMethodArgumentResolver 来处理参数。
在选择的对应的HandlerMethodArgumentResolver后会进行参数解析绑定,也就是先把参数解析成一串字符串,然后从String转换成各个需要的参数类型。
在处理Json格式的数据的时候,使用@JsonFormat注解有用,是因为这时候配套使用的注解是@RequestBody(前端的Content-type一般为application/json),所以这时候HandlerMethodArgumentResolver为RequestResponseBodyMethodProcessor。
然后在这里参数的解析使用的是jackson的序列化以及反序列化,由于@JsonFormat注解的设置,在Json反序列化的时候,会把时间的String字符串转换成Date类型。
@DateTimeFormat注解生效情况:
在不处理Json格式的字符串的时候,也就是加注解@RequestParam或者不加注解的时候,因为这时候的前端请求的Content-type为x-www-form-urlencoded方式或是表单提交方式或者是GET方式。
因此采取了其他的HandlerMethodArgumentResolver来实现参数解析然后绑定(视具体情况,这里分不同的HandlerMethodArgumentResolver),在这时候转换的过程使用@DateFormat注解可以生效。
参数解析绑定时,用的就不再是Jackson的反序列化解析了,这时候解析出来的参数也是一串字符串,只不过是键值对然后用&拼接的,然后通过类型转换器把字符串转换成相应的数据类型。
因为@DateFormat注解相当于声明了一个String转Date的转换方法,然后在遇到要转Date数据时,就会调用这个类型转换方法从而实现String转换成Date。

拓展: 在SpringMvc中,返回数据的时候,一般都是对象或者其他Map,List类型的数据,这时候
SpringMvc的HttpMessageConvert会自动转换成Json格式的数据输出,所以这时候JSON的序列化配置会生效,因此@JsonFormat注解依然生效,会再序列化成指定的时间格式字符串。

在Springboot中也可以配置全局统一的时间格式配置,如下配置的时间格式就是yyyy-MM-dd HH:mm:ss(如果不配置会使用默认的yyyy-MM-ddTHH:mm:ss.000Z格式):

spring:
    jackson:
        date-format: yyyy-MM-dd HH:mm:ss
        time-zone: GMT+8

Tip: 我看网上很多人说这两个的区别是:@JsonFormat用来返回给前端的,@DateTimeFormat用来从前端接收Date的。这是不正确的,@JsonFormat也能从前端接收Date,只不过需要前端传递JSON格式的数据,并且Content-Type需要为application/json,让SpringMvc辨识数据为JSON格式,从而让SpringMvc走jackson的序列化和反序列化。

你可能感兴趣的:(SpringMvc,java,spring,json,spring,boot,后端)