如何使用 Querydsl 和 Spring Data 轻松实现“REST API 查询语言"来过滤实体? [英] How to easy implement 'REST API query language' with Querydsl and Spring Data to filter the entities?
问题描述
如何使用 Spring Data 轻松实现一种REST API 查询语言"来过滤实体?
How to easy implement a kind of 'REST API query language' with Spring Data to filter the entities?
例如,对于以下 Person
实体:
For example, for the following Person
entity:
@Data
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
private LocalDate dob; // date of birth
private String name;
@Formula("timestampdiff('year', dob, now())")
private Integer age;
public Person(String name, LocalDate dob) {
this.name = name;
this.dob = dob;
}
}
我想通过这样的请求获取它的数据:
I would like to get its data with such a request:
GET /people?name=jo&age=18&page=1&sort=name,desc
ie: '获取name
中包含jo"(不区分大小写)且age
等于18的所有人的第一页,按排序名称
按降序排列'.
I.e.: 'get the 1st page of all people whose name
contains "jo" (case insensitive) and whose age
is equal to 18, sorting by name
in descending order'.
推荐答案
借助Querydsl Web Support,Web 支持 Spring Data 扩展,我们可以轻松实现一种REST API 查询语言"来过滤我们的实体.
With help of Querydsl Web Support, the part of Web support Spring Data extension, we can easy implement a kind of 'REST API query language' to filter our entities.
我们只需要做到以下几点:
All we need is do the following:
1) 从 QuerydslPredicateExecutor
扩展我们的存储库,
1) extend our repository from QuerydslPredicateExecutor
,
2) 将带有注释 @QuerydslPredicate
的 Predicate
作为参数添加到我们的 REST 控制器方法中
2) add Predicate
with annotation @QuerydslPredicate
, as argument, to our REST controller method
3) 在存储库的 findAll
方法中使用此谓词:
3) use this predicate in findAll
method of the repository:
public interface PersonRepo extends JpaRepository<Person, Long>, QuerydslPredicateExecutor<Person> {
}
@RequiredArgsConstructor
@RestController
@RequestMapping("/people")
public class PersonController {
private final PersonRepo personRepo;
@GetMapping
public ResponseEntity getFiltered(@QuerydslPredicate(root = Person.class) Predicate predicate, Pageable pageable) {
return ResponseEntity.ok(personRepo.findAll(predicate, pageable)));
}
}
然后我们就可以请求我们的数据了:
Then we will be able to request our data:
GET /people?name=John&age=18&page=1&sort=name,desc
接下来我们必须制作不区分大小写的like"过滤器.为此,我们从 QuerydslBinderCustomizer
扩展我们的 repo 并覆盖它的 customize
方法(就在 repo 中):
Next we have to make case insensitive 'like' filter. To do this we extend our repo from QuerydslBinderCustomizer
and override its customize
method (right in the repo):
public interface PersonRepo extends
JpaRepository<Person, Long>,
QuerydslPredicateExecutor<Person>,
QuerydslBinderCustomizer<QPerson> {
@Override
default void customize(QuerydslBindings bindings, QPerson person) {
// Make case-insensitive 'like' filter for all string properties
bindings.bind(String.class).first((SingleValueBinding<StringPath, String>) StringExpression::containsIgnoreCase);
}
}
为了使它起作用,我们必须将参数 bindings
添加到控制器方法的 @QuerydslPredicate
中:
To make it works we have to add parameter bindings
to @QuerydslPredicate
of our controller method:
@GetMapping
public ResponseEntity getFiltered(
@QuerydslPredicate(root = Person.class, bindings = PersonRepo.class) Predicate predicate,
Pageable pageable
) {
return ResponseEntity.ok(personRepo.findAll(predicate, pageable)));
}
现在我们可以按照问题中的要求请求我们的数据:
Now we can request our data as asked in the question:
GET /people?name=jo&age=18&page=1&sort=name,desc
使用 QuerydslBinderCustomizer
我们可以实现更复杂的过滤器,例如 between
和 greater or equal
过滤器(将此代码添加到 customize
方法):
With QuerydslBinderCustomizer
we can implement more complex filters, for example between
and greater or equal
filters (add this code to customize
method):
bindings.bind(person.age).all((path, value) -> {
Iterator<? extends Integer> it = value.iterator();
Integer from = it.next();
if (value.size() >= 2) {
Integer to = it.next();
return Optional.of(path.between(from, to)); // between
} else {
return Optional.of(path.goe(from)); // greater or equal
}
});
如果我们在请求中指定两个 age
参数,那么我们将获得年龄在这些参数之间的所有记录.如果我们只指定一个 age
参数 - 我们会得到年龄大于或等于该值的记录.
If we specify two age
parameters in the request then we get all records with the age between these parameters. If we specify only one age
parameter - we get records with the age is greater or equal that value.
GET /people?age=18&age=30
...获取所有年龄在 18 到 30 岁之间的人
GET /people?age=18
...获取所有年龄大于或等于 18 岁的人
最后我们可以从过滤器中排除一些不必要的属性,例如实体id
(将此代码添加到customize
方法中):
In the end we can exclude some unnecessary properties from the filter, for example the entity id
(add this code to customize
method):
bindings.excluding(person.id);
要使用 Querydsl Web Support,我们必须将这些依赖项和插件添加到我们的 Spring Boot 项目中:
To use Querydsl Web Support we have to add these dependencies and plugin to our Spring Boot project:
<dependencies>
<!-- ... -->
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- ... -->
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/annotations</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
然后,重要的是,编译项目以构建我们实体的Q-classes".
Then, it's important, compile the project to build 'Q-classes' of our entities.
您可以在我的 repo 中找到完整的示例演示:sb-querydsl-sd-demo 和 Postman 此演示的 API 文档 - 此处:带有 Querydsl 和 Spring Data 的 REST 查询语言.
Full example demo you can find in my repo: sb-querydsl-sd-demo, and Postman API-docs of this demo - here: REST query language with Querydsl and Spring Data.
这篇关于如何使用 Querydsl 和 Spring Data 轻松实现“REST API 查询语言"来过滤实体?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!