Spring - QueryDsl 支持的高级比较器

Posted

技术标签:

【中文标题】Spring - QueryDsl 支持的高级比较器【英文标题】:Spring - Advanced comparator for QueryDsl support 【发布时间】:2016-12-26 15:11:12 【问题描述】:

在official documentation 之后,将@EnableSpringDataWebSupport 注释添加到我的Spring 配置允许在查询中自动注入Predicate 类:

@RequestMapping(method = RequestMethod.GET, path="/find")
public ResponseEntity<PagedResources<FooResource>> find(Pageable pageable, PagedResourcesAssembler<Foo> assembler, @QuerydslPredicate(root = Foo.class) Predicate predicate) 
    Page<Foo> foos = fooRepository.findAll(predicate, pageable)
    final ResourceAssemblerSupport<Foo, FooResource> fooResourceAssembler = new ....;
    final PagedResources<FooResource> pagedResources = assembler.toResource(foos, fooResourceAssembler);
    return new ResponseEntity<>(pagedResources, HttpStatus.OK);

那么我在执行GET请求的时候就可以轻松搜索了:

GET /foo/name?=bob&name=alice&age=20

这很好用。但是我想知道如何实现更高级的搜索条件:

&gt; &lt; &gt;= &lt;=

通常我想将这些运算符应用于我的数据模型中的数字和日期字段。 Querydsl 支持这类标准。

我尝试在查询参数中添加&gt; (%3E),但解析失败(例如,对于像年龄这样的数字字段,它抱怨它无法将&gt;10 解析为数字。

是否可以直接在查询中使用该运算符?

(以防万一我使用 Spring Data Mongodb)

【问题讨论】:

你有没有找到实现这个的方法?我一直在尝试实现类似的东西,但没有成功。 @woemler 我实际上已经暂时搁置了这个问题,但它并没有消失。我想我最终会编写自己的代码来解析查询参数。我需要检查是否有一种简单的方法可以将其与弹簧注射机构集成。当我开始这样做时,我可能会在 spring github 存储库上寻求建议。如果我发现一些有趣的东西,会在这里写下来作为答案 @phoenix7360 有什么事吗?我也想这样做,但仍然使用@QuerydslPredicate @StopHarmingMonica 不幸的是我从来没有做到这一点,只是放弃了:/ @phoenix7360 Spring Data Querydsl 值运算符库执行此操作... 【参考方案1】:

自定义查询 DSL 绑定 - 大于比较

您可以通过扩展QueryDslPredicateExecutorQuerydslBinderCustomizer 在存储库中定义自己的QueryDSL 绑定:

public interface FooRepository
        extends CrudRepository<Foo, Integer>, QueryDslPredicateExecutor<Foo>, QuerydslBinderCustomizer<QFoo> 

    default void customize(final QuerydslBindings bindings, final QFoo foo) 
        SingleValueBinding<NumberPath<Integer>, Integer> singleBinding = new SingleValueBinding<NumberPath<Integer>,Integer>()
            @Override
            public Predicate bind(NumberPath<Integer> path, Integer ageValue) 
                return path.gt(ageValue);
            
        ;

        bindings.bind(foo.age).first(singleBinding);
    

我不是 Query DSL 专家,但我的理解如下:

绑定定义如何将特定字段与其进行比较 数据库列。

与 java 8 lambda 相同的绑定:(path, ageValue) -&gt; path.gt(ageValue)。您必须从 url 参数的角度阅读自定义方法中的代码:

获取作为参数提供的年龄大于的 Foos 数据库的值。

自定义查询 DSL 绑定 - 比较

另一个选项是为您的参数提供下限和上限,例如:?age=10&amp;age=30。然后,定义以下绑定:

default void customize(final QuerydslBindings bindings, final QFoo foo) 
    bindings.bind(foo.age).all((path, values) -> 
        Iterator<? extends Long> it = values.iterator();
        return path.between(it.next(), it.next());
    );

【讨论】:

这很有趣。唯一的问题是这不允许自定义表达式的实际解析。由于数据类型的设置方式,不可能有一个 int 字段而是解析一个字符串(例如包含“>”)。这似乎是春天的限制。 @alexbt 嘿,您的提示对我非常有用。但在我的情况下,我需要为 gt、eq 和 lt 做一个年龄过滤器。我尝试使用它们各自的 singleBinding (gt, eq, lt) 为年龄属性提供不同的别名。但似乎一个属性不能有多个别名。你知道我如何将 gt、eq 和 lt 用于相同的属性吗?谢谢。

以上是关于Spring - QueryDsl 支持的高级比较器的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot + Querydsl 框架,大大简化复杂查询操作!!

比较 Querydsl、jOOQ、JEQUEL、activejdbc、iciql 和其他查询 DSL

Spring QueryDsl 分页过滤器按 ACL 权限

通过 REST 控制器使用 Spring Data JPA 和 QueryDsl 的异常

Spring 数据规范或 QueryDSL

直接从querydsl更新数据时如何刷新Spring JPA?