SpringBoot如何优雅的接收日期类型

接受入参的实体

@Data
public class UserVO {

    /**
     * 姓名
     */
    private String userName;

    /**
     * 生日
     */
    private Date birthday;
}

Controller方法

@PostMapping("/receiveUserVo")
    public UserVO receiveUserVO(@RequestBody UserVO userVO){
        System.out.println(userVO.getUserName());
        System.out.println(userVO.getBirthday());
        userVO.setBirthday(new Date());
        return userVO;
    }

调试一

  • 采用postman测试接口,使用wireShark查看报文信息如下:可知日期解析失败。

    POST /api/test/receiveUserVo HTTP/1.1
    Content-Type: application/json
    User-Agent: PostmanRuntime/7.17.1
    Accept: */*
    Cache-Control: no-cache
    Postman-Token: c1f02977-0435-4dbb-8db9-f2ac4c16cee0
    Host: localhost:8888
    Accept-Encoding: gzip, deflate
    Content-Length: 59
    Cookie: JSESSIONID=41A840ADD2AA4F9186D82E4A177BF7A8
    Connection: keep-alive
    
    {
    	"userName" : "hk",
    	"birthday" : "2018-02-12 23:23:23"
    }HTTP/1.1 400 
    Content-Type: application/json;charset=UTF-8
    Transfer-Encoding: chunked
    Date: Sat, 12 Oct 2019 07:45:03 GMT
    Connection: close
    
    {"timestamp":1570866303815,"status":400,"error":"Bad Request","message":"JSON parse error: Cannot deserialize value of type `java.util.Date` from String \"2018-02-12 23:23:23\": not a valid representation (error: Failed to parse Date value '2018-02-12 23:23:23': Cannot parse date \"2018-02-12 23:23:23\": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSZ', parsing fails (leniency? null)); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.util.Date` from String \"2018-02-12 23:23:23\": not a valid representation (error: Failed to parse Date value '2018-02-12 23:23:23': Cannot parse date \"2018-02-12 23:23:23\": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSZ', parsing fails (leniency? null))\n at [Source: (PushbackInputStream); line: 3, column: 15] (through reference chain: cn.haoeasy.test.vo.UserVO[\"birthday\"])","path":"/api/test/receiveUserVo"}
    

解决方式

  • 在日期类型上添加@JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”)

    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date birthday;
    
  • 备注

    对于转换前端传过来的时间,@JsonFormat只适合 Content-Type 为application/json的请求,如果是表单请求,请采用@DateTimeFormat

调试二

  • 采用postman测试接口。报文信息如下:

    POST /api/test/receiveUserVo HTTP/1.1
    Content-Type: application/json
    User-Agent: PostmanRuntime/7.17.1
    Accept: */*
    Cache-Control: no-cache
    Postman-Token: c8b02d59-f79f-4ae0-9692-b1d4194ae1a4
    Host: localhost:8888
    Accept-Encoding: gzip, deflate
    Content-Length: 59
    Cookie: JSESSIONID=41A840ADD2AA4F9186D82E4A177BF7A8
    Connection: keep-alive
    
    {
    	"userName" : "hk",
    	"birthday" : "2018-02-12 23:23:23"
    }HTTP/1.1 200 
    Content-Type: application/json;charset=UTF-8
    Transfer-Encoding: chunked
    Date: Sat, 12 Oct 2019 07:51:37 GMT
    
    {"userName":"hk","birthday":"2018-02-12 23:23:23"}
    
  • 控制台输出如下:

    hk
    Tue Feb 13 07:23:23 CST 2018
    
  • 问题

    从postman测试返回的报文中我们可以看到,返回正常。

    从控制台输出,我们可以看到,日期存在异常。日期异常的产生原因主要是:@JsonFormat 默认的时区是Greenwich Time, 默认的是格林威治时间,而我们是在东八区上,所以时间会比实际我们想得到的时间少八个小时。可以在@JsonFormat中带上时区,如下:

    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
        private Date birthday;
    
  • 说明

    @JsonFormat注解是一个时间格式化注解,比如我们存储在mysql中的数据是date类型的(前端也可以传入date类型格式),当我们读取出来封装在实体类中的时候,就会变成英文时间格式,而不是yyyy-MM-dd HH:mm:ss这样的中文时间,因此我们需要用到JsonFormat注解来格式化我们的时间。

    当我们这样@ResponseBody输出json数据的时候,@JsonFormat注解标识的date属性就会自动返回yyyy-MM-dd HH:mm:ss样式的时间。

参考资料

[^1 ] @JsonFormat 实现原理

Spring Boot 中,可以使用 `SpringApplication` 类的 `WebApplicationType` 属性来控制应用的 Web 环境,从而实现优雅停止接收 HTTP 请求的功能。具体实现方式如下: 1. 在启动类中,设置 `WebApplicationType` 属性为 `REACTIVE` 或 `SERVLET`。`REACTIVE` 表示使用 Spring WebFlux,`SERVLET` 表示使用 Spring MVC。注意,如果你的应用中同时存在 WebFlux 和 MVC,那么需要使用 `NONE`,否则会抛出异常。 ```java @SpringBootApplication public class MyApp { public static void main(String[] args) { SpringApplication app = new SpringApplication(MyApp.class); app.setWebApplicationType(WebApplicationType.REACTIVE); // 或 SERVLET app.run(args); } } ``` 2. 在 `application.properties` 或 `application.yaml` 文件中,设置 `server.shutdown` 属性为 `graceful`,表示使用优雅停止的方式关闭应用。 ```yaml server: shutdown: graceful ``` 3. 在 Spring Boot 应用中添加一个 ShutdownHook,当应用被关闭时,会调用这个 ShutdownHook。 ```java @Component public class GracefulShutdown implements ApplicationListener<ContextClosedEvent> { private final Logger logger = LoggerFactory.getLogger(getClass()); private volatile boolean isShuttingDown = false; @Override public void onApplicationEvent(ContextClosedEvent event) { if (!isShuttingDown) { isShuttingDown = true; logger.info("Shutting down gracefully..."); try { Thread.sleep(5000); // 模拟执行任务的时间 } catch (InterruptedException e) { // 异常处理 } } } } ``` 在上面的代码中,我们使用了一个 `volatile` 变量 `isShuttingDown` 来记录应用是否正在关闭。当应用被关闭时,会调用 `onApplicationEvent` 方法,这里我们模拟执行任务的时间为 5 秒。注意,如果你使用的是 WebFlux,那么需要使用 `GracefulShutdownHandler` 类来实现优雅关闭,具体使用方式可以参考官方文档。 总的来说,使用 Spring Boot 实现优雅停止接收 HTTP 请求的方式比较简单,只需要设置 WebApplicationType 和 server.shutdown 属性即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值