2015-12-21 38 views
6

我在我的Spring应用程序REST端点,看起来像这样ZonedDateTime如PathVariable在弹簧安置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?

或者是作为String传递的唯一方法,然后自己进行转换?如果是的话,是否有一种通用的方法来处理类似设计的多种方法?

+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对象。


在春季启动,我想你可以申报相应Converter一个@Bean,它会自动注册它,但不要把我的话。

5

你需要接受你传递给@PathVariable的数据类型为String,然后自己进行转换,你的错误日志很清楚地告诉你。

不幸的是,弹簧库无法通过@PathVariable绑定字符串值“1446361200”到ZonedDateTime类型。

+0

你说的是对的,但这是关于Spring的转换,而不是Jackson。 – chrylis

1

默认情况下,@PathVariable仅支持有限的一组类型包括7种基本类型(booleanbyteshortintlongfloat,和double)加Date

但是,在控制器中使用an @InitBinderextend that是可能的,并添加了对ZonedDateTime.class的绑定。我不确定你是否可以在外部类中定义这个,但是如果不是,你需要在每个使用ZonedDateTime的控制器中定义这个@InitBinder

编辑:您可能需要创建自定义PropertyEditor并使用registerCustomEditor将其绑定来执行此操作。