Spring boot (二)—— 分页功能的实现

分页功能是一个spring boot项目常常用到的功能,所以这篇文章主要介绍一下两种简单的分页。
其实从网上我们可以看到比较常用的分页查询方法是用Pageable插件,但是我并不会用这个东西(手动捂脸),其实也是自己没去学的原因。所以这里介绍两种超级简单的分页查询,一种是通过Page类实现,另一种是通过对结果集的手动分页实现。

本文采用的例子便是笔者上一篇文章所写

Page类实现分页查询

1、非条件查询

UserRepository类里面新增这样一个方法:

Page<UserInfo> findAll(Pageable pageable);

然后来到UserController类里面,新增分页查询接口:

//分页查询
    @GetMapping(value = "/page")
    private Page<UserInfo> findByPage(@RequestParam("pageNo")Integer pageNo, @RequestParam("pageSize")Integer pageSize){
        Page<UserInfo> page = userRepository.findAll(new PageRequest(pageNo,pageSize));   //pageNo从第几页开始查,pageSize页面条数
        return page;
    }

这样,我们调用这个接口所返回的便是已经分页好的数据了,是不是超级简单?让我们来看看实际测试结果。

springboot mongodb 分页 springboot分页功能_List


截图不是很方便,实际结果如下:

{
    "content": [
        {
            "id": 1,
            "name": "小红",
            "type": null
        },
        {
            "id": 2,
            "name": "小明",
            "type": null
        },
        {
            "id": 4,
            "name": "小军",
            "type": null
        },
        {
            "id": 5,
            "name": "小强",
            "type": null
        },
        {
            "id": 6,
            "name": "小张",
            "type": null
        },
        {
            "id": 7,
            "name": "小李",
            "type": null
        },
        {
            "id": 8,
            "name": "小刚",
            "type": null
        },
        {
            "id": 9,
            "name": "小泽",
            "type": null
        },
        {
            "id": 10,
            "name": "小力",
            "type": null
        },
        {
            "id": 11,
            "name": "小总",
            "type": null
        }
    ],
    "pageable": {
        "sort": {
            "sorted": false,
            "unsorted": true,
            "empty": true
        },
        "offset": 0,
        "pageSize": 10,
        "pageNumber": 0,
        "unpaged": false,
        "paged": true
    },
    "totalElements": 11,
    "totalPages": 2,
    "last": false,
    "number": 0,
    "size": 10,
    "sort": {
        "sorted": false,
        "unsorted": true,
        "empty": true
    },
    "numberOfElements": 10,
    "first": true,
    "empty": false
}

可以看到,完整的结果里面是有很多东西的,当然大部分我们是不需要的,我们只需要保留下content(第0页的10条数据)、totalElements(总记录条数)、totalPages(总页数)、pageNumber(页码)、pageSize(页面大小)这五种数据。那么怎么获得它们呢?很简单,用Page类自带的方法就可以获得了。

page.getContent();
        page.getTotalElements();
        page.getTotalPages();
        page.getSize();
        page.getNumber();

这个时候我们再创建一个结果类,把需要的数据封装到结果类里面,由接口返回出来,就可以得到我们想要的结果了。
新建一个结果类ResultDto

public class ResultDto {
    private Integer pageNo;
    private Integer pageSize;
    private Long totalRecord;
    private Integer totalPage;
    private List<UserInfo> results;
    
    public ResultDto(){
        super();
    }
    
    public ResultDto(Integer pageNo, Integer pageSize, Long totalRecord, Integer totalPage, List<UserInfo> results){
        this.pageNo = pageNo;
        this.pageSize = pageSize;
        this.totalRecord = totalRecord;
        this.totalPage = totalPage;
        this.results = results;
    }
    
    public Integer getPageNo() {
        return pageNo;
    }

    public void setPageNo(Integer pageNo) {
        this.pageNo = pageNo;
    }

    public Integer getPageSize() {
        return pageSize;
    }

    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }

    public Long getTotalRecord() {
        return totalRecord;
    }

    public void setTotalRecord(Long totalRecord) {
        this.totalRecord = totalRecord;
    }

    public Integer getTotalPage() {
        return totalPage;
    }

    public void setTotalPage(Integer totalPage) {
        this.totalPage = totalPage;
    }

    public List<UserInfo> getResults() {
        return results;
    }

    public void setResults(List<UserInfo> results) {
        this.results = results;
    }
}

然后再修改一下分页查询的接口:

//分页查询
    @GetMapping(value = "/page")
    private ResultDto findByPage(@RequestParam("pageNo")Integer pageNo, @RequestParam("pageSize")Integer pageSize){
        Page<UserInfo> page = userRepository.findAll(new PageRequest(pageNo,pageSize));   //pageNo从第几页开始查,pageSize页面条数
        ResultDto result = new ResultDto(page.getNumber(),page.getSize(),page.getTotalElements(),page.getTotalPages(),page.getContent());
        return result;
    }

