问题:再一次项目测试中,发现别人用PageImpl来实现分页查询的功能,但是测试的时候会出现一个问题就是当调整分页大小的时候会出现严重的bug,返回的数据总数在不断的递增,增加的数量就是分页的大小,而且每次返回的数据都是一模一样的。
研究:网上也有很多类似的实现,都是数据库查出一个list,然后根据前端的pageIndex和PageSize来构造一个PageAble,然后再构造一个PageImpl出来。代码如下,这里我使用写死的list来代表数据库查出的数据。
private List<String> list = Stream.of("a","b","c","d","e","f").collect(Collectors.toList());
/**
* @author: 豆豆
* @date: 2018/11/20 16:44a
* @description: 入口函数,自动生成
*/
public static void main(String[] args){
PageTest test = new PageTest();
Pageable request = PageRequest.of(4,2);
Page<String> page = new PageImpl<>(test.list, request, test.list.size());
}
当我们的pageIndex乘以PageSize大于查出来的总数的时候就会出现上述的bug。然后我去看了源码,有如下解释:
首先是整个类的注释,说是一个基本的Page实现。然后是构造方法,第一个参数和第二个参数很好理解,但是到了第三个参数就出现问题了,说是当请求的长度大于总数的时候会对总数作出调整,这就很郁闷,为什么要做这个事情,通过代码可以看到当offset+pageSize > total的时候,会将前者的值赋值给total。这时候total就变了。
(若是有大神指导原因劳烦告知下我)
package org.springframework.data.domain;
import java.util.List;
import java.util.function.Function;
import org.springframework.lang.Nullable;
/**
* Basic {@code Page} implementation.
*
* @param <T> the type of which the page consists.
* @author Oliver Gierke
* @author Mark Paluch
*/
public class PageImpl<T> extends Chunk<T> implements Page<T> {
private static final long serialVersionUID = 867755909294344406L;
private final long total;
/**
* Constructor of {@code PageImpl}.
*
* @param content the content of this page, must not be {@literal null}.
* @param pageable the paging information, must not be {@literal null}.
* @param total the total amount of items available. The total might be adapted considering the length of the content
* given, if it is going to be the content of the last page. This is in place to mitigate inconsistencies.
*/
public PageImpl(List<T> content, Pageable pageable, long total) {
super(content, pageable);
this.total = pageable.toOptional().filter(it -> !content.isEmpty())//
.filter(it -> it.getOffset() + it.getPageSize() > total)//
.map(it -> it.getOffset() + content.size())//
.orElse(total);
}
//其他的方法省略自行查看
}
看了代码后我就感觉这个PageImpl根本不能实现我们平时的分页查询的功能,虽然我们可以使用SpringDataJPA提供的分页方法,但是在某些情况下比如维护的别人使用EntityManager执行的复杂查询sql的时候,你又不想去修改他的查询逻辑使用基于准则的查询的时候,就需要一个可以直接将查询结果进行分页的设计,这时候PagedListHolder就派上用场了。他的使用方法如下:
PagedListHolder<PersonAlarm> pagedListHolder = new PagedListHolder<>(要分页的集合);
pagedListHolder.setPageSize(PageSize);
pagedListHolder.setPage(PageIndex);
return pagedListHolder;
至此就可以完美解决你的分页问题,如果有人知道PageImpl的用处或者使用它分页,烦请留个言交流下。