2017-07-06 384 views
2

是否有一种方法可以通过querydsl别名对存储库查询结果进行排序?如何按querydsl别名排序

到目前为止,我已经成功地过滤,但对结果进行排序,并显示错误:

org.springframework.data.mapping.PropertyReferenceException: No property username found for type User!

要求:

GET /users?size=1&sort=username,desc

我的休息控制器的方法:

@GetMapping("/users") 
public ListResult<User> getUsersInGroup(
     @ApiIgnore @QuerydslPredicate(root = User.class) Predicate predicate, 
     Pageable pageable) { 
    Page<User> usersInGroup = 
      userRepository.findByGroup(CurrentUser.getGroup(), predicate, pageable); 
    return new ListResult<>(usersInGroup); 
} 

我的资料库:

@Override 
default void customize(QuerydslBindings bindings, QUser root) { 
    bindings.including(root.account.login, root.account.firstName, root.account.lastName, 
      root.account.phoneNumber, root.account.email, root.account.postalCode, root.account.city, 
      root.account.address, root.account.language, root.account.presentationAlias); 
    bindAlias(bindings, root.account.login, "username"); 
} 

default Page<User> findByGroup(Group group, Predicate predicate, Pageable pageable) { 
    BooleanExpression byGroup = QUser.user.group.eq(group); 
    BooleanExpression finalPredicate = byGroup.and(predicate); 
    return findAll(finalPredicate, pageable); 
} 

default void bindAlias(QuerydslBindings bindings, StringPath path, String alias) { 
    bindings.bind(path).as(alias).first(StringExpression::likeIgnoreCase); 
} 

我也试图实现自己的PageableArgumentResolver基于QuerydslPredicateArgumentResolver,但有些方法中使用的有包私有,所以我想也许我在错误的方向

回答

2

我成功通过创建我要去一个PageableArgumentResolver使用类类型的查询根类进行了注释,并将别名注册表添加到我的通用存储库接口。

该解决方案似乎是一个解决方法,但至少它的工作原理;)

库:

public interface UserRepository extends PageableAndFilterableGenericRepository<User, QUser> { 

QDSLAliasRegistry aliasRegistry = QDSLAliasRegistry.instance(); 

@Override 
default void customize(QuerydslBindings bindings, QUser root) { 
    bindAlias(bindings, root.account.login, "username"); 
} 

default void bindAlias(QuerydslBindings bindings, StringPath path, String alias) { 
    bindings.bind(path).as(alias).first(StringExpression::likeIgnoreCase); 
    aliasRegistry.register(alias, path); 
} 

别名注册表:

public class QDSLAliasRegistry { 

private static QDSLAliasRegistry inst; 

public static QDSLAliasRegistry instance() { 
    inst = inst == null ? new QDSLAliasRegistry() : inst; 
    return inst; 
} 

private QDSLAliasRegistry() { 
    registry = HashBiMap.create(); 
} 

HashBiMap<String, Path<?>> registry; 

解析:

public class QDSLSafePageResolver implements PageableArgumentResolver { 

private static final String DEFAULT_PAGE = "0"; 
private static final String DEFAULT_PAGE_SIZE = "20"; 
private static final String PAGE_PARAM = "page"; 
private static final String SIZE_PARAM = "size"; 
private static final String SORT_PARAM = "sort"; 
private final QDSLAliasRegistry aliasRegistry; 

public QDSLSafePageResolver(QDSLAliasRegistry aliasRegistry) { 
    this.aliasRegistry = aliasRegistry; 
} 

@Override 
public boolean supportsParameter(MethodParameter parameter) { 
    return Pageable.class.equals(parameter.getParameterType()) 
      && parameter.hasParameterAnnotation(QDSLPageable.class); 
} 

@Override 
public Pageable resolveArgument(MethodParameter parameter, 
           ModelAndViewContainer mavContainer, 
           NativeWebRequest webRequest, 
           WebDataBinderFactory binderFactory) { 

    MultiValueMap<String, String> parameterMap = getParameterMap(webRequest); 

    final Class<?> root = parameter.getParameterAnnotation(QDSLPageable.class).root(); 
    final ClassTypeInformation<?> typeInformation = ClassTypeInformation.from(root); 

    String pageStr = Optional.ofNullable(parameterMap.getFirst(PAGE_PARAM)).orElse(DEFAULT_PAGE); 
    String sizeStr = Optional.ofNullable(parameterMap.getFirst(SIZE_PARAM)).orElse(DEFAULT_PAGE_SIZE); 
    int page = Integer.parseInt(pageStr); 
    int size = Integer.parseInt(sizeStr); 
    List<String> sortStrings = parameterMap.get(SORT_PARAM); 
    if(sortStrings != null) { 
     OrderSpecifier[] specifiers = new OrderSpecifier[sortStrings.size()]; 

     for(int i = 0; i < sortStrings.size(); i++) { 
      String sort = sortStrings.get(i); 
      String[] orderArr = sort.split(","); 
      Order order = orderArr.length == 1 ? Order.ASC : Order.valueOf(orderArr[1].toUpperCase()); 
      specifiers[i] = buildOrderSpecifier(orderArr[0], order, typeInformation); 
     } 

     return new QPageRequest(page, size, specifiers); 
    } else { 
     return new QPageRequest(page, size); 
    } 
} 

private MultiValueMap<String, String> getParameterMap(NativeWebRequest webRequest) { 
    MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>(); 

    for (Map.Entry<String, String[]> entry : webRequest.getParameterMap().entrySet()) { 
     parameters.put(entry.getKey(), Arrays.asList(entry.getValue())); 
    } 
    return parameters; 
} 

private OrderSpecifier<?> buildOrderSpecifier(String sort, 
               Order order, 
               ClassTypeInformation<?> typeInfo) { 


    Expression<?> sortPropertyExpression = new PathBuilderFactory().create(typeInfo.getType()); 
    String dotPath = aliasRegistry.getDotPath(sort); 
    PropertyPath path = PropertyPath.from(dotPath, typeInfo); 
    sortPropertyExpression = Expressions.path(path.getType(), (Path<?>) sortPropertyExpression, path.toDotPath()); 

    return new OrderSpecifier(order, sortPropertyExpression); 
} 
}