【问题标题】:Parse LocalTime using spring expression language from application.properties使用 application.properties 中的 spring 表达式语言解析 LocalTime
【发布时间】:2019-10-23 15:35:54
【问题描述】:

我正在尝试使用以下代码从 spring 的 application.properties 解析 LocalTime:

@Value("#{ T(java.time.LocalTime).parse('${app.myDateTime}')}")
private LocalTime myDateTime;

在 application.properties 我定义了这样的属性:

app.myDateTime=21:45:00

错误信息:

Failed to bind properties under 'app.my-date-time' to java.time.LocalTime:

Property: app.my-date-time
Value: 21:45:00
Origin: class path resource [application.properties]:44:15
Reason: failed to convert java.lang.String to @org.springframework.beans.factory.annotation.Value java.time.LocalTime

知道我做错了什么吗?谢谢。

调试模式出错:

Caused by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.time.LocalTime] for value '21:45:00'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [21:45:00]
    at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:47)
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:191)
    at org.springframework.boot.context.properties.bind.BindConverter$CompositeConversionService.convert(BindConverter.java:170)
    at org.springframework.boot.context.properties.bind.BindConverter.convert(BindConverter.java:96)
    at org.springframework.boot.context.properties.bind.BindConverter.convert(BindConverter.java:88)
    at org.springframework.boot.context.properties.bind.Binder.bindProperty(Binder.java:313)
    at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:258)
    at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:214)
    ... 210 common frames omitted
Caused by: java.lang.IllegalArgumentException: Parse attempt failed for value [21:45:00]
    at org.springframework.format.support.FormattingConversionService$ParserConverter.convert(FormattingConversionService.java:206)
    at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
    ... 217 common frames omitted
Caused by: java.time.format.DateTimeParseException: Text '21:45:00' could not be parsed at index 5
    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
    at java.time.LocalTime.parse(LocalTime.java:441)
    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:200)
    ... 218 common frames omitted

【问题讨论】:

  • 您需要使用堆栈跟踪添加完整的错误消息
  • @Deadpool 不幸的是。应用程序未能以我所写的原因开始。 ://
  • 启用调试级别日志记录并重新运行应用程序,我也想知道这个app.my-date-time 属性
  • @Deadpool 我用堆栈跟踪更新了问题,请检查一下
  • 试试我对我有用的答案

标签: java spring spring-boot java-time application.properties


【解决方案1】:

默认情况下,Spring uses 本地化非iso FormatStyle.SHORT 用于时间格式,除非它以某种方式被覆盖。所以我怀疑你可以使用09:45 PM 作为属性值,但这不是你想要的。

但正如我已经提到的,您可以使用 DateTimeFormatterRegistrar 机制全局覆盖 Spring 所期望的模式。

或者您也可以在 LocalTime myDateTime 字段上使用 @DateTimeFormat 注释。使用此注解,您可以通过三种方式指定所需的格式,即styleisopattern。在您的情况下,iso = DateTimeFormat.ISO.TIME 会起作用。所以你的代码看起来像这样:

@Value("${app.myDateTime}")
@DateTimeFormat(iso = DateTimeFormat.ISO.TIME)
private LocalTime myDateTime;

请注意,这三个属性是互斥的(请参阅提供的链接中的 javadoc):

每个属性是互斥的,所以每个注解实例只设置一个属性

【讨论】:

    【解决方案2】:

    选项 1 - 使用 @ConfigurationPropertiesBinding

    如果您使用 @ConfigurationProperties 加载属性,您可以使用 @ConfigurationPropertiesBinding 将自定义转换器绑定到 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"));
      }
    }
    

    选项 2 - 使用 @Value

    如果你宁愿坚持@Value,那么你已经很接近了:

    @Value("#{T(java.time.LocalTime).parse('${app.myDateTime}', T(java.time.format.DateTimeFormatter).ofPattern('HH:mm:ss'))}")
    

    有关 DateTimeFormatter 选项的列表,请参阅 https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html

    来源:

    【讨论】:

    • 第二个选项是我正在寻找的,但我得到了同样的错误:未能将 java.lang.String 转换为 @org.springframework.beans.factory.annotation.Value java.time.LocalTime
    • @DenisStephanov 听到这个消息我很惊讶,所以我自己尝试了第一个选项。它确实有效。该答案中的唯一错误是您想要“HH:mm:ss”,以便您可以在[0-23]间隔内解析小时。我用小时校正更新了答案,并截图了它对我来说的样子。出于同样的原因,第二个答案可能会失败。我链接了 DateTimeFormatter 文档,目的是让 DateTimeFormatter 满足您的需求。
    • 我用堆栈跟踪更新了问题,请检查一下
    【解决方案3】:

    要将日期注入@Value,使用 Spring 表达式语言 (SpEL), 例如:

    @Value(“#{new java.text.SimpleDateFormat(‘${aTimeFormat}’).parse(‘${aTimeStr}’)}”)
    Date myDate;
    

    在您的情况下,您直接注入 Date 值而不提供格式化程序,因此它不知道要解析为什么格式,使用该格式定义一个新属性并使用该格式化程序解析值,如上面的示例,它会被注入。 您的 application.properties 属性应如下所示:

    aTimeStr=21:16:46
    aTimeFormat=HH:mm:ss
    

    【讨论】:

    • 这是否适用于LocalTime?因为 OP 使用的是LocalTime
    • 我尝试过这样的 DateTimeFormatter (java.time.format.DateTimeFormatter).ofPattern('HH:mm:ss') 但不起作用。错误:无法将“java.time.format.Parsed”类型的值转换为所需的“java.time.LocalTime”类型:找不到匹配的编辑器或转换策略
    【解决方案4】:

    我已经用 jdk-11 在 spring boot-2.1.5 上测试过这个

    @Value("#{ T(java.time.LocalTime).parse('${app.myDateTime}',T(java.time.format.DateTimeFormatter).ISO_LOCAL_TIME)}")
    private LocalTime timeValue;   //21:45
    

    【讨论】:

    • 我不明白...同样的错误:/我使用的是open jdk 8,可能是这个问题吗?
    • 你可能会犯一些小错误,或者你可以尝试升级java版本吗? @DenisStephanov
    猜你喜欢
    • 2016-06-27
    • 1970-01-01
    • 2012-05-24
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多