首页 > 解决方案 > Spring数据排序数组或设置为可分页

问题描述

我有一个 AirworhnessDirective 列表(或一组):

@Entity
public class AirworthinessDirective {

    @Id
    private String issueNumber;

    private String casaCode;

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-d")
    private LocalDate issueDate;

    private String title;

    private boolean isCancelled;

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-d")
    private LocalDate effective;

    @Column(columnDefinition = "TEXT")
    private String applicability;

    private AdRecurrence period;

    private String file;

    public AirworthinessDirective() {
    }

    public static AirworthinessDirective of(String issueNumber, String casaCode, LocalDate issueDate, String title, boolean isCancelled, LocalDate effective, String applicability, AdRecurrence period, String file) {

        AirworthinessDirective ad = new AirworthinessDirective();
        ad.issueNumber = issueNumber;
        ad.casaCode = casaCode;
        ad.issueDate = issueDate;
        ad.title = title;
        ad.isCancelled = isCancelled;
        ad.effective = effective;
        ad.applicability = applicability;
        ad.period = period;
        ad.file = file;
        return ad;
    }

    // accessors, equals, hashcode and builder ommitted
}

我想排序的两个字段是 issueNumber 和 isCancelled。

我有这个服务方法:

public Page<AirworthinessDirective> formPagedAds(int pg, List<AirworthinessDirective> ads) {
    Pageable pageable = PageRequest.of(pg, 10, standardAdSorting());
    int start = Math.toIntExact(pageable.getOffset());
    int end = (start + pageable.getPageSize()) > ads.size() ? ads.size() : (start + pageable.getPageSize());
    return new PageImpl<>(ads.subList(start, end), pageable, ads.size());
}

可以使用 AirworthinessDirective 的 HashSet 来设置相同的东西。我尝试了这两种方法,因为我认为该套装可能无法正确订购(但这不是原因)。standardADSorting()方法如下:

    private Sort standardAdSorting() {
        List<Sort.Order> sortOrders = new ArrayList<>();
        sortOrders.add(Sort.Order.asc("isCancelled"));
        sortOrders.add(Sort.Order.desc("issueNumber"));
        return Sort.by(sortOrders);
    }

我希望你能看到,它打算首先按 isCancelled 字段排序,然后按 issueNumber 字段排序。换句话说,我希望所有取消的广告都在后面,否则,按 issueNumber 排序。

我发现,虽然设置了 Pageable,但在我运行此测试时实际上并没有发生任何排序:

@RunWith(SpringRunner.class)
@ActiveProfiles("embedded")
public class MaintenanceContractServiceTest {

    @Autowired
    private MaintenanceContractService.Default service;

    @Test
    public void formPagedAds_withUnsortedADs() {

        List<AirworthinessDirective> ads = new ArrayList<>();

        ads.add(AirworthinessDirective.of("AD/PA-31/75", "PA-31", LocalDate.of(2006, 12, 31),
                "King KFC 300 Autopilot Yaw Bridle Cable Clamps - Replacement - CANCELLED", true, null,
                null, null, "http://services.casa..."));
        ads.add(AirworthinessDirective.of("AD/PA-31/2009-13-06R1", "PA-31", null,
                "Forward Baggage Door Locking Mechanism - Inspection / Modification", false, LocalDate.of(2011, 11, 2),
                null, null, "http://services.casa..."));
        ads.add(AirworthinessDirective.of("AD/PA-31/33", "PA-31", LocalDate.of(2006, 12, 31),
                "Exhaust System Couplings - Inspection - CANCELLED", true, null,
                null, null, "http://services.casa..."));
        ads.add(AirworthinessDirective.of("AD/PA-31/104", "PA-31", LocalDate.of(2006, 12, 31),
                "Elevator Outboard Hinge Installation - CANCELLED", true, null,
                null, null, "http://services.casa..."));
        ads.add(AirworthinessDirective.of("AD/PA-31/97 Amdt 2", "PA-31", LocalDate.of(2006, 12, 31),
                "Horizontal Stabiliser and Elevator Outboard Hinge", false, null,
                null, null, "http://services.casa..."));
        ads.add(AirworthinessDirective.of("AD/PA-31/99 Amdt 1", "PA-31", LocalDate.of(2006, 12, 31),
                "Elevator Control Tube - CANCELLED", true, null,
                null, null, "http://services.casa..."));
        ads.add(AirworthinessDirective.of("AD/PA-31/90", "PA-31", LocalDate.of(2006, 12, 31),
                "Rudder Trim Mechanism - CANCELLED", true, null,
                null, null, "http://services.casa..."));
        ads.add(AirworthinessDirective.of("AD/PA-31/131", "PA-31", LocalDate.of(2006, 12, 31),
                "Nose Baggage Door - CANCELLED", true, null,
                null, null, "http://services.casa..."));
        ads.add(AirworthinessDirective.of("AD/PA-31/2016-08-18 (Correction)", "PA-31", null,
                "Inspection of the Fuel Hose Assembly and Turbocharger Support Assembly Clearance", false, LocalDate.of(2016, 6, 5),
                null, null, "http://services.casa..."));

        Page<AirworthinessDirective> page = service.formPagedAds(0, ads);

        assertThat(page, is(notNullValue()));
        assertThat(page.getTotalPages(), is(1));
        assertThat(page.getTotalElements(), is(9L));
        assertThat(page.getContent(), is(notNullValue()));
        assertThat(page.getContent().size(), is(9));

        // all asserts relating to ordering fail, basically everything is
        // in input order.
    }
}

有谁知道我还需要做什么才能获得我想要的排序?

标签: javaspring-data

解决方案


在 JB Nizet 的帮助下,我能够使用比较器而不是使用 Spring Data 进行排序来解决问题。归结为将formPagedAds()方法更改为:

    public Page<AirworthinessDirective> formPagedAds(int pg, List<AirworthinessDirective> ads) {
        ads.sort(
                Comparator
                .comparing(AirworthinessDirective::isCancelled)
                .thenComparing(AirworthinessDirective::getIssueNumber)
        );

        Pageable pageable = PageRequest.of(pg, 10, Sort.unsorted());
        int start = Math.toIntExact(pageable.getOffset());
        int end = (start + pageable.getPageSize()) > ads.size() ? ads.size() : (start + pageable.getPageSize());
        return new PageImpl<>(ads.subList(start, end), pageable, ads.size());
    }

推荐阅读