【问题标题】:micronaut convert request param to Instant or ZonedDateTimemicronaut 将请求参数转换为 Instant 或 ZonedDateTime
【发布时间】:2020-04-13 17:53:53
【问题描述】:

我正在使用 Micronaut 1.3.4,我正在尝试将输入转换为 Instant。到目前为止,我尝试了很多方法,但没有成功。下面的代码只显示了我尝试过的两种情况,但都没有成功。

我想将输入日期转换为InstantOffsetDateTime

    @Get("/...")
    public List<Obj> method(
//            @Format("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
//                    Instant startDateTime,
            @Format("yyyy-MM-dd")
                    LocalDate endDateTime
    ) {

如果可能,我想使用 ISO 8601。

我尝试过的输入:

2013-02-04
2013-02-04T22:44:30.652Z
...

我得到的输出是:

"message": "Required argument [LocalDate endDateTime] not specified",

我的后备是:

        String startDateTime

        Instant parse = Instant.parse(startDateTime);
        OffsetDateTime parse = OffsetDateTime.parse(startDateTime);

但我仍然想知道如何使用 Micronaut 来做到这一点。

【问题讨论】:

    标签: micronaut


    【解决方案1】:

    这是一个示例,说明如何在 Micronaut 中将 LocalDateTime 作为查询参数传递:

    @Get("/local")
    public String local(@Format("yyyy-MM-dd'T'HH:mm:ss") @QueryValue LocalDateTime time) {
        return "Time " + DateTimeFormatter.ISO_DATE_TIME.format(time);
    }
    

    带有结果的 curl 调用示例:

    $ curl http://localhost:8080/example/local?time=2020-04-13T21:13:59
    Time 2020-04-13T21:13:59
    

    当时区始终相同时,您可以使用LocalDateTime。你可以把它转换成Instant,像这样time.atZone(ZoneId.systemDefault()).toInstant()

    当时区可以不同并且必须是输入时间的一部分时,您可以像这样使用ZonedDateTime参数:

    @Get("/zoned")
    public String method(@Format("yyyy-MM-dd'T'HH:mm:ss.SSSZ") @QueryValue ZonedDateTime time) {
        return "Time " + DateTimeFormatter.ISO_DATE_TIME.format(time);
    }
    

    转换成Instant 很简单:time.toInstant()

    带有结果的 curl 调用示例:

    $ curl http://localhost:8080/example/zoned?time=2020-04-13T21:13:59.123-0100
    Time 2020-04-13T21:13:59.123-01:00
    

    当您以错误的格式输入时间查询参数(此处缺少秒数和区域偏移量)时,其行为如下:

    $ curl http://localhost:8080/example/zoned?time=2020-04-13T21:13:59
    {"message":"Required QueryValue [time] not specified","path":"/time","_links":{"self":{"href":"/example/zoned?time=2020-04-13T21:13:59","templated":false}}}
    

    您也可以使用时间作为请求路径的一部分:

    @Get("/local/{time}")
    public String local(@Format("yyyy-MM-dd'T'HH:mm:ss") LocalDateTime time) {
        return "Time from request path " + DateTimeFormatter.ISO_DATE_TIME.format(time);
    }
    

    那么示例 curl 调用将是:

    $ curl http://localhost:8080/example/local/2020-04-13T21:13:59
    Time from request path 2020-04-13T21:13:59
    

    当您在路径中输入错误格式的时间(此处不需要的秒数)时,它的行为如下:

    $ curl http://localhost:8080/example/local/2020-04-13T21:13:59.111
    {"message":"Failed to convert argument [time] for value [2020-04-13T21:13:59.111] due to: Text '2020-04-13T21:13:59.111' could not be parsed, unparsed text found at index 19","path":"/time","_links":{"self":{"href":"/example/local/2020-04-13T21:13:59.111","templated":false}}}
    

    【讨论】:

    • 我试过@Format("yyyy-MM-dd'T'HH:mm:ss.SSSZ") @QueryValue ZonedDateTime startDateTime,但没有成功。我仍然得到"Required QueryValue [startDateTime] not specified"curl 'http://localhost:8080/.../...?startDateTime=2020-04-14T00:00:00%2B03:00&amp;endDateTime=2020-04-15T00:00:00%2B03:00'
    • 是的,因为您的格式模式也需要几分之一秒。将它 (.000) 添加到您的 curl 请求中:?startDateTime=2020-04-14T00:00:00.000%2B0300&amp;endDateTime=2020-04-15T00:00:00.000%2B0300。或者您可以在yyyy-MM-dd'T'HH:mm:ssZ 上更改所需的格式,然后不需要几分之一秒。
    【解决方案2】:

    还有另一种方法可以做到这一点。 @Formatannotation 是有问题的,因为它不能支持 Java 类如 OffsetDateTime 和 ZonedDateTime 支持的所有格式。

    如果你有例如这个方法:

    @Get("/local")
    public String local(@QueryValue OffsetDateTime time) {
        return "Time " + time.toString();
    }
    

    要使其支持 ISO8601,请修改您的 Application.java(或创建一个新类),其中包含:

    @Context
    public class Application {
    
        public static void main(String[] args) {
            // starts micronaut
        }
    
        @PostConstruct
        public void addPathConverter(ConversionService<DefaultConversionService> conversionService) {
            conversionService.addConverter(String.class, OffsetDateTime.class, (in) ->
                    OffsetDateTime.parse(in));
        }
    }
    

    【讨论】:

      【解决方案3】:

      在 Micronaut 3 中推荐的解决此问题的方法,具有以下灵活性 多种格式,是通过添加自定义类型转换器。

      OffsetDateTime 的示例实现可能是:

      @Singleton
      public class OffsetDateTimeConverter implements TypeConverter<String, OffsetDateTime> {
      
          @Override
          public Optional<OffsetDateTime> convert(String inputDateTime, Class<OffsetDateTime> targetType, ConversionContext context) {
              if (inputDateTime != null) {
                  try {
                      var offsetDateTime = OffsetDateTime.parse(inputDateTime);
                      return Optional.of(offsetDateTime);
                  } catch (DateTimeParseException e) {
                      context.reject(inputDateTime, e);
                  }
              }
      
              return Optional.empty();
          }
      }
      

      这可以在3.2.7 documentation(和其他人)中查看。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-08-03
        • 2013-12-07
        • 1970-01-01
        • 2017-05-31
        • 1970-01-01
        • 2018-12-24
        • 2016-07-24
        相关资源
        最近更新 更多