spring-mvc - 如何使用 Spring MVC @RequestParam 解析不同的 ISO 日期/时间格式
问题描述
我们的 Rest API 被多个外部方使用。它们都使用“ISO-ish”格式,但时区偏移的格式略有不同。这些是我们看到的一些最常见的格式:
2018-01-01T15:56:31.410Z
2018-01-01T15:56:31.41Z
2018-01-01T15:56:31Z
2018-01-01T15:56:31+00:00
2018-01-01T15:56:31+0000
2018-01-01T15:56:31+00
在我的控制器中,我使用以下注释:
@RequestMapping(value = ["/some/api/call"], method = [GET])
fun someApiCall(
@RequestParam("from")
@DateTimeFormat(iso = ISO.DATE_TIME)
from: OffsetDateTime
) {
...
}
它可以很好地解析变体 1-4,但会为变体 5 和 6 产生 400 Bad Request 错误,但有以下异常:
Caused by: java.time.format.DateTimeParseException: Text '2018-01-01T13:37:00.001+00' could not be parsed, unparsed text found at index 23
at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1952)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
如何让它接受所有上述 ISO 格式变体(即使它们不是 100% 符合 ISO 标准)?
解决方案
我通过添加自定义格式化程序注释来解决它:
@Target(AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
annotation class IsoDateTime
加上一个 FormatterFactory:
class DefensiveDateTimeFormatterFactory :
EmbeddedValueResolutionSupport(), AnnotationFormatterFactory<IsoDateTime>
{
override fun getParser(annotation: IsoDateTime?, fieldType: Class<*>?): Parser<*> {
return Parser<OffsetDateTime> { text, _ -> OffsetDateTime.parse(text, JacksonConfig.defensiveFormatter) }
}
override fun getPrinter(annotation: IsoDateTime, fieldType: Class<*>): Printer<*> {
return Printer<OffsetDateTime> { obj, _ -> obj.format(DateTimeFormatter.ISO_DATE_TIME) }
}
override fun getFieldTypes(): MutableSet<Class<*>> {
return mutableSetOf(OffsetDateTime::class.java)
}
}
实际的 DateTimeFormat 类来自我的另一个问题,如何使用 Jackson 和 java.time 解析不同的 ISO 日期/时间格式?
并使用 WebMvcConfigurer 将其添加到 Spring:
@Configuration
open class WebMvcConfiguration : WebMvcConfigurer {
override fun addFormatters(registry: FormatterRegistry) {
registry.addFormatterForFieldAnnotation(DefensiveDateTimeFormatterFactory())
}
}
推荐阅读
- python - 如何以逆时针方向对坐标元组列表进行排序?
- java - 在spring boot中使用多个依赖服务时如何测试服务层
- numpy - 在 numpy/pytorch 中使用 bool 数组或索引数组进行索引是否更快?
- kubernetes - GCP 中不允许使用磁盘创建 Kubernetes 集群
- jquery - 使用特定值缩短 JQUERY UI Slider 的代码
- kotlin - 如何在开始对话框中显示键盘
- ios - 是否可以在 Lottie 框架中组合两个动画
- android - Android 应用更新 - 从 Google Play 下载后无法打开
- iis - 仅为 IIS 上的子域启用 Windows 身份验证
- laravel - HTTPS:Laravel 使用 .htaccess (public/)