如何为 Spring Data Rest 存储库和 Querydsl 定义请求日期格式
How to define request date format for Spring Data Rest repositories and Querydsl
简介
假设在 Spring 引导应用程序中有一个扩展 JpaRepository
、QuerydslPredicateExecutor
和 QuerydslBinderCustomizer
的人员存储库接口,如下所示:
@RepositoryRestResource(path = "persons")
public interface PersonRepository
extends JpaRepository<Person, Long>, QuerydslPredicateExecutor<Person>,
QuerydslBinderCustomizer<QPerson> {
@Override
default void customize(QuerydslBindings bindings, QPerson root) {
bindings.bind(String.class)
.first((StringPath path, String value) -> (path.eq(value)));
bindings.bind(LocalDate.class)
.first((DatePath<LocalDate> path, LocalDate value) -> (path.eq(value)));
}
}
属于此存储库的 Person
class(JPA 实体)仅包含属性 name: String
和 dateOfBirth: LocalDate
。
鉴于此,有收集端点可以查询属于存储库的(提供魔法的)控制器,如下所示(此处查询所有名称等于某物的人):
curl "http://localhost:8080/persons?name=John"
此请求已成功处理。
问题
但是如何(集中)定义日期格式来查询所有生日等于某天的人?
我想像这样查询存储库(格式为yyyy-MM-dd):
curl "http://localhost:8080/persons?dateOfBirth=1987-12-15"
应用程序 运行 所在的系统区域设置为 en_US,因此日期格式类似于 MM/dd/yy。 (使用这种日期格式查询,请求也处理成功)
第一次(未成功)thought/attempt
要使用预期的格式,我的第一个想法是在 spring 启动的应用程序属性中定义日期格式:
spring.mvc.format.date: yyyy-MM-dd
但是这种方法导致 DateTimeParseException
说无法解析 yyyy-MM-dd
格式的日期:
...
Caused by: java.lang.IllegalArgumentException: Parse attempt failed for value [2020-01-01]
at org.springframework.format.support.FormattingConversionService$ParserConverter.convert(FormattingConversionService.java:223) ~[spring-context-5.2.10.RELEASE.jar:5.2.10.RELEASE]
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41) ~[spring-core-5.2.10.RELEASE.jar:5.2.10.RELEASE]
... 56 common frames omitted
Caused by: java.time.format.DateTimeParseException: Text '2020-01-01' could not be parsed at index 4
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046) ~[na:na]
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948) ~[na:na]
at java.base/java.time.LocalDate.parse(LocalDate.java:428) ~[na:na]
at org.springframework.format.datetime.standard.TemporalAccessorParser.parse(TemporalAccessorParser.java:69) ~[spring-context-5.2.10.RELEASE.jar:5.2.10.RELEASE]
at org.springframework.format.datetime.standard.TemporalAccessorParser.parse(TemporalAccessorParser.java:46) ~[spring-context-5.2.10.RELEASE.jar:5.2.10.RELEASE]
at org.springframework.format.support.FormattingConversionService$ParserConverter.convert(FormattingConversionService.java:217) ~[spring-context-5.2.10.RELEASE.jar:5.2.10.RELEASE]
(手动创建的“常规”存储库资源以 LocalDate
作为参数使用所需的日期格式,因此成功处理了 .../persons/search/findByDateOfBirth=1987-12-15
之类的请求)
为了完整示例,我创建了一个包含一些测试的可执行文件 sample project。
提供带有 RepositoryRestConfigurer
的自定义 Converter
解决了我的问题,因此可以指定日期格式(Jsr310Converters.StringToLocalDateConverter.INSTANCE
使用 DateTimeFormatter.ISO_DATE
):
@Component
public class LocalDateConfiguration implements RepositoryRestConfigurer {
@Override
public void configureConversionService(ConfigurableConversionService conversionService) {
conversionService.addConverter(StringToLocalDateConverter.INSTANCE);
}
}
总的来说:
@Component
public class LocalDateConfiguration implements RepositoryRestConfigurer {
@Override
public void configureConversionService(ConfigurableConversionService conversionService) {
conversionService.addConverter(new Converter<String, LocalDate>() {
@Override
public LocalDate convert(String source) {
// Use any format
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
return LocalDate.parse(source, formatter);
}
});
}
}
简介
假设在 Spring 引导应用程序中有一个扩展 JpaRepository
、QuerydslPredicateExecutor
和 QuerydslBinderCustomizer
的人员存储库接口,如下所示:
@RepositoryRestResource(path = "persons")
public interface PersonRepository
extends JpaRepository<Person, Long>, QuerydslPredicateExecutor<Person>,
QuerydslBinderCustomizer<QPerson> {
@Override
default void customize(QuerydslBindings bindings, QPerson root) {
bindings.bind(String.class)
.first((StringPath path, String value) -> (path.eq(value)));
bindings.bind(LocalDate.class)
.first((DatePath<LocalDate> path, LocalDate value) -> (path.eq(value)));
}
}
属于此存储库的 Person
class(JPA 实体)仅包含属性 name: String
和 dateOfBirth: LocalDate
。
鉴于此,有收集端点可以查询属于存储库的(提供魔法的)控制器,如下所示(此处查询所有名称等于某物的人):
curl "http://localhost:8080/persons?name=John"
此请求已成功处理。
问题
但是如何(集中)定义日期格式来查询所有生日等于某天的人?
我想像这样查询存储库(格式为yyyy-MM-dd):
curl "http://localhost:8080/persons?dateOfBirth=1987-12-15"
应用程序 运行 所在的系统区域设置为 en_US,因此日期格式类似于 MM/dd/yy。 (使用这种日期格式查询,请求也处理成功)
第一次(未成功)thought/attempt
要使用预期的格式,我的第一个想法是在 spring 启动的应用程序属性中定义日期格式:
spring.mvc.format.date: yyyy-MM-dd
但是这种方法导致 DateTimeParseException
说无法解析 yyyy-MM-dd
格式的日期:
...
Caused by: java.lang.IllegalArgumentException: Parse attempt failed for value [2020-01-01]
at org.springframework.format.support.FormattingConversionService$ParserConverter.convert(FormattingConversionService.java:223) ~[spring-context-5.2.10.RELEASE.jar:5.2.10.RELEASE]
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41) ~[spring-core-5.2.10.RELEASE.jar:5.2.10.RELEASE]
... 56 common frames omitted
Caused by: java.time.format.DateTimeParseException: Text '2020-01-01' could not be parsed at index 4
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046) ~[na:na]
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948) ~[na:na]
at java.base/java.time.LocalDate.parse(LocalDate.java:428) ~[na:na]
at org.springframework.format.datetime.standard.TemporalAccessorParser.parse(TemporalAccessorParser.java:69) ~[spring-context-5.2.10.RELEASE.jar:5.2.10.RELEASE]
at org.springframework.format.datetime.standard.TemporalAccessorParser.parse(TemporalAccessorParser.java:46) ~[spring-context-5.2.10.RELEASE.jar:5.2.10.RELEASE]
at org.springframework.format.support.FormattingConversionService$ParserConverter.convert(FormattingConversionService.java:217) ~[spring-context-5.2.10.RELEASE.jar:5.2.10.RELEASE]
(手动创建的“常规”存储库资源以 ) LocalDate
作为参数使用所需的日期格式,因此成功处理了 .../persons/search/findByDateOfBirth=1987-12-15
之类的请求
为了完整示例,我创建了一个包含一些测试的可执行文件 sample project。
提供带有 RepositoryRestConfigurer
的自定义 Converter
解决了我的问题,因此可以指定日期格式(Jsr310Converters.StringToLocalDateConverter.INSTANCE
使用 DateTimeFormatter.ISO_DATE
):
@Component
public class LocalDateConfiguration implements RepositoryRestConfigurer {
@Override
public void configureConversionService(ConfigurableConversionService conversionService) {
conversionService.addConverter(StringToLocalDateConverter.INSTANCE);
}
}
总的来说:
@Component
public class LocalDateConfiguration implements RepositoryRestConfigurer {
@Override
public void configureConversionService(ConfigurableConversionService conversionService) {
conversionService.addConverter(new Converter<String, LocalDate>() {
@Override
public LocalDate convert(String source) {
// Use any format
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
return LocalDate.parse(source, formatter);
}
});
}
}