DateTimeFormat

@DateTimeFormat和@JsonFormat

1.@DateTimeFormat注解

1.1@DateTimeFormat注解简介

@DateTimeFormat注解是由Spring提供的一个注解,位于Spring和核心组件之一的context组件。对应的所需依赖如下:

1
2
3
4
5
6
7
8
9
10
11
12
# SpringBoot对应的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

# Spring对应的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>

1.2@DateTimeFormat注解的功能

@DateTimeFormat注解的功能是将一个日期字符串转化为对应的Date类型,主要处理前端时间类型与后端pojo对象中的成员变量进行数据绑定,在注解属性patttern中所约束的时间格式并不会影响后端返回前端的时间类型数据格式。

DateTimeFormat接口的pattern属性:

pattern属性类型为String类型,用于格式化字段或方法参数的自定义模式。默认为空字符串,表示没有指定自定义模式字符串。

当然也可以使用自定义日期模式字符串,如yyyy-MM-dd HH:mm:ss

1.3@DateTimeFormat注解的注意点

  • @DateTimeFormat注解既可以作用于pojo类型的属性上,也可以作用于方法参数上。

  • 前端传入的时间类型的字符串要和pattern属性所规定的规则相同。

  • @DateTimeFormat注解只能处理非JSON数据格式的字符串(如url-String格式、Form-Data格式),如果要处理JSON数据格式,就需要采用@RequestBody注解,@RequestBody就是获取请求体中的内容(即JSON字符串),再通过JSON解析库(如Jackson、FastJosn)将JSON字符串转换为pojo对象。fastjson所需依赖:com.alibaba:fastjson:1.2.54,Jackson由于是Spring提供的,所以它所需的依赖就在Spring依赖中。

  • @DateTimeFormat注解只是解析日期字符串转为Date类型,转换后的日期格式并不会受到@DateTimeFormat注解中pattern属性的约束。

  • GET的url、POST的form,这两种入参方式与使用@RequestBody标注的JSON入参是不一样的。

  • 不使用这个注解的话,无法将String类型的入参转换为Date类型

  • @DateTimeFormat注解只是解析日期字符串转为Date类型,转换后的日期格式并不会受到@DateTimeFormat注解中pattern属性的约束

  • @DateTimeFormat注解既可以作用于pojo类型的属性上,也可以作用于方法参数上(get/set都行)。

  • 前端传入的时间类型的字符串要和pattern属性所规定的规则相同。

  • @DateTimeFormat注解只能处理的数据类型有:

    • url-String格式
    • Form-Data格式
    • 这两种入参的方式也需要按照注解中的pattern样式进行传参
  • 如果要处理JSON数据格式,controller接口中标注@RequestBody注解,此时@DateTimeFormat这个注解的作用是失效的。且这个参数可以接受的参数形式必须为:2012-03-12T12:11:55.222+00:00,(秒参数及秒之后的参数可以省略,年月日时分不可以省略)。除此格式之外的其他格式均会报错(无论@DateTimeFormat注解限定的pattern是什么,也就是:这个注解的作用失效了)

1.4@DateTimeFormat功能演示

1.4.1类型转换异常情况测试

  1. pojo层

    1
    2
    3
    4
    5
    6
    7
    8
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public class User {
    private String username;
    private Date birthday;
    }
  2. controller层

    1
    2
    3
    4
    5
    @GetMapping("getUrl")
    public User getUrl(User user){
    log.info( "用户信息是:" + user);
    return user;
    }
  3. 用ApiFox进行接口测试,传输的数据格式为url路径传参

    image-20230628111106598

请求400,查看控制台日志信息

报错信息:即String类型转换为Date类型失败

Failed to convert property value of type ‘java.lang.String’ to required type ‘java.util.Date’ for property ‘birthday’; nested exception is org.springframework.core.convert

1.4.2接收url路径传参格式测试

  1. pojo层
1
2
3
4
5
6
7
8
9
10
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
private String username;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date birthday;
}

  1. 传输的数据格式为url路径传参

查看响应情况和控制台输出情况:可以发现@DateTimeFormat注解对日期字符串进行了解析,转换为对应的Date类型

但是要注意:@DateTimeFormat注解只是解析日期字符串转为Date类型,转换后的日期格式并不会受到@DateTimeFormat注解中pattern属性的约束

img

响应的JSON字符串数据如下:

image-20221101094616306

