为 QueryDSL 支持自定义参数绑定
Customizing Param Binding for QueryDSL Support
我有一个 Spring Data Rest 存储库,它利用此处概述的 QueryDSL 支持:
https://spring.io/blog/2015/09/04/what-s-new-in-spring-data-release-gosling#spring-data-rest
默认使用equals查询所有指定的参数。同一篇文章中给出了一种覆盖参数绑定到除 equals 之外的东西的机制,但是它需要 Java 8.
https://spring.io/blog/2015/09/04/what-s-new-in-spring-data-release-gosling#querydsl-web-support
Java7 中是否有任何干净的方法来实现相同的功能?
更新
我可以让绑定自定义工作如下:
@Override
public void customize(QuerydslBindings bindings, QMember member) {
bindings.bind(member.forename).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String value) {
return path.like(value);
}
});
bindings.bind(member.surname).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String value) {
return path.startsWith(value);
}
});
}
然而,这些示例都在存储库界面上使用 Java 8 默认方法来应用它们。
public interface MemberRepository extends JpaRepository<Member, Long>,
QueryDslPredicateExecutor<Member>,QuerydslBinderCustomizer<QMember> {
default void customize(QuerydslBindings bindings, QMember member) {
....
}
}
在Java7中这显然是不可能的。我尝试使用自定义存储库,但失败并出现错误:
org.springframework.data.mapping.PropertyReferenceException: 未找到 属性 自定义成员类型!
public interface MemberRepositoryCustom {
public void customize(QuerydslBindings bindings, QMember member);
}
public class MemberRepositoryCustomImpl implements MemberRepositoryCustom {
@Override
public void customize(QuerydslBindings bindings, QMember member) {
bindings.bind(member.forename).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String value) {
return path.like(value);
}
});
bindings.bind(member.surname).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String value) {
return path.startsWith(value);
}
});
}
}
您可以使用
BooleanBuilder
import com.mysema.query.BooleanBuilder;
构造queryDsl谓词
QUser quser=QUser.User;
BooleanBuilder whereClause=new BooleanBuilder();
whereClause.and(quser.property1.eq("some"));
whereClause.and(quser.property2.in(listOfValues));
springRepository.find(whereClause);
脚注:java 8 将有助于减少上述情况下的大量击键
有两种方法可以使用 Java 7 完成此操作。第一种方法是创建一个通用基础存储库,它将自定义绑定应用于所有已实现的模型存储库。例如:
public class GenericModelRepository<T, ID extends Serializable, S extends EntityPath<T>> extends QueryDslJpaRepository<T, ID> implements QuerydslBinderCustomizer<S> {
public GenericModelRepository(
JpaEntityInformation<T, ID> entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
}
public GenericModelRepository(
JpaEntityInformation<T, ID> entityInformation,
EntityManager entityManager,
EntityPathResolver resolver) {
super(entityInformation, entityManager, resolver);
}
@Override
public void customize(QuerydslBindings bindings, S t) {
bindings.bind(String.class).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String s) {
return path.equalsIgnoreCase(s);
}
});
}
}
要告诉 Spring 数据在实现所有自定义存储库接口时使用此基础存储库,只需将其添加为 @EnableJpaRepositories
注释中的 repositoryBaseClass
:
@Configuration
@EnableJpaRepositories(basePackages = { "me.woemler.project.repositories" }, repositoryBaseClass = GenericModelRepository.class)
@EnableTransactionManagement
public class RepositoryConfig { ... }
@RepositoryRestResource
public interface PersonRepository extends JpaRepository<Person, Long>,
QueryDslPredicateExecutor<Person>,
QuerydslBinderCustomizer<EntityPath<Person>> {
}
现在所有 Web 服务 StringPath
查询操作都将进行不区分大小写的相等性测试:
GET http://localhost:8080/persons?name=joe%20smith
"_embedded": {
"persons": [
{
"name": "Joe Smith",
"gender": "M",
"age": 35,
"_links": {
"self": {
"href": "http://localhost:8080/persons/1"
},
"person": {
"href": "http://localhost:8080/persons/1"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/persons"
},
"profile": {
"href": "http://localhost:8080/profile/persons"
}
},
"page": {
"size": 20,
"totalElements": 1,
"totalPages": 1,
"number": 0
}
}
如果您希望更好地控制每个存储库处理其绑定的方式,第二个选项是创建您希望自定义的存储库的 Impl
版本:
public class PersonRepositoryImpl implements QuerydslBinderCustomizer<EntityPath<Person>> {
@Override
public void customize(QuerydslBindings bindings, EntityPath<Person> t) {
bindings.bind(String.class).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String s) {
return path.equalsIgnoreCase(s);
}
});
}
}
然后您可以正常使用 @EnableJpaRepositories
注释,但是您必须为每个要自定义的存储库接口创建一个 Impl
实例。
我有一个 Spring Data Rest 存储库,它利用此处概述的 QueryDSL 支持:
https://spring.io/blog/2015/09/04/what-s-new-in-spring-data-release-gosling#spring-data-rest
默认使用equals查询所有指定的参数。同一篇文章中给出了一种覆盖参数绑定到除 equals 之外的东西的机制,但是它需要 Java 8.
https://spring.io/blog/2015/09/04/what-s-new-in-spring-data-release-gosling#querydsl-web-support
Java7 中是否有任何干净的方法来实现相同的功能?
更新
我可以让绑定自定义工作如下:
@Override
public void customize(QuerydslBindings bindings, QMember member) {
bindings.bind(member.forename).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String value) {
return path.like(value);
}
});
bindings.bind(member.surname).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String value) {
return path.startsWith(value);
}
});
}
然而,这些示例都在存储库界面上使用 Java 8 默认方法来应用它们。
public interface MemberRepository extends JpaRepository<Member, Long>,
QueryDslPredicateExecutor<Member>,QuerydslBinderCustomizer<QMember> {
default void customize(QuerydslBindings bindings, QMember member) {
....
}
}
在Java7中这显然是不可能的。我尝试使用自定义存储库,但失败并出现错误:
org.springframework.data.mapping.PropertyReferenceException: 未找到 属性 自定义成员类型!
public interface MemberRepositoryCustom {
public void customize(QuerydslBindings bindings, QMember member);
}
public class MemberRepositoryCustomImpl implements MemberRepositoryCustom {
@Override
public void customize(QuerydslBindings bindings, QMember member) {
bindings.bind(member.forename).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String value) {
return path.like(value);
}
});
bindings.bind(member.surname).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String value) {
return path.startsWith(value);
}
});
}
}
您可以使用
BooleanBuilder
import com.mysema.query.BooleanBuilder;
构造queryDsl谓词
QUser quser=QUser.User;
BooleanBuilder whereClause=new BooleanBuilder();
whereClause.and(quser.property1.eq("some"));
whereClause.and(quser.property2.in(listOfValues));
springRepository.find(whereClause);
脚注:java 8 将有助于减少上述情况下的大量击键
有两种方法可以使用 Java 7 完成此操作。第一种方法是创建一个通用基础存储库,它将自定义绑定应用于所有已实现的模型存储库。例如:
public class GenericModelRepository<T, ID extends Serializable, S extends EntityPath<T>> extends QueryDslJpaRepository<T, ID> implements QuerydslBinderCustomizer<S> {
public GenericModelRepository(
JpaEntityInformation<T, ID> entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
}
public GenericModelRepository(
JpaEntityInformation<T, ID> entityInformation,
EntityManager entityManager,
EntityPathResolver resolver) {
super(entityInformation, entityManager, resolver);
}
@Override
public void customize(QuerydslBindings bindings, S t) {
bindings.bind(String.class).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String s) {
return path.equalsIgnoreCase(s);
}
});
}
}
要告诉 Spring 数据在实现所有自定义存储库接口时使用此基础存储库,只需将其添加为 @EnableJpaRepositories
注释中的 repositoryBaseClass
:
@Configuration
@EnableJpaRepositories(basePackages = { "me.woemler.project.repositories" }, repositoryBaseClass = GenericModelRepository.class)
@EnableTransactionManagement
public class RepositoryConfig { ... }
@RepositoryRestResource
public interface PersonRepository extends JpaRepository<Person, Long>,
QueryDslPredicateExecutor<Person>,
QuerydslBinderCustomizer<EntityPath<Person>> {
}
现在所有 Web 服务 StringPath
查询操作都将进行不区分大小写的相等性测试:
GET http://localhost:8080/persons?name=joe%20smith
"_embedded": {
"persons": [
{
"name": "Joe Smith",
"gender": "M",
"age": 35,
"_links": {
"self": {
"href": "http://localhost:8080/persons/1"
},
"person": {
"href": "http://localhost:8080/persons/1"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/persons"
},
"profile": {
"href": "http://localhost:8080/profile/persons"
}
},
"page": {
"size": 20,
"totalElements": 1,
"totalPages": 1,
"number": 0
}
}
如果您希望更好地控制每个存储库处理其绑定的方式,第二个选项是创建您希望自定义的存储库的 Impl
版本:
public class PersonRepositoryImpl implements QuerydslBinderCustomizer<EntityPath<Person>> {
@Override
public void customize(QuerydslBindings bindings, EntityPath<Person> t) {
bindings.bind(String.class).first(new SingleValueBinding<StringPath, String>() {
@Override
public Predicate bind(StringPath path, String s) {
return path.equalsIgnoreCase(s);
}
});
}
}
然后您可以正常使用 @EnableJpaRepositories
注释,但是您必须为每个要自定义的存储库接口创建一个 Impl
实例。