如何让 Spring 引导解析属性以ISO8601格式绑定到 LocalTime?



我有一个使用 Spring Boot 2.2.6 的应用程序,它使用@ConfigurationProperties组件,如下所示:

@Component
@ConfigurationProperties("myapplication")
public class MyApplicationSettings {
private LocalTime startOfDay;
// getter and setters here
}

我的集成测试突然在 Jenkins 上开始失败,但在本地运行良好。异常显示如下内容:

Description:
Failed to bind properties under 'myapplication.start-of-day' to java.time.LocalTime:
Property: myapplication.start-of-day
Value: 06:00
Origin: class path resource [application-integration-test.properties]:29:62
Reason: failed to convert java.lang.String to java.time.LocalTime
Action:
Update your application's configuration

完整异常跟踪的根本原因为:

Caused by: java.time.format.DateTimeParseException: Text '06:00' could not be parsed at index 5
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
at java.base/java.time.LocalTime.parse(LocalTime.java:463)
at org.springframework.format.datetime.standard.TemporalAccessorParser.parse(TemporalAccessorParser.java:72)
at org.springframework.format.datetime.standard.TemporalAccessorParser.parse(TemporalAccessorParser.java:46)
at org.springframework.format.support.FormattingConversionService$ParserConverter.convert(FormattingConversionService.java:217)

经过一些代码的挖掘,我发现 Spring 将使用默认语言环境来解析LocalTime。由于我的本地机器使用 24 小时表示法,因此它可以工作。生成服务器处于 12 小时区域设置上,因此它无法分析字符串,因为没有 am/pm 指示。

我的问题:

如何配置 Spring 引导以将配置属性解析为 ISO-8601 格式,独立于 JVM 的默认语言环境?

我还检查了文档,但"属性转换"一章没有提到LocalTime(或LocalDate(

解决方案应包括以下步骤:

  1. 使用LocalTime字段(在您的情况下为 MyApplicationSettings(创建@ConfigurationProperties带注释的类,并在@Configuration中注册它@EnableConfigurationProperties(MyApplicationSettings.class)
  2. application.properties中定义值:
myapplication.startOfDay=06:00:00
  1. 创建一个特殊的转换器,并确保它被 Spring 启动应用程序扫描和加载。当然,实际解析的逻辑可以不同,在那里实现您想要的任何内容,任何特定格式,语言环境 - 无论什么:
@Component
@ConfigurationPropertiesBinding
public class LocalTimeConverter implements Converter<String, LocalTime> {
@Override
public LocalTime convert(String source) {
if(source==null){
return null;
}
return LocalTime.parse(source, DateTimeFormatter.ofPattern("HH:mm:ss"));
}
}
  1. 现在@ConfigurationProperties类中的所有LocalTime条目都将通过此转换器。

有一种方法可以做到这一点,但不是直接的解决方案。您需要创建自定义ConversionServiceBean,将此代码片段放在应用程序文件中,它应该可以工作。

在这里,我正在注册一个新的转换器,它将始终以ISO_LOCAL_TIME格式转换LocalTime。您也可以选择使用其他日期格式化程序。

@Bean
public ConversionService conversionService() {
ApplicationConversionService conversionService = new ApplicationConversionService();
conversionService.addConverter(
String.class,
LocalTime.class,
(Converter) source -> LocalTime.parse((String) source, DateTimeFormatter.ISO_LOCAL_TIME));
return conversionService;
}

最新更新