spring-data-jpa 对对象列表进行多次排序

izj3ouym  于 2022-11-10  发布在  Spring
关注(0)|答案(2)|浏览(178)

我有一个通过外部REST服务检索到的对象列表,我想使用Pageable.Sort属性中的用户定义值对这些对象进行排序。
这是我的DTO对象:

@Data
@Builder
public class UserDto {
    private String guid;
    private String firstName;
    private String lastName;
}

给定一个UserDto列表和一个Pageable.Sort,我尝试为每个定义的属性及其方向对列表进行排序。

public Page<UserDto> listToPage(List<UserDto> list, Pageable pageable) {

        var sorts = pageable.getSort();

        //Retrieves the name of all object fields
        var fields = Arrays.stream(UserDto.class.getDeclaredFields())
                .map(Field::getName)
                .collect(Collectors.toList());

        //For each sort specified in the pageable I need to sort the list of objects
        for (var sort : sorts) {
            //If a given property does not exist. Throws an exception.
            if (!fields.contains(sort.getProperty()))
                throw new InvalidDataException("Property [" + sort.getProperty() + "] does not exists in " + UserDto.class.getName() + " class");

            //Looks for the property and its direction
            switch (sort.getProperty()) {
                case "guid":
                    list = sort.getDirection().isDescending() ?
                            list.stream().sorted(Comparator.comparing(UserDto::getGuid).reversed()).collect(Collectors.toList()) :
                            list.stream().sorted(Comparator.comparing(UserDto::getGuid)).collect(Collectors.toList());
                    break;
                case "firstName":
                    list = sort.getDirection().isDescending() ?
                            list.stream().sorted(Comparator.comparing(UserDto::getFirstName).reversed()).collect(Collectors.toList()) :
                            list.stream().sorted(Comparator.comparing(UserDto::getFirstName)).collect(Collectors.toList());
                    break;
                case "lastName":
                    list = sort.getDirection().isDescending() ?
                            list.stream().sorted(Comparator.comparing(UserDto::getLastName).reversed()).collect(Collectors.toList()) :
                            list.stream().sorted(Comparator.comparing(UserDto::getLastName)).collect(Collectors.toList());
                    break;
                default:
                    break;
            }
        }

        final int start = (int) pageable.getOffset();
        final int end = Math.min((start + pageable.getPageSize()), list.size());

        var subList = list.subList(start, end);
        return new PageImpl<>(subList, pageable, list.size());
    }

除了传递多个属性来对用户列表进行排序外,所有这些都可以正常工作。
第一轮应该按firstName:ASC排序,然后在第二轮中,应该按lastName:DESC排序,记住第一个排序顺序,但这不是这样做的。
有没有什么方法可以处理同一个列表在不同轮中的多个排序?我不想使用thenComparing操作符,因为我想通过用户交互动态地完成这一操作。
未来方法是以一种通用的方式创建此函数,以处理任何对象并对其属性进行排序,从而利用此JPA提供的类。
这是我的测试案例:

@Test
    void testCase1() {
        var userDtoList = List.of(
                UserDto.builder().firstName("A3").lastName("B7").guid("G000a").build(),
                UserDto.builder().firstName("A2").lastName("B4").guid("G000b").build(),
                UserDto.builder().firstName("A3").lastName("B1").guid("G000c").build(),
                UserDto.builder().firstName("A2").lastName("B5").guid("G000d").build(),
                UserDto.builder().firstName("A1").lastName("B6").guid("G000e").build(),
                UserDto.builder().firstName("A2").lastName("B3").guid("G000f").build(),
                UserDto.builder().firstName("A1").lastName("B2").guid("G000g").build()
        );

        Sort firstNameSort = Sort.by("firstName");
        Sort lastNameSort = Sort.by("lastName").descending();

        Sort sort = firstNameSort.and(lastNameSort);

        var pageable = PageRequest.of(0, 5, sort);

        var result = userService.listToPage(userDtoList, pageable);
        result.getContent().forEach(System.out::println);

        assertEquals(5, result.getContent().size());

    }
vfhzx4xs

vfhzx4xs1#

如果您希望从数据库中检索用户,您可以使用Spring Data ,如下所示:

public interface UserRepository extends JpaRepository<UserDto, String>{

    List<UserDto> findByFirstNameAscLastNameDesc(Pageable pageable);

}
f4t66c6m

f4t66c6m2#

对于面临同样问题的人,我使用Java反射创建了一个通用的PageUtils类来解决这个问题。
您可以在下面的Github repo中找到代码:
https://github.com/rortegat/generic-pageable

相关问题