且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Spring Boot &JPA:使用可选的范围条件实现搜索查询

更新时间:2022-05-09 17:38:10

你可以在 spring 数据中通过 JpaSpecificationExecutor 实现复杂的有规范的查询.存储库接口必须扩展 JpaSpecificationExecutor 接口,以便我们可以通过创建新的 Specification 对象来指定数据库查询的条件.

You can achieve complex queries with specifications by JpaSpecificationExecutor in spring data. Repository interface must extend the JpaSpecificationExecutor<T> interface so we can specify the conditions of our database queries by creating new Specification<T> objects.

诀窍在于将 Specification 接口与 JpaSpecificationExecutor 结合使用.这是示例:

The trick is in the use of the Specification interface in combination with a JpaSpecificationExecutor. here is the example:

@Entity
@Table(name = "person")
public class Person {

 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private Long id;

 @Column(name = "name")
 private String name;

 @Column(name = "surname")
 private String surname;

 @Column(name = "city")
 private String city;

 @Column(name = "age")
 private Integer age;

        ....

}

然后我们定义我们的存储库:

Then we define our repository:

public interface PersonRepository extends JpaRepository<Person, Long>, JpaSpecificationExecutor<Person> {

}

如您所见,我们扩展了另一个接口 JpaSpecificationExecutor.该接口定义了通过规范类执行搜索的方法.

As you can see we have extended another interface the JpaSpecificationExecutor. This interface defines the methods to perform the search via a Specification class.

我们现在要做的是定义我们的规范,该规范将返回包含查询约束的Predicate(在示例中,PersonSpecification 正在执行查询选择* 来自姓名 = ? 或(姓氏 = ? 和年龄 = ?) 的人):

What we have to do now is to define our specification that will return the Predicate containing the constraints for the query (in the example the PersonSpecification is performing the query select * from person where name = ? or (surname = ? and age = ?) ):

public class PersonSpecification implements Specification<Person> {

    private Person filter;

    public PersonSpecification(Person filter) {
        super();
        this.filter = filter;
    }

    public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> cq,
            CriteriaBuilder cb) {

        Predicate p = cb.disjunction();

        if (filter.getName() != null) {
            p.getExpressions()
                    .add(cb.equal(root.get("name"), filter.getName()));
        }

        if (filter.getSurname() != null && filter.getAge() != null) {
            p.getExpressions().add(
                    cb.and(cb.equal(root.get("surname"), filter.getSurname()),
                            cb.equal(root.get("age"), filter.getAge())));
        }

        return p;
    }
}

现在是时候使用它了.以下代码片段展示了如何使用我们刚刚创建的规范:

Now it is time to use it. The following code fragment shows how to use the Specification we just created:

...

Person filter = new Person();
filter.setName("Mario");
filter.setSurname("Verdi");
filter.setAge(25);

Specification<Person> spec = new PersonSpecification(filter);

List<Person> result = repository.findAll(spec);

这里是 github 中的完整示例

Here is full example present in github

您还可以使用规范创建任何复杂的查询

Also you can create any complex queries using Specification