-1

我正在开发 2 个在它们之间进行通信的 Spring Boot 项目(第一个项目调用在第二个项目上定义的 POST API 并向其发送 JSON 格式的 DTO 对象。目前这两个项目都在同一台机器上运行,因此它们应该有相同的时区(我想......)

我在正确发送日期格式时遇到问题。我将尝试解释我在做什么以及我面临什么问题。

在第一个项目中,我有这个DTO对象:

import java.util.Date;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonPropertyOrder(alphabetic=true)
public class OneRowReadTrain1DTO {
    
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = JsonFormat.DEFAULT_TIMEZONE)
    @JsonProperty("Time_Stamp")
    private Date timeStamp;
    
    private Double v1;
    private Double v2;
    ........................................
    ........................................
    ........................................
    CONSTRUCTOR AND GETTER AND SETTER METHODS
}

如您所见,我有这个带有此注释的 timeStamp 字段,用于转换 JSON 中的字段:

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = JsonFormat.DEFAULT_TIMEZONE)

它还应该设置默认时区

然后进入第一个项目的一个类,我有这个方法执行对第二个项目中定义的 API 的 POST 请求:

@Scheduled(fixedRate=90000)
public void insertOneRowReadTrain1Job() {
    System.out.println("COUNTER: " + counter);
    
    OneRowReadTrain1DTO currentElement = excelRowAsDtoList.get(counter);
    System.out.println("CURRENT DTO: " + currentElement);
    
    String insertApiUrl = baseUrl + "oneRowReadTrain1/";
    try {
        uri = new URI(insertApiUrl);
    } catch (URISyntaxException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    
    ResponseEntity<Integer> result = restTemplate.postForEntity(uri, currentElement, Integer.class);
    
    System.out.println("result: " + result);
    System.out.println("--------------------------------------------------------------------------------------------"); 
    counter++;
    
}

如您所见,我正在通过这一行执行 API 调用:

ResponseEntity<Integer> result = restTemplate.postForEntity(uri, currentElement, Integer.class);

使用调试器timeStamp字段值似乎是正确的,实际上这个字段值是:

OneRowReadTrain1DTO [timeStamp=Sat Oct 17 06:00:14 PDT 2009, v1=6.5718506, v2=538.47812, ......]

如您所见,此日期字段的值为timeStamp=Sat Oct 17 06:00:14,它是预期值。

然后调用第二个项目中定义的 API,在这里我得到了这个字段值的奇怪行为。

在第二个项目中,调用的 API 是:

@PostMapping(value = "/train/{trainName}", consumes = "application/json")
@CrossOrigin(origins = "*", allowedHeaders = "*")
public int insertTrend(@PathVariable("trainName") String trainName, 
                       @RequestBody Map<String, Object> jsonTrainInfo) throws IOException {
    
    int result = 0;
    
    System.out.println("trainName: " + trainName);
    System.out.println("JSON: " + jsonTrainInfo);
    
    result = trainService.insertOneRowReadTrain(trainName, jsonTrainInfo);
    
    return result;
}

如您所见,获得的有效负载在此方法参数中:

@RequestBody Map<String, Object> jsonTrainInfo

问题是我得到了这样的东西:

{Time_Stamp=2009-10-17 13:00:14, v1=6.5718506,.....}

如您所见,该字段的值为:Time_Stamp=2009-10-17 13:00:14其中日期部分(2009-10-17)是正确的,但时间部分完全错误,实际上获得的时间部分是13:00:14而不是预期的 06:00:14(存在于已发送对象中的那个)。

现在据我所知 6:00 PDT 等于 13:00 GMT 但为什么我有这个问题?我需要收到的日期在同一时区(或者我错过了什么?)

为什么当它被接收到Map<String, Object> jsonTrainInfo时区似乎改变了?

怎么了?我错过了什么?我该如何尝试解决此问题?我快疯了

4

1 回答 1

1

日期

在您的第一个项目中,您将时间戳java.util.Date存储为自“纪元”(1970 年 1 月 1 日,格林威治标准时间 00:00:00)以来以毫秒为单位的存储信息。由于我没有你的全部代码,我假设你在调试器中看到的是toString()你的类的表示。在这里您可以看到正确的输出,因为java.util.Date使用内部系统本地时区,但后面的值只是一个瞬间,没有任何有关时区的信息。

序列化

您的OneRowReadTrain1DTO 课程使用以下注释指定日期格式 @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = JsonFormat.DEFAULT_TIMEZONE),快速查看 timezone 属性的文档:

用于序列化的时区(如果需要)。DEFAULT_TIMEZONE 的特殊值可用于表示“仅使用默认值”,其中默认值由序列化上下文指定,而序列化上下文又默认为系统默认值 (UTC),除非明确设置为另一个时区。
默认值:“##default”

此外,请参阅文档中有关以下内容的内容DEFAULT_TIMEZONE

指示应使用默认 TimeZone(来自反序列化或序列化上下文)的值:注释未定义要使用的值。
注意:这里的默认值并不意味着 JVM 默认值,而是 Jackson 数据绑定默认值,通常是 UTC,但可以在 ObjectMapper 上更改。

配置杰克逊

默认情况下,spring boot 使用 Jackson 来序列化/反序列化对象,特别是MappingJackson2HttpMessageConverter. 它使用杰克逊的ObjectMapper写/读数据。当您将时区设置为 时JsonFormat.DEFAULT_TIMEZONE,结果是 UTC,因此您会在不同时区的其他应用程序时间戳中收到。

如果您的数据应始终包含PDT“时区”中的日期,您可以在 DTO 的注释中设置它,如下所示:( @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "America/Los_Angeles") 如果您想知道为什么我使用 America/Los_Angeles 时区,请参阅此处)。您可以尝试的另一件事是添加spring.jackson.time-zone=America/Los_Angeles到您的application.properties中,这将在您的整个应用程序中使用的 JacksonProperties 中设置时区。

最后说明

提供的解决方案应该适用于java.util.Date,但请注意,不鼓励使用此类,请考虑使用 java 8java.time包中的类。

于 2020-07-28T22:48:53.347 回答