如何使用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
实体:
@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
即:获取所有name
包含"jo"(不区分大小写)且age
等于18的所有人的第一页,并按name
降序排列."
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'.
推荐答案
在网络支持Spring数据扩展,我们可以轻松实现一种"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
扩展
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
接下来,我们必须创建不区分大小写的喜欢"过滤器.为此,我们从QuerydslBinderCustomizer
扩展了仓库,并覆盖了customize
方法(在仓库中):
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);
}
}
要使其正常工作,我们必须在控制器方法的@QuerydslPredicate
中添加参数bindings
:
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支持,我们必须将以下依赖项和插件添加到我们的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类".
Then, it's important, compile the project to build 'Q-classes' of our entities.
您可以在我的仓库中找到完整的示例演示: sb-querydsl-sd-demo 和邮递员此演示的API文档-此处:
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屋!