最后运行一下,就会发现它返回的结果变成了这样子:

springboot mongodb 分页 springboot分页功能_分页_02


这样看上去就舒服了很多,不会有那么多你不想要的信息,简洁明了。这里其实也就提到了一个结果类的思想,很多时候我们在调用接口时需要返回的信息是有要求的,这时我们就要自己建一个结果类来规范返回的信息。

  • 注意:参数pageNo和pageSize中pageNo是一个坑点,因为一般我们是从第一页开始查询,但在java我们是从第0页开始查询,所以这里就要注意你传过来的参数值了,假如你是前后端分离开发的,那你就要跟前端商量好,传过来的值是啥意思。
2、条件查询

在entity类里面新增一个type字段用于测试

@Column(name = "type")
    private Integer type;

    public Integer getType() {
        return type;
    }

    public void setType(Integer type) {
        this.type = type;
    }

新增字段后记得手动去数据库设置type值,然后在UserRepository类里面新增这样一个方法:

Page<UserInfo> findByType(Integer type,Pageable pageable);

接着在UserController类里面新增接口:

//条件分页查询
    @GetMapping(value = "/typepage")
    private ResultDto findByTypePage(@RequestParam("type")Integer type,@RequestParam("pageNo")Integer pageNo, @RequestParam("pageSize")Integer pageSize){
        Page<UserInfo> page = userRepository.findByType(type,new PageRequest(pageNo,pageSize));   //pageNo从第几页开始查,pageSize页面条数
        ResultDto result = new ResultDto(page.getNumber(),page.getSize(),page.getTotalElements(),page.getTotalPages(),page.getContent());
        return result;
    }

最后运行测试一下,就可以得到结果了。

springboot mongodb 分页 springboot分页功能_分页查询_03


总结:条件分页查询和非条件分页查询其实属于同一种方法,改变的只是增加了一个字段条件而已,这个分页查询方法也十分简单,相信你们看一遍就会了。接下来讲一个粗暴的分页方法:分页工具类。

分页工具类实现查询结果分页

简述:从之前的学习中我们知道,很多时候我们查询出来的结果是一个List数组,而分页无非就是将这个List数组进行再处理,分段罢了,当我们理解了分页的本质之后,就可以制作这样一个分页工具类,手动对结果进行分页。而分页工具最大的优点就是查询和分页是分开的,这样无论你做多复杂的查询,只要是个List数组,我分页工具就能把你分页!
分页工具类PageUtils

public class PageUtils<T> {
    //页码
    private int pageNo;
    //页面大小
    private int pageSize;
    //总记录条数
    private long totalRecord;
    //总页数
    private int totalPage;
    //每页的开始
    private int start;
    //当前页面记录集
    private List<T> results;

    public void doPage(List<T> lists){
        int count = lists.size();
        setTotalRecord(count);
        setTotalPage(count % pageSize == 0 ? count / pageSize : count / pageSize + 1);
        setStart(getPageNo() * getPageSize());
        setResults(lists.subList(getStart(),
                (count - getStart()) > getPageSize() ? getStart() + getPageSize() : count));
    }
    public PageUtils(){
        super();
    }
    public PageUtils(int pageNo, int pageSize){
        this.pageNo = pageNo;
        this.pageSize = pageSize;
    }

    public int getStart() {
        return start;
    }

    public void setStart(int start) {
        this.start = start;
    }

    public List<T> getResults() {
        return results;
    }

    public void setResults(List<T> results) {
        this.results = results;
    }

    public int getPageNo() {
        return pageNo;
    }

    public void setPageNo(int pageNo) {
        this.pageNo = pageNo;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public long getTotalRecord() {
        return totalRecord;
    }

    public void setTotalRecord(long totalRecord) {
        this.totalRecord = totalRecord;
    }

    public int getTotalPage() {
        return totalPage;
    }

    public void setTotalPage(int totalPage) {
        this.totalPage = totalPage;
    }
}

写好工具类之后,就可以直接到controller层UserController类里面写接口了:

@GetMapping(value = "/utilpage")
    private ResultDto findByUtil(@RequestParam("pageNo")Integer pageNo, @RequestParam("pageSize")Integer pageSize){
        PageUtils<UserInfo> page = new PageUtils<>(pageNo,pageSize);
        List<UserInfo> users = userRepository.findAll();
        page.doPage(users);
        ResultDto result = new ResultDto(page.getPageNo(),page.getPageSize(),
                page.getTotalRecord(),page.getTotalPage(),page.getResults());
        return result;
    }

运行一下,再postman里面查看结果:

springboot mongodb 分页 springboot分页功能_Java_04


到此,关于分页的两个方法就介绍完了。