1 简介

在后端与前端进行交互的过程中,需要对后端得到的数据进行分页推送给前端,比如说在某个博客网站上某用户编写了100篇文档,但在页面展示时,可能在每个页面仅仅展示10条数据,如下图所示

因此,而且此类需求是一个常见需求,所以可以总结一下这个用法。
一般需要实现该情景,需要返回的类似数据如下:

{"result": "success","msg": "查询历史信息成功","data": {"totalPage": 66,"pageSize": 10,"currentPage": 1,"rows": [{"month": "08","createTime": "2018-12-24 16:15:36","year": "2018","description": "完成2018年08月的缴纳, 金额为800.0元","operation": "缴纳","operator": "周周"},{"month": "08","createTime": "2018-12-24 15:22:01","year": "2018","description": "完成2018年08月购买的发起","operation": "党费发起","operator": "周周"},{"month": "08","createTime": "2018-12-24 15:13:36","year": "2018","description": "完成文件的上传,可以发起2018年08月的购买流程","operation": "上传工资","operator": "周周"},{"month": "03","createTime": "2018-12-24 10:52:40","year": "2021","description": "完成2021年03月购买的部门领导","operation": "部门领导","operator": "猪八戒"},{"month": "03","createTime": "2018-12-24 10:52:07","year": "2021","description": "完成综合计划室党支部-政工组2021年03月购买的确认","operation": "党支部确认","operator": "松松"},{"month": "03","createTime": "2018-12-24 10:51:47","year": "2021","description": "完成2021年03月的购买, 金额为500.0元","operation": "购买","operator": "松松"},{"month": "03","createTime": "2018-12-24 10:51:27","year": "2021","description": "完成开发组2021年03月购买的确认","operation": "党支部确认","operator": "范范"},{"month": "03","createTime": "2018-12-24 10:51:22","year": "2021","description": "为吵吵代办2021年03月购买,金额为222.0元","operation": "党费代办","operator": "范范"},{"month": "03","createTime": "2018-12-24 10:51:12","year": "2021","description": "为猪八戒代办2021年03月购买,金额为555.0元","operation": "党费代办","operator": "范范"},{"month": "03","createTime": "2018-12-24 10:50:43","year": "2021","description": "完成2021年03月的购买, 金额为255.0元","operation": "购买","operator": "范范"}],"totalCount": 654}
}

一般在分页结构中应该包含的最少内容如下:

{“result”: “success”,“msg”: “获取数据成功”,“data”: {“totalCount”: 300,"totalPage": 66,"pageSize": 10,"currentPage": 1,rows: [{…},{…},{…},{…},…]}
}

因此,在定义该类时,应该包含上述5个成员totalCount, totalPage, pageSize, currentPage, 以及保存当前页对应的所有数据的rows成员.

2 定义

package com.sqh.util;import java.io.Serializable;
import java.util.List;    public class Page<T> implements Serializable {  private static final long serialVersionUID = 5760097915453738435L;  public static final int DEFAULT_PAGE_SIZE = 10;  /** * 每页显示个数 */ private int pageSize;  /** * 当前页数 */ private int currentPage;  /** * 总页数 */ private int totalPage;  /** * 总记录数 */ private int totalCount;  /** * 结果列表 */ private List<T> rows;  public Page(){  this.currentPage = 1;  this.pageSize = DEFAULT_PAGE_SIZE;  }  public Page(int currentPage,int pageSize){  this.currentPage=currentPage<=0?1:currentPage;  this.pageSize=pageSize<=0?1:pageSize;  }  public int getPageSize() {  return pageSize;  }  public void setPageSize(int pageSize) {  this.pageSize = pageSize;  }  public int getCurrentPage() {  return currentPage;  }  public void setCurrentPage(int currentPage) {  this.currentPage = currentPage;  }  public int getTotalPage() {  return totalPage;  }  public void setTotalPage(int totalPage) {  this.totalPage = totalPage;  }  public int getTotalCount() {  return totalCount;  }  public void setTotalCount(int totalCount) {//设置了totalCount就可以计算出总totalPage  this.totalCount = totalCount;int countRecords = this.getTotalCount();int totalPages = countRecords % pageSize == 0 ? countRecords / pageSize : (countRecords / pageSize + 1);setTotalPage(totalPages);}  /** * 设置结果 及总页数 * @param rows 分页之后查询到的结果*/ public void build(List<T> rows) {this.setRows(rows);int count =  this.getTotalCount();/*int divisor = count / this.getPageSize();int remainder = count % this.getPageSize();//设置总页数, Trash code, confusing.this.setTotalPage(remainder == 0 ? (divisor == 0 ? 1 : divisor) : divisor + 1);*///已在setTotalCount中进行/*
int countRecords = this.getTotalCount();int totalPages = countRecords % pageSize == 0 ? countRecords / pageSize : (countRecords / pageSize + 1);setTotalPage(totalPages);*/}  public List<T> getRows() {  return rows;  }  public void setRows(List<T> rows) {this.rows = rows;  }
}

