我正在尝试使用Spring Data REST,到目前为止,它进展得还算不错。我能够查询和操作实体,并且已经达到要通过可变数量的参数过滤检索到的数据的地步。为此,我已经阅读并决定使用QueryDSL which is integrated nicely with Spring,使用实体中的字段时,它几乎(几乎)可以正常工作。
但是,我的过滤表单包含一些没有直接映射到实体的参数,从而导致了这个问题。为了简洁起见,我将使用一个过于简化的示例,因此我使用的是人的年龄而不是出生日期等。
假设我们有以下Person
实体:
@Data
@NoArgsConstructor
@Entity
public class Person {
@Id
@GeneratedValue
private UUID id;
private String name;
private String lastName;
private Integer age;
}
...和适当的回购
@RepositoryRestResource
public interface PersonRepository extends CrudRepository<Person,UUID>,QuerydslPredicateExecutor<Person>,QuerydslBinderCustomizer<QPerson> {
@RestResource
Page<Person> findAll(@QuerydslPredicate Predicate predicate,Pageable pageable);
@Override
default void customize(QuerydslBindings bindings,QPerson person) {
bindings.bind(String.class).first((SingleValueBinding<StringPath,String>) StringExpression::containsIgnoreCase);
}
}
...到目前为止,人们可以通过http://<server>/persons?name=whatever
按姓名或姓氏(不区分大小写)访问和过滤人员。
下一步,我只想看到65岁以上的“可养老金”人群,因此URL看起来像http://<server>/persons?pensionable=true
。但是,pensionable
不是Person
实体中的属性,因此将其添加为请求参数不会执行任何操作。
我一直试图弄清楚如何实现此目标,或者当前是否是框架的局限性,但到目前为止,我的搜索尚未成功。最终通过反复试验,我想出了一些似乎可行的方法,但感觉更像是黑客:
创建另一个包含额外/任意参数的PersonExtendedFilter
bean(不是实体):
@Data
@NoArgsConstructor
public class PersonExtendedFilter{
private Boolean pensionable;
}
...使用上面的方法创建一个BooleanPath
,并使用它在存储库的customize
方法内定义绑定:
@Override
default void customize(QuerydslBindings bindings,QPerson person) {
bindings.bind(String.class).first((SingleValueBinding<StringPath,String>) StringExpression::containsIgnoreCase);
BooleanPath pensionable = new PathBuilder<>(PersonExtendedFilter.class,"personExtendedFilter").getBoolean("pensionable");
bindings.bind(pensionable).first((path,value) -> new BooleanBuilder().and(value ? person.age.gt(65) : person.age.loe(65)));
}
最重要的是,我想知道是否有一种优雅的方法来做到这一点,或者我是否缺少某些东西,无论是逻辑POV,RTFM还是其他东西。