【问题标题】:How to easy implement 'REST API query language' with Querydsl and Spring Data to filter the entities?如何使用 Querydsl 和 Spring Data 轻松实现“REST API 查询语言”来过滤实体?
【发布时间】:2018-12-10 04:01:35
【问题描述】:

如何使用 Spring Data 轻松实现一种“REST API 查询语言”来过滤实体?

例如,对于以下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 降序排序。

【问题讨论】:

    标签: spring rest spring-boot spring-data querydsl


    【解决方案1】:

    借助Querydsl Web SupportWeb support Spring Data extension 的一部分,我们可以轻松实现一种“REST API 查询语言”来过滤我们的实体。

    我们只需要做到以下几点:

    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 Support,我们必须将这些依赖项和插件添加到我们的 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-classes”。

    您可以在我的 repo 中找到完整的示例演示:sb-querydsl-sd-demo,以及此演示的 Postman API-docs - 这里:REST query language with Querydsl and Spring Data

    【讨论】:

    • 如果 "GET /people?age=18" 返回所有 18 岁或以上的人。如何获得所有18岁的人?就像那个“GET /people?age=18&age=18”?
    • @SvenDöring 是的,你是对的。也许我关于这个主题的其他帖子也会有用:stackoverflow.com/a/55761257stackoverflow.com/a/55978161
    猜你喜欢
    • 2014-06-21
    • 2018-10-15
    • 1970-01-01
    • 2020-06-05
    • 1970-01-01
    • 2016-05-12
    • 2021-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多