在该类使用时,应该首先使用步骤如下:

  1. currentPage和 pageSize进行分页类Page对象的实例化,
  2. 然后使用setTotalCount()函数传入总记录数,
  3. 这样在把当前页结果给取出来,传入Page对象,即可封装该分页结构

3 使用

3.1 Mongo数据库分页查询

在与mongo数据库进行交互时,由于没有直接提供分页的函数,因此我们可对这种应用场景进行封装

public Page<T> findPage(Page<T> page, Query query,String collectionName){//如果没有条件 则所有全部  query=query==null?new Query(Criteria.where("_id").exists(true)):query;long count = this.count(query, collectionName);// 总数  page.setTotalCount((int) count);  int currentPage = page.getCurrentPage();  int pageSize = page.getPageSize();  query.skip((currentPage - 1) * pageSize).limit(pageSize);  List<T> rows = this.find(query,collectionName);  page.build(rows);  return page;  }

在上述的普通函数中,我们调用了Query类型,

public class Query extends Object


MongoDB Query类对象表示规则Criteria,投射Projection,排序sorting,和Query Hints。使用了mongoTemplate对象进行查询和计数。可查询相关API,不再赘述。

@RequestMapping(value = "/partydues/viewSalarayInfo", method = RequestMethod.POST)@ResponseBodypublic String viewSalarayInfo(@RequestBody JSONObject form) {System.out.println(("viewSalarayInfo starts"));JSONObject result = new JSONObject();if ((!form.containsKey("year")) || (!form.containsKey("month"))) {return result.element("result", "fail").element("msg", "查询工资时请指定年月参数").toString();}String year = form.getString("year");String month = form.getString("month");//获取分页参数并验证数据有效性if ((year.isEmpty()) || (month.isEmpty())) {return result.element("result", "fail").element("msg", "查询工资时年月参数不能为空").toString();}if ((!form.containsKey("pageSize")) || (!form.containsKey("page"))) {return result.element("result", "fail").element("msg", "查询时请指定分页信息").toString();}int page = form.getInt("page");int pageSize = form.getInt("pageSize");if (pageSize < 0) {pageSize = 10;}if (page<0) {page=0;}//创建分页对象Page<FreeModel> pageResult = new Page<FreeModel>();pageResult.setPageSize(pageSize);pageResult.setCurrentPage(page);Query query = new Query();query.addCriteria(new Criteria("map.year").is(year));query.addCriteria(new Criteria("map.month").is(month));query.with(new Sort(new Sort.Order(Sort.Direction.ASC, "map.orderBy")));//使用上述封装的函数,传入分页对象,和表名,这样在函数执行时自动填充totalCount,和rowsfreeDao.findPage(pageResult, query, SALARY_TABLE);List<FreeModel> rows =  pageResult.getRows();JSONArray array = new JSONArray();//重组rows中的内容for(int i=0; i<rows.size(); i++) {//检索第一个元素,按照指定的形式返回前端数据PageData pageData = rows.get(i).getMap();JSONObject salaryRecord = JSONObject.fromObject(pageData);array.add(salaryRecord);}pageResult.setRows(array);return CommonReturn.httpReturn(CommonReturn.SUCCESS, "查询工资记录成功", pageResult);
}

可见,在上述的Controller层调用时依然遵循了相同的Page对象使用步骤。

3.2 普通List对象组装

在Java web开发的过程中,也存在一种情形,需要我们自己组织list数据,并返回给前端符合分页结构的数据,这也是一种常见的情形,对于这类情形,如何使用Page类进行分页对象的构建呢?查看下述例子:

/*** @description: 返回指定年月的工资信息,展示列表,支持分页展示* @url:* @author: Song Quanheng* @date: 2018/11/13-14:42* @return:*/@RequestMapping(value = "/partydues/viewSalarayInfoByDept/{year}/{month}")@ResponseBodypublic String viewSalaryInfoByDept(@PathVariable("year") String year,@PathVariable("month") String month, @RequestBody JSONObject form) {JSONObject res = new JSONObject();if (!form.containsKey("page") || !form.containsKey("pageSize")) {return CommonReturn.httpReturnFailure("请指定分页参数page和pageSize");}int page = form.getInt("page");int pageSize = form.getInt("pageSize");if (pageSize < 0) {pageSize = 10;}if (page<=0) {page=1;}Query query = new Query();query.addCriteria(new Criteria("map.year").is(year));query.addCriteria(new Criteria("map.month").is(month));JSONObject ret = partyDuesBusiness.findSalaryInfoByDept(year, month);if (ret.size() == 0) {return CommonReturn.httpReturnFailure("查询不到"+year+"年"+month+"月的工资信息");}JSONArray deptOrder = partyDuesBusiness.viewDeptInfoInOrder();JSONArray result = new JSONArray();if (0 == deptOrder.size()) {return CommonReturn.httpReturn(FAILURE, "请插入有序的部门名称到数据库中");}for (int i=0; i<deptOrder.size(); i++) {String deptName = deptOrder.getString(i);int count = 0;if (ret.containsKey(deptName)) {//根据部门名获得该部门相关的人数count = ret.getInt(deptName);} else {continue;}//如果0==count,表示该部门不用展示在页面上,因为不存在人员if (0==count) {continue;}JSONObject itemOne = new JSONObject();itemOne.put("deptName", deptName);itemOne.put("totalNumOfPersons", count);itemOne.put("year", year);itemOne.put("month", month);result.add(itemOne);}int countRecords = result.size();int totalPages = countRecords % pageSize == 0 ? countRecords / pageSize : (countRecords / pageSize + 1);//获得指定范围的结果List<JSONObject> pageResult = partyDuesBusiness.getListByPage(result, page, pageSize);//组织为分页对象Page pageRet = new Page(page, pageSize);pageRet.setRows(pageResult);pageRet.setTotalPage(totalPages);pageRet.setTotalCount(countRecords);return CommonReturn.httpReturn(CommonReturn.SUCCESS, "按照部门分组查询信息成功", pageRet);}

上述的代码遵循相同的步骤逻辑,查询分页范围内的结果,然后利用当前页和页面记录数新建分页对象,设置totalCount成员,最后设置分页范围的记录内容。返回给前端即可。

3.3 getListByPage

在上述普通的list对象生成分页数据的过程中,调用了一个函数getListByPage()函数,该函数封装内容如下:

public List getListByPage(List list,int page,int pageSize) {if(list.size() > 0 ){int firstIndex = (page - 1) * pageSize;int lastIndex = page * pageSize;int actualLastIndex = 0;if(list.size() > lastIndex || list.size() == lastIndex){actualLastIndex = lastIndex;}else{actualLastIndex = list.size();}return list.subList(firstIndex,actualLastIndex);}return list;
}

函数中主要使用List接口的subList函数。
List表示有序的collection。此接口的用户可以对列表中的每个元素的插入位置进行精确的控制。用户可以根据元素的整数索引访问元素,并搜索列表中元素的位置。

List<E> subList(int fromIndex, int toIndex)
返回列表中指定的fromIndex(包括)和toIndex(不包括)之间的部分视图。
返回:列表中指定范围的视图
抛出:IndexOutOfBoundsException – 非法的端点值(fromIndex<0 || toIndex > size || fromIndex > toIndex)

注意:由于getListByPage中list为List类型,因此只要类型实现了List接口,均可以传入,诸如ArrayList或者JSONArray都可以传入该函数进行分页提取数据。

4 总结

在编程过程中,对于不断重复的模式可以进行封装,这样既能锤炼代码的凝练度,同时可以增强代码的正确性。Java分页相关的内容介绍到这里,不断的反思和总结是一个人持续进步的基石,是每个程序员自我要求,自我实现的一部分。

5 参考

https://blog.csdn.net/lk142500/article/details/84561292

6下载

https://download.csdn.net/download/lk142500/10873558

Java分页类定义和使用相关推荐

  1. phppage类封装分页功能_PHP封装的page分页类定义与用法完整示例

    本文实例讲述了PHP封装的page分页类定义与用法.分享给大家供大家参考,具体如下: 亲测有效,见下图=========> 1. 测试实例test.php header("Conten ...

  2. java里写分页,自己写的Java分页类

    自己写的分页类 //分页类 package xiyou.cm.cattsoft.util; public class Page { private int totalRows;//总共记录数 priv ...

  3. java - 分页类

    pager.java package com.jspnews.util;import java.io.Serializable; import java.util.List;/*** * <b& ...

  4. java box类定义三变量_01.类的成员变量:\n设计一个立方体类Box,定义三个属性,分别是长,宽,高。定义二个方法,分别计...

    01.类的成员变量:\n设计一个立方体类Box,定义三个属性,分别是长,宽,高.定义二个方法,分别计算并输出立方体的体积和表面积 答:java.util.Scanner; public class B ...

  5. java分页类Page

    package com.h3c.itac.util;import java.util.ArrayList; import java.util.List;@SuppressWarnings(" ...

  6. Java的类和包的总结

    ​ 学习目录 面向对象的初步认识 面向对象和面向过程 简单的认识类 类定义的格式 类的实例化 总结类和对象 this引用 this引用的特性 构造方法 对象的初始化 封装 访问限定符 封装扩展包 包的 ...

  7. java定义一个类计算圆的半径,C++编程:定义一个圆类要求属性为半径,操作为计算圆的周长和面积...,java编程:定义一个圆类,属性为半径,方法为对输入的半径计...

    导航:网站首页 > C++编程:定义一个圆类要求属性为半径,操作为计算圆的周长和面积...,java编程:定义一个圆类,属性为半径,方法为对输入的半径计 C++编程:定义一个圆类要求属性为半径, ...

  8. java定义一个学生类cstudent_编写一个JAVA程序片断 定义一个表示学生的类student

    编写一个JAVA程序片断定义一个表示学生的类student,包括域"学号","班级","姓名","性别","年 ...

  9. 分页类实例 java

    保存代码片段 分页类: 分页类,点击查看 1 package cn.news.vo; 2 3 import java.util.List; 4 /** 5 * 用于在页面上使用的数据类,包含有分页的信 ...

最新文章

  1. docker 上传到自己的容器
  2. python统计文件行数检测字符串_python统计文件中的字符串数目示例
  3. 时频特性分析(Matlab)
  4. 的有效性最好_世界前10名面膜补水排行榜 最好用的十款面膜推荐
  5. 利用反射获得类的public static/const成员的值
  6. huffman算法c语言实验报告,huffman二叉树实验报告--数据结构(c语言).doc
  7. R7-4 检查密码 (15 分)
  8. 19) maven 项目结构:聚集
  9. 中国急性髓系白血病药物市场趋势报告、技术动态创新及市场预测
  10. android mmkv使用_锦囊篇|一文摸懂SharedPreferences和MMKV(一)
  11. 开箱即用的SSH攻击字典收集工具
  12. 深度解析,AI如何让创新变得更简单
  13. ABP Framework 5.3.0 版本新增功能和变更说明
  14. python实现华氏温度和摄氏温度转换
  15. 正点原子ATK-LORA-01无线串口代码移植+STM32F103C8T6(标准库)
  16. 每日一练_是程序呀(每日更新)_XML
  17. foo:function(){}与function foo(){}还有foo=function()三者间的区别
  18. 报错:org.springframework.cloud.gateway.support.NotFoundException: Unable to find instance for localhos
  19. C语言实现稳定的快排
  20. 关于搭建一个简易搭建网站的大概步骤

热门文章

  1. APP版本号命名规范
  2. 塔式、机架式、刀片式服务器区别以及特点
  3. 电影推荐系统(推荐系统的hello work)
  4. 极光推送 使用实例 (一)服务端
  5. ubuntu用户和权限介绍
  6. vb与oracle数据库连接,vb.net 如何与oracle数据库连接
  7. POS收银机收款机使用介绍
  8. CH340有线USB转串与CH9140无线蓝牙转串
  9. JS表单验证(HTML+CSS+JS)小实例【详细教程】
  10. 我在B站工作的30天时光,从入职到离职