2015-12-21 2 views
6

У меня есть REST конечной точки в моей Spring приложение, которое выглядит как этотZonedDateTime, как PathVariable весной REST RequestMapping

@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?

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

+0

'ZonedDateTime' относительно новый, и Spring, вероятно, не был обновлен, чтобы поддерживать его напрямую. См. Ответ JasonZ для обходного пути для этого. – Powerlord

ответ

6

Приведенный по умолчанию преобразователь для параметров 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. The canonical way, чтобы сделать временную отметку до 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); 
    } 
} 

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

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

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


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

5

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

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

+0

Вы правы в том, что нужно сделать, но речь идет о преобразовании Весны, а не о Джексоне. – chrylis

1

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

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

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

Смежные вопросы