Java 如何按querydsl别名排序

Java 如何按querydsl别名排序,java,spring,spring-mvc,jpa,querydsl,Java,Spring,Spring Mvc,Jpa,Querydsl,有没有办法按querydsl别名对存储库查询结果排序 到目前为止,我已成功筛选,但排序结果时出现错误: org.springframework.data.mapping.PropertyReferenceException:找不到用户类型的属性用户名! 请求: GET/users?size=1&sort=username,desc 我的rest控制器方法: @GetMapping("/users") public ListResult<User> getUsersInGroup(

有没有办法按querydsl别名对存储库查询结果排序

到目前为止,我已成功筛选,但排序结果时出现错误:

org.springframework.data.mapping.PropertyReferenceException:找不到用户类型的属性用户名!

请求:

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

我的rest控制器方法:

@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);
}
@GetMapping(“/users”)
公共ListResult getUsersInGroup(
@ApiIgnore@QuerydslPredicate(root=User.class)谓词,
可寻呼(可寻呼){
页面用户组=
userRepository.findByGroup(CurrentUser.getGroup(),谓词,可分页);
返回新的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);
}
@覆盖
默认的void自定义(QuerydslBindings绑定,QUser根){
绑定。包括(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(绑定,root.account.login,“用户名”);
}
默认页面findByGroup(组组、谓词、可分页){
BooleanExpression byGroup=QUser.user.group.eq(组);
布尔表达式finalPredicate=byGroup.and(谓词);
返回findAll(最终预测,可分页);
}
默认的void bindAlias(QuerydslBindings绑定、StringPath路径、字符串别名){
bindings.bind(path).as(别名).first(StringExpression::likeIgnoreCase);
}

我还尝试基于
querydsldpredicateargumentresolver
实现我自己的
PageableArgumentResolver
,但是那里使用的一些方法是包私有的,所以我想我可能走错了方向

我成功地创建了一个
PageableArgumentResolver
,用查询根类的类类型进行注释,并将alias registry添加到我的通用存储库接口中

这个解决方案似乎是一个解决方案,但至少它是有效的;)

存储库:

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 interface UserRepository扩展了PageableAndFilterableGenericRepository{
QDSLAliasRegistry aliasRegistry=QDSLAliasRegistry.instance();
@凌驾
默认的void自定义(QuerydslBindings绑定,QUser根){
bindAlias(绑定,root.account.login,“用户名”);
}
默认的void bindAlias(QuerydslBindings绑定、StringPath路径、字符串别名){
bindings.bind(path).as(别名).first(StringExpression::likeIgnoreCase);
aliasRegistry.register(别名,路径);
}
别名注册表:

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;
公共类QDSLAliasRegistry{
私人律师注册所;
公共静态QDSLAliasRegistry实例(){
inst=inst==null?新的QDSLAliasRegistry():inst;
返回仪表;
}
私人QDSLAliasRegistry(){
registry=HashBiMap.create();
}
HashBiMap root=parameter.getParameterAnnotation(QDSLPageable.class).root();
final ClassTypeInformation typeInformation=ClassTypeInformation.from(根);
字符串pageStr=Optional.ofNullable(parameterMap.getFirst(PAGE_PARAM)).orElse(默认_页面);
String sizeStr=可选.ofNullable(parameterMap.getFirst(SIZE\u PARAM)).orElse(默认页面大小);
int page=Integer.parseInt(pageStr);
int size=Integer.parseInt(sizeStr);
List sortStrings=parameterMap.get(SORT_PARAM);
if(排序字符串!=null){
OrderSpecifier[]说明符=新的OrderSpecifier[SortString.size()];
对于(int i=0;i
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);
}
}