我有一个使用 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
(
解决方案应包括以下步骤:
- 使用
LocalTime
字段(在您的情况下为 MyApplicationSettings(创建@ConfigurationProperties
带注释的类,并在@Configuration
中注册它@EnableConfigurationProperties(MyApplicationSettings.class)
- 在
application.properties
中定义值:
myapplication.startOfDay=06:00:00
- 创建一个特殊的转换器,并确保它被 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"));
}
}
- 现在
@ConfigurationProperties
类中的所有LocalTime
条目都将通过此转换器。
有一种方法可以做到这一点,但不是直接的解决方案。您需要创建自定义ConversionService
Bean,将此代码片段放在应用程序文件中,它应该可以工作。
在这里,我正在注册一个新的转换器,它将始终以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;
}