如何使用 Querydsl 和 Spring 数据轻松实现 'REST API query language' 来过滤实体?

How to easy implement 'REST API query language' with Querydsl and Spring Data to filter the entities?

如何使用 Spring 数据 轻松实现一种 'REST API query language' 来过滤实体?

例如,对于以下 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

即:'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, the part of Web support Spring Data extension 的帮助下,我们可以轻松实现一种 'REST API query language' 来过滤我们的实体。

我们只需要执行以下操作:

1) 从 QuerydslPredicateExecutor

扩展我们的存储库

2) 将带有注释 @QuerydslPredicatePredicate 作为参数添加到我们的 REST 控制器方法

3) 在存储库的 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 扩展我们的 repo 并覆盖其 customize 方法(就在 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

@GetMapping
public ResponseEntity getFiltered(
    @QuerydslPredicate(root = Person.class, bindings = PersonRepo.class) Predicate predicate, 
    Pageable pageable
) {
    return ResponseEntity.ok(personRepo.findAll(predicate, pageable)));
}

现在我们可以按照问题中的要求请求我们的数据:

GET /people?name=jo&age=18&page=1&sort=name,desc

使用QuerydslBinderCustomizer我们可以实现更复杂的过滤器,例如betweengreater or equal过滤器(将此代码添加到customize方法):

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方法):

bindings.excluding(person.id);

要使用 Querydsl Web 支持,我们必须将这些依赖项和插件添加到我们的 Spring 引导项目中:

<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' 我们的实体。

您可以在我的存储库中找到完整的示例演示:sb-querydsl-sd-demo, and Postman API-docs of this demo - here: REST query language with Querydsl and Spring Data