ZonedDateTime как PathVariable в Spring REST RequestMapping



У меня есть конечная точка REST в моем весеннем приложении, которая выглядит так



@RequestMapping(value="/customer/device/startDate/{startDate}/endDate/{endDate}", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
public Page<DeviceInfo> getDeviceListForCustomerBetweenDates(@PathVariable ZonedDateTime startDate, @PathVariable ZonedDateTime endDate, Pageable pageable) {
... code here ...
}


Я попытался передать переменные пути как миллисекунды, так и секунды. Однако я получаю следующее исключение в обоих случаях:



"Failed to convert value of type 'java.lang.String' to required type 'java.time.ZonedDateTime'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String to type @org.springframework.web.bind.annotation.PathVariable java.time.ZonedDateTime for value '1446361200'; nested exception is java.time.format.DateTimeParseException: Text '1446361200' could not be parsed at index 10"


Может кто-нибудь объяснить, как я могу передать (в секундах или миллисекундах) строку, такую как 1446361200, и заставить ее преобразовать в ZonedDateTime?



Или это единственный способ передать как строку, а затем сделать преобразование самому? Если да, то есть ли общий способ получить это обрабатывается для нескольких методов с аналогичным дизайном?

629   3  

3 ответов:

Есть конвертер по умолчанию для параметров ZonedDateTime. Он использует Java 8 DateTimeFormatter, созданный как

DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);

Это могло быть любое FormatStyle или действительно любое DateTimeFormatter, поскольку вы обеспокоены, ваш пример не сработал бы. DateTimeFormatter анализирует и форматирует строки даты, а не временные метки, что вы и предоставили.

Вы могли бы предоставить соответствующий обычай @org.springframework.format.annotation.DateTimeFormat к вашему параметру, такому как

public Page<DeviceInfo> getDeviceListForCustomerBetweenDates(
    @PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime startDate, 
    @PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) ZonedDateTime endDate, 
    Pageable pageable) { ...

Или с соответствующим pattern и еще ... соответствующая строка даты, например

2000-10-31T01:30:00.000-05:00

Вы не сможете сделать ничего из вышеперечисленного с меткой времени unix. канонический способ выполнить преобразование timestamp в ZonedDateTime заключается в следующем:Instant#ofEpochSecond(long), дано соответствующее ZoneId.

long startTime = 1446361200L;
ZonedDateTime start = Instant.ofEpochSecond(startTime).atZone(ZoneId.systemDefault());
System.out.println(start);

Чтобы сделать эту работу с @PathVariable, регистрировать пользовательский Converter. Что-то вроде

class ZonedDateTimeConverter implements Converter<String, ZonedDateTime> {
    private final ZoneId zoneId;

    public ZonedDateTimeConverter(ZoneId zoneId) {
        this.zoneId = zoneId;
    }

    @Override
    public ZonedDateTime convert(String source) {
        long startTime = Long.parseLong(source);
        return Instant.ofEpochSecond(startTime).atZone(zoneId);
    }
}

И зарегистрировать его в a WebMvcConfigurationSupport @Configuration аннотированный класс, переопределение addFormatters

@Override
protected void addFormatters(FormatterRegistry registry) {
    registry.addConverter(new ZonedDateTimeConverter(ZoneId.systemDefault()));
}

Теперь Spring MVC будет использовать этот конвертер для десериализации сегмента пути String в объект ZonedDateTime.


В Spring Boot, я думаю, вы можете просто объявить @Bean для соответствующего Converter, и он зарегистрирует его автоматически, но не верьте мне на слово.

Вам нужно будет принять то, что вы передали в @PathVariable как тип данных String, а затем выполнить преобразование самостоятельно, ваши журналы ошибок довольно ясно говорят вам об этом.

Библиотека Spring не может преобразовать строковые значения"1446361200" в тип ZonedDateTime через @PathVariable привязку, к сожалению.

По умолчанию, @PathVariable поддерживает только ограниченный набор типов, включая 7 основных типов (boolean, byte, short, int, long, float, и double) плюс Date.

Однако можно расширить это , используя @InitBinder в вашем контроллере и добавление привязки для ZonedDateTime.class. Хотя я не уверен, что вы можете определить это во внешнем классе... если нет, то вам нужно определить это @InitBinder в каждом контроллере, использующем ZonedDateTime.

Edit: возможно, Вам потребуется создать пользовательский PropertyEditor и свяжите его с помощью registerCustomEditor, чтобы сделать это.

Comments

    Ничего не найдено.