我在Spring Boot项目中使用QueryDSL并计划使用Spring的Web支持(current query dsl web docs)。问题是,我无法找到使用不同运营商的任何信息。如何定义not equals
或matches regex
操作?乍一看,它只是将您的?fieldname=value
格式GET
请求转换为您在存储库中设置的预定义操作。我可以以允许同一字段的多个操作的方式扩展它吗?
示例:
目前,我可以通过传递URL参数来获取QueryDsl Predicate
,例如?user.company.id=1
:
@Controller
class UserController {
@Autowired UserRepository repository;
@RequestMapping(value = "/", method = RequestMethod.GET)
Page<User> getUsers(@QuerydslPredicate(root = User.class) Predicate predicate,
Pageable pageable) {
return repository.findAll(predicate, pageable);
}
}
但是,由于我链接的文档状态,我只能为某个字段定义单个操作。如果我想要用户,user.lastName
从哪里开始并且仍然可以查询完全匹配的内容,该怎么办? (?lastName=Xyz,contains
和?lastName=Xyz,equals
也许)
QuerydslBinderCustomizer
定义每个字段的操作,但您只能定义如何处理该特定字段,不可能添加多个操作。
也许我不能用QueryDSL做到这一点,但是一般在Spring启动时如何将过滤器应用于搜索查询?
答案 0 :(得分:3)
我正在做那样的事情。虽然我尝试做更复杂的动作时遇到了一些限制。我在一些步骤中做了什么:
MyBinderCustomizer<T extends EntityPath<?>>
的新界面QuerydslBinderCustomizer<QUser>
(请注意用户的Q,您需要QueryDSL自动生成的类而不是您的实体。)customize
方法。例如:
@Override
public default void customize(QuerydslBindings bindings, T root) {
bindings.bind(String.class).all(MyBinderCustomizer::applyStringComparison);
}
static BooleanExpression applyStringComparison(Path<String> path, Collection<? extends String> strings) {
BooleanExpression result = null;
for (String s : strings) {
try {
final String[] parts = s.split(",");
final String operator = parts[0];
final String value = parts.length > 1 ? parts[1] : null;
final Method method = Arrays.stream(path.getClass().getMethods())
.filter(m -> operator.equals(m.getName()))
.filter(m -> BooleanExpression.class.equals(m.getReturnType()))
.filter(m -> m.getParameterTypes().length == (value == null ? 0 : 1))
.filter(m -> value == null || m.getParameterTypes()[0].equals(String.class) || m.getParameterTypes()[0].equals(Object.class))
.findFirst().get();
final BooleanExpression be;
if (value == null) {
be = (BooleanExpression) method.invoke(path);
} else {
be = (BooleanExpression) method.invoke(path, value);
}
result = result == null ? be : result.and(be);
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
return result;
}
MyBinderCustomizer<QUser>
(再次注意Q)。这将允许您使用这些操作:
public BooleanExpression StringExpression.like(java.lang.String) public BooleanExpression StringExpression.notLike(java.lang.String) public BooleanExpression StringExpression.notEqualsIgnoreCase(java.lang.String) public BooleanExpression StringExpression.containsIgnoreCase(java.lang.String) public BooleanExpression StringExpression.likeIgnoreCase(java.lang.String) public BooleanExpression StringExpression.startsWithIgnoreCase(java.lang.String) public BooleanExpression StringExpression.endsWithIgnoreCase(java.lang.String) public BooleanExpression StringExpression.equalsIgnoreCase(java.lang.String) public BooleanExpression StringExpression.startsWith(java.lang.String) public BooleanExpression StringExpression.endsWith(java.lang.String) public BooleanExpression StringExpression.matches(java.lang.String) public BooleanExpression StringExpression.contains(java.lang.String) public BooleanExpression StringExpression.isEmpty() public BooleanExpression StringExpression.isNotEmpty() public BooleanExpression SimpleExpression.isNull() public BooleanExpression SimpleExpression.isNotNull() public BooleanExpression SimpleExpression.ne(java.lang.Object) public BooleanExpression SimpleExpression.eq(java.lang.Object)
答案 1 :(得分:0)
Spring Data QueryDSL Value Operators库扩展了Spring Data QueryDSL web support的操作符,不仅适用于字符串字段,而且还包含数字和枚举字段。它需要一些特殊的配置才能使其适用于非String字段,如here所述:
值运算符在基于字符串的属性/字段上似乎工作得很顺利。但是,这些运算符不适用于Number或Enum之类的非字符串值,因为默认情况下
QuerydslPredicateArgumentResolver
解析注释QuerydslPredicate
,该注释用于注释RESTful方法(也称为RestController方法)上的搜索处理方法,根据Querydsl的指导设计原理执行强类型化,即,它尝试将从HTTP请求接收的值转换为在相应Q类中定义的确切类型。在没有值运算符的情况下,此方法效果很好,并且与Querydsl承诺允许类型安全查询的承诺保持一致,但阻碍了值运算符完成其任务的路径。
该库提供了两种方法来使运算符适用于非字符串字段:
QuerydslPredicateArgumentResolver
中替换ConversionService,以便将所有查询参数都视为String(失去强类型)这两种方法以及它们的用例和缺点都有很好的记录。
我目前正在评估方法1,因为它适合我们的用例,但是我需要扩展它以容纳DateTime字段以及一些自定义运算符。
答案 2 :(得分:0)
https://bitbucket.org/gt_tech/spring-data-querydsl-value-operators/src/master/
这里的文档说:
QuerydslPredicateArgumentResolver使用ConversionService进行类型转换。由于String到Enum或String到Integer的转换是Spring依赖项注入的核心,因此不建议更改这些默认的内置转换器(永远不要这样做)。该库提供了BeanPostProcessor和ServletFilter的实验性组合,可以在目标应用程序的上下文中对其进行显式配置,以禁用QuerydslPredicateArgumentResolver尝试的强类型转换。
因此,要实现此目的,您需要将其添加到应用程序上下文中:
/**
* Note the use of delegate ConversionService which comes handy for types like
* java.util.Date for handling powerful searches natively with Spring data.
* @param factory QuerydslBindingsFactory instance
* @param conversionServiceDelegate delegate ConversionService
* @return
*/
@Bean
public QuerydslPredicateArgumentResolverBeanPostProcessor querydslPredicateArgumentResolverBeanPostProcessor(
QuerydslBindingsFactory factory, DefaultFormattingConversionService conversionServiceDelegate) {
return new QuerydslPredicateArgumentResolverBeanPostProcessor(factory, conversionServiceDelegate);
}
让我知道是否有人成功实现了这种实验性功能。