Отправка объекта, содержащего поле даты в формате JSON, в API, кажется, что часовой пояс изменился, а время "изменилось"
Я работаю над двумя проектами Spring Boot, которые обмениваются данными между собой (первый проект вызывает API POST, определенный во втором проекте, и отправляет ему объект DTO в формате JSON. Оба проекта в настоящий момент работают на одном компьютере, поэтому они должны иметь тот же часовой пояс (я полагаю...)
У меня проблема с правильной отправкой формата даты. Я постараюсь объяснить, что делаю и с какой проблемой сталкиваюсь.
В первом проекте у меня есть этот объект 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)
он также должен установить часовой пояс по умолчанию
Затем в класс этого первого проекта у меня есть этот метод, который выполняет запрос POST к API, определенному во втором проекте:
@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 17 Oct 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
Что не так? Что мне не хватает? Как я могу попытаться исправить эту проблему? я схожу с ума
1 ответ
Дата
В своем первом проекте вы сохраняете метку времени как java.util.Date
в котором хранится информация в миллисекундах с "эпохи" (1 января 1970 г., 00:00:00 по Гринвичу). Поскольку у меня нет всего вашего кода, я предполагаю, что то, что вы видите в отладчике, - этоtoString()
представление вашего класса. Здесь вы видите правильный результат, потому чтоjava.util.Date
использует местный часовой пояс внутренней системы, но за ним стоит мгновение без какой-либо информации о часовых поясах.
Сериализация
Ваш OneRowReadTrain1DTO
class определяет формат даты с помощью:@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = JsonFormat.DEFAULT_TIMEZONE)
аннотация, краткий обзор документации по свойству часового пояса:
Часовой пояс для сериализации (при необходимости). Специальное значение DEFAULT_TIMEZONE может использоваться для обозначения "просто использовать значение по умолчанию", где значение по умолчанию определяется контекстом сериализации, который, в свою очередь, по умолчанию используется в системе по умолчанию (UTC), если явно не установлен другой часовой пояс.
По умолчанию: "##default"
И еще посмотрите, что говорится в документации о DEFAULT_TIMEZONE
:
Значение, указывающее, что следует использовать часовой пояс по умолчанию (из контекста десериализации или сериализации): аннотация не определяет значение для использования.
ПРИМЕЧАНИЕ: значение по умолчанию здесь НЕ означает значения по умолчанию для JVM, а по умолчанию привязки данных Джексона, обычно UTC, но могут быть изменены в ObjectMapper.
Настройка Джексона
По умолчанию весенняя загрузка использует Джексона для сериализации / десериализации объектов и, в частности, 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
пакет вместо этого.