1.4.3接收Form-Data数据格式测试

  1. pojo和controller都不变
  2. 用ApiFox进行接口测试,传输的数据格式为Form-Data类型

image-20230628111350009

  1. 测试结果:

image-20221101100453834

响应的JSON字符串数据如下:

1
2
3
4
{
"username": "zhangsan",
"birthday": "2012-03-03T04:23:23.000+00:00"
}

1.4.4接收JSON数据格式测试

  1. pojo不变

  2. controller

1
2
3
4
5
@PostMapping("postJson")
public User postJson(@RequestBody User user){
log.info( "用户信息是:" + user);
return user;
}
  1. apipost-正常响应

image-20230628111912816

  1. 异常响应(即使按照@DataTimeFormat的样式)

image-20230628111954283

1.4.5接收JSON数据格式测试-fastjson

  1. pojo层不变

  2. controller层

    1
    2
    3
    4
    5
    6
    @PostMapping("postJsonHandleFastJson")
    public User postJsonHandleFastJson(@RequestBody String userString){
    log.info( "用户信息是:" + userString);
    User user = JSONObject.parseObject(userString, User.class);
    return user;
    }

    fastjson默认使用的序列化格式就是:DEFFAULT_DATE_FORMAT = “yyyy-MM-dd HH:mm:ss”;

1.4.6接收JSON数据格式测试-jackson

1.controller

1
2
3
4
5
6
7
@PostMapping("postJsonHandleObjectMapper")
public User postJsonHandleObjectMapper(@RequestBody String userString) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
log.info( "用户信息是:" + userString);
User user = objectMapper.readValue(userString, User.class);
return user;
}

2.正常响应

image-20230628120028326

3.错误响应

控制台报错,错误信息提示反序列化失败,因为jackson默认的日期反序列不支持yyyy-MM-dd HH:mm:ss 这种格式,而是默认"yyyy-MM-dd’T’HH:mm:ss.SSSX",所以反序列化失败。

image-20230628120042140

2.@JsonFormat注解

2.1@JsonFormat注解简介

@JsonFormat注解是由Jackson提供的一个注解,@JsonFormat注解的功能是处理请求中的JSON日期字符串和查询数据库中的日期类型。即可约束时间类型的请求格式和响应格式。

2.3@JsonFormat注解的注意点

  • @JsonFormat只能作用在实体类上,不能作用于方法参数上。
  • @JsonFormat会根据pattrn属性约束日期格式,在返回数据时会返回约束日期格式,这点和@DateTimeFormat不同
  • @JsonFormat注解当需要处理前端传来的数据时,先通过@RequestBody将入参参数映射到实体后,@JsonFormat注解才能去对时间格式进行约束;

2.4@JsonFormat功能演示

2.4.1处理前端传递的日期字符串

  1. pojo层
1
2
3
4
5
6
7
8
9
10
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
private String username;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date birthday;
}

  1. controller层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Slf4j
@RestController
@RequestMapping("/datetimeFormatTest")
public class DatetimeFormatTest {

@GetMapping("/exception")
public User dft1(@RequestBody String userMsg) {
ObjectMapper objectMapper = new ObjectMapper();
User user = null;
try {
user = objectMapper.readValue(userMsg, User.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
log.info("用户信息是:" + user);
return user;
}
}

  1. 测试结果:

image-20230628131314878

2.4.2处理查询数据库中的datatime类型格式

  1. 数据库中的数据格式为datatime类型

    image-20221105184232640

  2. 先测试不添加@JsonFormat注解时的情况,发送请求,查询数据库,查看响应的JSON数据

image-20230628131355668

  1. 添加@JsonFormat注解再次进行测试

image-20221105184553662

总结

  • 当处理的数据格式为非JSON格式(url路径传参、Form-Data)的时候适合使用@DateTimeFormat注解进行处理,就是格式化后的日期格式并不会按照属性pattern中所约束的格式响应,如果想要规定日期格式,可采用SimpleDateFormat对象进行处理。
  • 当处理的数据格式为JSON数据格式时适合使用@JsonFormat注解进行处理,如果是前端返回的JSON日期字符串,需要使用@RequestBody注解获取请求体中的JSON字符串,再通过JSON解析库将JSON字符串转换为对应的POJO类型。或者是从数据库中查出对应的DateTime类型时对类型进行转换。

参考链接

@DateTimeFormat和@JsonFormat介绍_jsonformat和datetimeformat