2015-12-21 13 views
6

Ho un endpoint REST nella mia applicazione primavera che assomiglia a questoZonedDateTime come PathVariable nella primavera 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 ... 
} 

ho provato passando nelle variabili di percorso sia come millisecondi e secondi. Tuttavia, ottengo la seguente eccezione in entrambi i modi:

"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" 

Qualcuno può spiegare come posso passare a (o come secondi o millisecondi) una stringa come 1446,3612 milioni e farlo convertire a ZonedDateTime?

Oppure è l'unico modo per passare come String e quindi effettuare la conversione da solo? Se è così esiste un modo generico per ottenere questo trattamento per più metodi con design simile?

+0

'ZonedDateTime' è relativamente nuovo e Spring probabilmente non è stato aggiornato per supportarlo direttamente. Vedi la risposta di JasonZ per una soluzione alternativa a questo. – Powerlord

risposta

6

C'è un convertitore predefinito per i parametri ZonedDateTime. Esso utilizza Java 8 DateTimeFormatter creato come

DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT); 

Questo potrebbe essere stato qualsiasi FormatStyle o realmente qualsiasi DateTimeFormatter per quanto ti riguarda, il tuo esempio non avrebbe funzionato. DateTimeFormatter parses e formati per datare stringhe, non timestamp, che è quello che hai fornito.

Si potrebbe avere fornito un adeguato personalizzato @org.springframework.format.annotation.DateTimeFormat al parametro, ad esempio

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

o con un adeguato pattern e una corrispondente stringa di data come

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

Non è possibile eseguire alcuna delle operazioni precedenti con un timestamp unix. The canonical way per fare il timestamp a ZonedDateTime la conversione è attraverso Instant#ofEpochSecond(long), dato un appropriato ZoneId.

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

per fare questo lavoro con @PathVariable, registrare un personalizzato Converter. Qualcosa di simile

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); 
    } 
} 

e registrarlo in una classe annotata WebMvcConfigurationSupport@Configuration, ignorando addFormatters

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

Ora, Spring MVC userà questo convertitore di deserializzare il segmento String percorso in un oggetto ZonedDateTime.


Nella primavera del caricamento del sistema, penso che si può solo dichiarare una @Bean per il corrispondente Converter che verrà registrarlo automaticamente, ma non prendere la mia parola per esso.

5

Devi accettare quello che hai passato a @PathVariable come un tipo di dati String, quindi eseguire personalmente la conversione, i tuoi log degli errori ti dicono chiaramente.

La libreria Spring non può convertire i valori stringa "1446361200" in ZonedDateTime tipo tramite @PathVariable vincolante sfortunatamente.

+0

Hai ragione su ciò che deve essere fatto, ma si tratta della conversione di primavera, non di Jackson. – chrylis

1

Per impostazione predefinita, @PathVariable supporta solo un insieme limitato di tipi tra cui i 7 tipi di base (boolean, byte, short, int, long, float e double) più Date.

Tuttavia, è possibile utilizzare extend that utilizzando an @InitBinder nel controller e aggiungere un binding per ZonedDateTime.class. Non sono sicuro che sia possibile definirlo in una classe esterna, sebbene ... in caso contrario, è necessario definire questo @InitBinder in ogni controller che utilizza uno ZonedDateTime.

Modifica: potrebbe essere necessario creare un numero personalizzato PropertyEditor e associarlo utilizzando registerCustomEditor per farlo.

Problemi correlati