注解很方便,但是想要灵活动态起来就不太方便了。想做一个灵活的通用查询方法,查询参数可以是数据库该表的所有属性,不灵活通用的用@QuerydslPredicate就可以实现,灵活起来就不行了

@QuerydslPredicate是根据GET请求的参数来转换成QueryDsl所需要的Predicate

SpringMvc方法的参数上注入NativeWebRequest webRequest

代码:

// 实体类全类名
Class<?> clazz = Class.forName("me.kuku.xx");
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
for (Map.Entry<String, String[]> entry : webRequest.getParameterMap().entrySet()) {
    parameters.put(entry.getKey(), Arrays.asList(entry.getValue()));
}
// 从Spring容器中获取该对象,自动注入会异常,是在依赖注入流程之后初始化完成的,只能手动去获取
QuerydslPredicateArgumentResolver resolver = SpringContextHolder.getBean(QuerydslPredicateArgumentResolver.class);
// 反射获取私有属性
Class<? extends QuerydslPredicateArgumentResolver> resolverClass = resolver.getClass();
Field bindingsFactoryField = resolverClass.getDeclaredField("bindingsFactory");
bindingsFactoryField.setAccessible(true);
QuerydslBindingsFactory bindingsFactory = (QuerydslBindingsFactory) bindingsFactoryField.get(resolver);
Field predicateBuilderField = resolverClass.getDeclaredField("predicateBuilder");
predicateBuilderField.setAccessible(true);
// Spring 源码中的操作,直接搬过来
QuerydslPredicateBuilder predicateBuilder = (QuerydslPredicateBuilder) predicateBuilderField.get(resolver);
ClassTypeInformation<?> classTypeInformation = ClassTypeInformation.from(clazz);
// @QuerydslPredicate注解中的bindings
QuerydslBindings bindings;
try {
    Class<?> bindClazz = Class.forName("$Binder的全类名");
    bindings = bindingsFactory.createBindingsFor(classTypeInformation, (Class<? extends QuerydslBinderCustomizer<?>>) bindClazz);
} catch (Exception e) {
    bindings = bindingsFactory.createBindingsFor(ClassTypeInformation.from(clazz));
}
Predicate result = predicateBuilder.getPredicate(classTypeInformation, parameters, bindings);
if (result == null) result = new BooleanBuilder();

获取到了Predicate,就可以通过Querydsl进行查询了。

最后修改:2022 年 11 月 16 日
如果觉得我的文章对你有用,请随意赞赏