spring-data - 为 QueryDSL 支持自定义参数绑定(bind)

标签 spring-data spring-data-rest

我有一个 Spring Data Rest 存储库,它利用此处概述的 QueryDSL 支持:

https://spring.io/blog/2015/09/04/what-s-new-in-spring-data-release-gosling#spring-data-rest

默认是使用equals查询所有指定的参数。同一篇文章中给出了一种覆盖参数绑定(bind)到除 equals 之外的东西的机制,但是它需要 Java 8。

https://spring.io/blog/2015/09/04/what-s-new-in-spring-data-release-gosling#querydsl-web-support

在 Java 7 中是否有任何简洁的方法来实现相同的功能?

更新

我可以让绑定(bind)定制工作如下:

@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);
        }
    });
}

然而,这些示例都在存储库接口(interface)上使用 Java 8 默认方法来应用它们。

public interface MemberRepository extends JpaRepository<Member, Long>, 
         QueryDslPredicateExecutor<Member>,QuerydslBinderCustomizer<QMember> {

    default void customize(QuerydslBindings bindings, QMember member) {
      ....
    }
}

在 Java 7 中这显然是不可能的。我尝试使用自定义存储库,但失败并出现错误:

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);
            }
        });
    }
}

最佳答案

使用 Java 7 可以通过两种方式实现这一点。第一种方式是创建一个通用的基础存储库,它将自定义绑定(bind)应用于所有已实现的模型存储库。例如:

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 Data 在实现所有自定义存储库接口(interface)时使用此基础存储库,只需将其添加为 @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
      }
    }

第二个选项,如果你想更好地控制每个存储库如何处理它的绑定(bind),将创建一个你希望自定义的存储库的 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 注释,但是您必须为每个您希望自定义的存储库接口(interface)创建一个 Impl 实例。

关于spring-data - 为 QueryDSL 支持自定义参数绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40384132/

相关文章:

spring-data-jpa - 是否可以在 spring 数据中为关系数据库和非关系数据库创建一个存储库?

java - 自定义 Spring Data REST 生成的默认查询

java - 通过 Spring Security 和 SpEL 表达式限制 POST 和 REST 请求时出错

spring-data-neo4j - Neo4j RelationshipEntities 和 Spring Data Rest 的循环 JSON 序列化问题

java - 使用 aerospikeTemplate java 将数据插入 aerospike

hibernate - Spring Boot JPA 将架构名称外部化到属性文件

java - 在java8中迭代嵌套对象

java - Spring 数据休息 : Expose new endpoints for Repository that extends Revision Repository

javascript - 如何使用 Restangular 将我的任务添加回我的列表

spring-boot - 将自定义 header 添加到 REST PUT 请求