编程语言
首页 > 编程语言> > java – Spring REST LocalDate UTC有一天不同

java – Spring REST LocalDate UTC有一天不同

作者:互联网

我正在使用Spring Boot 1.5.4,Hibernate 5.2.10,Spring Data REST,HATEOAS,JDK8以及LocalDate和LocalDateTime.
我的计算机在CEST时区,但我希望应用程序在UTC中工作,所以我在application.properties中设置:

spring.datasource.url=jdbc:mysql://localhost:3306/database?useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=true
spring.jpa.hibernate.jdbc.time_zone = UTC

根据这个article,我不想改变我的JVM的时区,因为这似乎不是最佳实践.

Spring Data REST公开我的存储库,我使用Swagger2有一个很好的接口来使用API​​.
当我尝试端点时,我看到类似的东西:

    {
  "_embedded": {
    "dailyCodes": [
      {
        "sid": "d495cdaa-14f2-44cb-a98f-8aa6ddd43d91",
        "createdDate": "2017-06-28T16:20:01",
        "lastModifiedDate": "2017-06-28T16:20:01",
        "lastModifiedBy": "admin",
        "date": "2017-06-28",
        "code": "js",
        "new": false,
        "_links": {
          "self": {
            "href": "http://localhost:8080/api/v1/dailyCodes/1"
          },
          "dailyCode": {
            "href": "http://localhost:8080/api/v1/dailyCodes/1"
          }
        }
      }

就像你可以看到日期时间格式很好,它也显示CEST时间,即使在db中实时是14:20:01.
我想这是错误的,因为我的REST API应该在UTC中工作.

我怎么能实现这个结果?

总是在同一主题上,我有一个REST端点(由Spring Data REST公开)来使用LocalDate params进行搜索;我正在使用

@Transactional
@PreAuthorize("isAuthenticated()")
public interface DailyCodeRepository extends PagingAndSortingRepository<DailyCode, Long> {

@Query("SELECT d FROM DailyCode d WHERE (:code IS NULL or code=:code) AND (:from IS NULL OR date>=:from) AND (:to IS NULL OR date<=:to)")
    public Page<DailyCode> findAllWithParameter(@Param("code") @RequestParam(value = "code", required = false) String code,
            @Param("from") @RequestParam(value = "from", required = false) LocalDate from,
            @Param("to") @RequestParam(value = "to", required = false) LocalDate to, Pageable pageable);
}

同样在这种情况下,我有一个奇怪的事情:如果我调用端点传递参数,在服务器中它们到达时减少1天.此外,接受的日期模式似乎是我的语言环境(意大利语)的JDK默认值,但我想这不是最佳做法.

是否有最佳做法可以避免双向日期/时间参数出现任何问题?

解决方法:

我同意这篇文章The 5 laws of API dates and times的作者,我们必须以UTC格式存储和返回时间.并且’前端’必须决定如何根据客户端时区转换时间值.

为了实现这一点(以UTC格式存储和返回时间),我们设置JVM参数-Duser.timezone = UTC或将spring.jpa.properties.hibernate.jdbc.time_zone = UTC添加到application.properties(从Hibernate 5.2.3.Final开始) .然后将我们实体的时间字段从LocalDateTime(不存储时区信息)更改为ZonedDateTime类型.

之后,时间值将独立于启动应用程序的计算机的本地时区以UTC格式存储,SDR将以ISO8601格式返回这些值:2017-07-02T11:58:10.089Z

但是如果需要在特定时区返回时间值,我们必须将@JsonFormat注释设置为我们所有的时间字段:

@JsonFormat(timezone = "Europe/Rome", pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
private ZonedDateTime createdDate;

我们可以在应用程序中定义常量TIME_ZONE,并在@JsonFormat注释中设置它:@JsonFormat(timezone = Application.TIME_ZONE,…).

然后我们得到这个输出:

{
    //...
    "createdDate": "2017-07-02T14:11:45.964+0200",
    //...
}

不幸的是,参数spring.jackson.time-zone(基于我的简短调查)仅影响应用程序中的服务消息,例如:

{
    "timestamp": "2017-07-02T14:14:09.486+0200",
    "status": 404,
    "error": "Not Found",
    "message": "No message available",
    "path": "/users"
}

要以’zoned’形式获取时间,我们必须在application.properties中正确设置spring.jackson.date-format参数:

spring.jackson.date-format=com.fasterxml.jackson.databind.util.StdDateFormat

标签:java,spring,rest,spring-data-rest,spring-mvc
来源: https://codeday.me/bug/20191003/1845943.html