如何使用 Spring Data 轻松实现一种“ REST API查询语言” 以过滤实体?
例如,对于以下Person实体:
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; } }
我想通过这样的请求获取其数据:
GET /people?name=jo&age=18&page=1&sort=name,desc
即:“获取所有name包含“ jo”(不区分大小写)且age等于18的人的第一页,name以降序排列。
name
age
借助Querydsl Web支持(Web支持Spring数据扩展)的一部分,我们可以轻松实现一种“ REST API查询语言”来过滤我们的实体。
我们需要做的是:
1)扩大我们的资料库QuerydslPredicateExecutor,
QuerydslPredicateExecutor
2)将Predicate带有注释的@QuerydslPredicate参数添加到我们的REST控制器方法中
Predicate
@QuerydslPredicate
3)findAll在存储库的方法中使用此谓词:
findAll
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))); } }
然后,我们将能够请求我们的数据:
GET /people?name=John&age=18&page=1&sort=name,desc
接下来,我们必须创建不区分大小写的“ like”过滤器。为此,我们从扩展仓库QuerydslBinderCustomizer并覆盖其customize方法(在仓库中):
QuerydslBinderCustomizer
customize
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我们的控制器的方法:
bindings
@GetMapping public ResponseEntity getFiltered( @QuerydslPredicate(root = Person.class, bindings = PersonRepo.class) Predicate predicate, Pageable pageable ) { return ResponseEntity.ok(personRepo.findAll(predicate, pageable))); }
现在,我们可以按照问题中的要求获取数据:
使用QuerydslBinderCustomizer我们可以实现更复杂的过滤器,例如between和greater or equal过滤器(将此代码添加到customize方法中):
between
greater or equal
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参数- 我们将获得年龄大于或等于该值的记录。
GET /people?age=18&age=30
… 让所有年龄在18至30岁之间的人
GET /people?age=18
… 让所有年龄大于或等于18岁的人
最后,我们可以从过滤器中排除一些不必要的属性,例如实体id(将此代码添加到customize方法中):
id
bindings.excluding(person.id);
要使用Querydsl Web支持,我们必须将以下依赖项和插件添加到我们的Spring Boot项目中:
<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类”。
您可以在我的仓库中找到完整的示例演示:sb- querydsl-sd-demo和该演示的Postman API文档-在这里:带有Querydsl和Spring Data的REST查询语言。