Java分页类定义和使用「建议收藏」

Java分页类定义和使用「建议收藏」1 简介在后端与前端进行交互的过程中,需要对后端得到的数据进行分页推送给前端,比如说在某个博客网站上某用户编写了100篇文档,但在页面展示时,可能在每个页面仅仅展示10条数据,如下图所示因此,而且此类需求是一个常见需求,所以可以总结一下这个用法。一般需要实现该情景,需要返回的类似数据如下:{"result":"success&

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

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

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

@RequestMapping(value = "/partydues/viewSalarayInfo", method = RequestMethod.POST)
    @ResponseBody
    public 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,和rows
        freeDao.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}")
    @ResponseBody
    public 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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/186316.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Conda 替换镜像源方法尽头,再也不用到处搜镜像源地址[通俗易懂]

    Conda 替换镜像源方法尽头,再也不用到处搜镜像源地址[通俗易懂]文章目录conda替换镜像源教程1镜像源添加方法2如何找到你要用的源conda替换镜像源教程由于国内访问conda官网很慢,离线安装又费时费力,因此,替换国内源是一个极佳的办法。但是,目前国内源的替换教程过于老旧,都是2018-2021年的方法,尽管替换镜像源的方法不变,但是网上的资料中,很多镜像源都失效了,没有一个教程能够告诉大家如何去找自己的镜像源并添加进去。本教程出于此目的,保证大家以后添加的镜像源实效性强。(时间2022.3.10)1镜像源添加方法首先是一些常用命令,帮你诊断目前你的co

  • ViewStub延迟加载

    ViewStub延迟加载在项目中,难免会遇到这种需求,在程序运行时需要动态根据条件来决定显示哪个View或某个布局,最通常的想法就是把需要动态显示的View都先写在布局中,然后把它们的可见性设为View.GONE,最后在代码中通过控制View.VISIABLE动态的更改它的可见性。这样的做法的优点是逻辑简单而且控制起来比较灵活。但是它的缺点就是,耗费资源,虽然把View的初始可见View.GONE但是在Inflate布局…

  • 设置css属性clear的值为什么时可清除左右两边浮动_html清除浮动代码

    设置css属性clear的值为什么时可清除左右两边浮动_html清除浮动代码.clear:after{content:”.”;display:block;height:0;clear:both;visibility:hidden;}.clear{zoom:1;}这里给出了clear的简单样式问题,关于效果实现,我在另一篇文章中做了引用,可以直接看其效果,

  • pycharm最新激活码-激活码分享「建议收藏」

    (pycharm最新激活码)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html…

  • Hmily 源码解析(二)—— Hmily事务工作流程「建议收藏」

    Hmily 源码解析(二)—— Hmily事务工作流程「建议收藏」Hmily源码解析(二)前言这一篇不想谈论Hmily源码的技术实现,而是想在过了一遍hmily的实现后把hmily的工作思路单独地整理出来再进行一次总结。看看能不能进一步有所得。以hmily-demo-springcloud为例,它的实现思路如下。Hmily事务工作流程首先它是基于切面编程来实现分布式事务的操作,及通过日志记录TCC事务的信息以保证最终一致性。前…

  • LOJ10049_基金012498

    LOJ10049_基金012498LOJ10049Trie裸题(虽然我写这SB题写了快一小时)对字符串建树的同时刷答案,有两种情况:经过了一个字符串的词尾(即过了一个标记点)一直在另一个字符串里走(没有让树长出新枝)#include&lt;bits/stdc++.h&gt;#definegt()(p1==p2&amp;&amp;(p2=(p1=buf)+fread(buf,1,1000000,std…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号