All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sicheng.common.persistence.Page Maven / Gradle / Ivy

There is a newer version: 4.1.1
Show newest version
/**
 * 本作品使用 木兰公共许可证,第2版(Mulan PubL v2) 开源协议,请遵守相关条款,或者联系sicheng.net获取商用授权。
 * Copyright (c) 2016 SiCheng.Net
 * This software is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */
package com.sicheng.common.persistence;

import com.fasterxml.jackson.annotation.JsonIgnore;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Pattern;

/**
 * 

标题: 分页类

*

描述: 是分页的核心类

*

公司: 思程科技 www.sicheng.net

*

* Page 分页的其特性 * pageSize=-1 表示不分页 * count=-1 表示不查询总数,可用于提高性能,但不能显示“总记录数”,超出后会查不出数据。适合海量数据的分页,如有100万条数据,页面上只有一个“下一页”按钮,用户一直点就一直翻页。直到返回空数据时停止。 * count>0 表示已通过其它途径获得了conut总条数,不再需要再查询总条数,节省性能。适海量数据的分页,如有100万条数据,用户不可能从第1页翻到最后一页,可以只让用户查前100页(2000条)。 *

* * @param 数据实体类的类型 * @author zhaolei * @version 2017年1月21日 上午11:44:08 */ public class Page { static public String PAGESIZE = "pageSize"; // 常量 static public String PAGESIZE_COOKIE = "fdp_pageSize"; // 常量,pageSize存储在cookie中使用的key,见page.jsp static public String PAGENO = "pageNo"; // 常量 static public String ENCODE = "UTF-8"; // 常量,编码,从request中取参数时可能会使用 private long count; // 总记录数,设置为“2000”表示只查询前2000条,若每页20条只查100页,适用于海量数据 private int pageSize = 20; // 每页记录数 -1表示不分页 private int pageNo = 1; // 当前页码 private String pageURL; // 分页导航的URL+查询参数 private int first; // 首页索引 private int last; // 尾页索引,总页数getTotalPage() private int prev; // 上一页索引 private int next; // 下一页索引 private boolean firstPage; // 是否是第一页 private boolean lastPage; // 是否是最后一页 private boolean beyondPage; // 输入的页码超过总页数 private int length = 8; // 分类导航条的长度 private int slider = 1; // 前后显示页面长度 private String orderBy = ""; // 标准查询有效, 实例: updatedate desc, name asc private String message = ""; // 设置提示消息,显示在“共n条”之后 private List list = new ArrayList(); // 本页数据对象列表,是查询出来的一页数据 /** * 创建一个默认分页对象(常用) * 从request中获取分页数据,来初始化一个page对象 * * @return Page 分页对象 */ public static Page newPage() { return null; } /** * 构造方法 * * @param request 传递 repage 参数,来记住页码 * @param response 用于设置 Cookie,记住页码 */ public Page(HttpServletRequest request, HttpServletResponse response) { } /** * 构造方法 * * @param request 传递 repage 参数,记住页码, 2016-8-13 赵磊修改:使用RepageInterceptor来实现,替换cookie实现 * @param response 用于设置 Cookie,记住页码 * @param defaultPageSize 默认分页大小,如果传递 -1 则为不分页,返回所有数据 */ public Page(HttpServletRequest request, HttpServletResponse response, int defaultPageSize) { } /** * 构造方法 */ public Page() { initialize(); } /** * 构造方法 * * @param pageNo 当前页码 * @param pageSize 分页大小 */ public Page(int pageNo, int pageSize) { // this(pageNo, pageSize, 0); this.setPageSize(pageSize); this.setPageNo(pageNo); } /** * 构造方法 * * @param pageNo 当前页码 * @param pageSize 分页大小 * @param count 数据条数 */ public Page(int pageNo, int pageSize, long count) { // this(pageNo, pageSize, count, new ArrayList()); this.setPageSize(pageSize); this.setPageNo(pageNo); this.setCount(count);// setCount()方法中会执行initialize(); } /** * 构造方法 * * @param pageNo 当前页码 * @param pageSize 分页大小 * @param count 数据条数 * @param list 本页数据对象列表 */ public Page(int pageNo, int pageSize, long count, List list) { this.list = list; this.setPageSize(pageSize); this.setPageNo(pageNo); this.setCount(count);// setCount()方法中会执行initialize(); } /** * 初始化参数 */ public void initialize() { this.first = 1; this.last = (int) (count / (this.pageSize < 1 ? 20 : this.pageSize) + first - 1); if (this.count % this.pageSize != 0 || this.last == 0) { this.last++; } if (this.last < this.first) { this.last = this.first; } //处理是否超出,要放在靠前的位置,放在pageNo被改变之前 //标记为页码未超出 this.beyondPage = this.pageNo > this.last;//标记为页码超出 //处理firstPage if (this.pageNo <= 1) { this.pageNo = this.first; this.firstPage = true; } else { this.firstPage = false; } //处理lastPage if (this.pageNo >= this.last) { this.pageNo = this.last; this.lastPage = true; } else { this.lastPage = false; } //处理next if (this.pageNo < this.last - 1) { this.next = this.pageNo + 1; } else { this.next = this.last; } //处理prev if (this.pageNo > 1) { this.prev = this.pageNo - 1; } else { this.prev = this.first; } // 如果当前页小于首页 if (this.pageNo < this.first) { this.pageNo = this.first; } // 如果当前页大于尾页 if (this.pageNo > this.last) { this.pageNo = this.last; } } /** * 构造分页导航的URL,包含查询参数 用于点击“下一页”时,能带参数进行查询 * * @param request HttpServletRequest */ private void buildPageURL(HttpServletRequest request) { String sPageURLPara = buildParameter(request); if (sPageURLPara.length() > 0) { pageURL = "?" + sPageURLPara.substring(1) + "&"; } else { pageURL = "?"; } pageURL = request.getRequestURI() + pageURL + "pageNo="; } /** * 从HttpServletRequest取参数,刨除pageNo参数(页码) * * @param request HttpServletRequest * @return 参数的字符串形式,如 &a=1&b=2 */ @SuppressWarnings("rawtypes") private String buildParameter(HttpServletRequest request) { Map map = request.getParameterMap(); Set set = map.keySet(); Iterator it = set.iterator(); StringBuilder sbf = new StringBuilder(); while (it.hasNext()) { String key = (String) it.next(); if ((!key.equals(PAGENO)) && (!key.equals(PAGESIZE))) { String[] values = (String[]) map.get(key); for (String v : values) { sbf.append("&"); sbf.append(key); sbf.append("="); if (request.getCharacterEncoding() == null) { // 如果request没设置编码,就要解码 try { sbf.append(new String(v.getBytes(StandardCharsets.ISO_8859_1), ENCODE)); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } else { // 如果request已设置编码,直接取值就OK sbf.append(v); } } } } // 若有多个pageSize参数,只取最后一个,只拼接一次 // 一般情况pageSize参数只会有一个 String[] pageSize_value = request.getParameterValues(PAGESIZE); if (pageSize_value != null) { for (int i = pageSize_value.length - 1; i >= 0; i--) { String v = pageSize_value[i]; if (StringUtils.isNoneBlank(v)) { sbf.append("&").append(PAGESIZE).append("=").append(v); break;// 从最后开始找,找到一个就返回了 } } } return sbf.toString(); } /** * 获取分页HTML代码(不常用) * 只供临时测试使用,不建议在正式的系统中使用本方法输出分页条(因为“表现”与“数据”没有实现分离)。 * 在正式的系统中应使用page.jsp做为模板、Page类做为数据,使用模板技术来输出自定义的分页导航条 * * @return HTML代码 */ public String getHtml() { StringBuilder sb = new StringBuilder(); if (pageNo == first) { // 如果是首页,"上一页"不可点击 sb.append("
  • « 上一页
  • \n"); } else { // 如果不是首页,"上一页"可点击 sb.append("
  • « 上一页
  • \n"); } int begin = pageNo - (length / 2);// 左边的起始页码,如当前是第50页,最左边的页码是46 if (begin < first) { begin = first;// 防止出现负数 } int end = begin + length - 1;// 右边的结束页码,如当前是第50页,最右边的页码是54 if (end >= last) { end = last; // 防止超过总页数 begin = end - length + 1; if (begin < first) { begin = first; } } // 在循环中生成 左边的页码。slider为1时,作用就是“首页” if (begin > first) { int i = 0; for (i = first; i < first + slider && i < begin; i++) { sb.append("
  • " + (i + 1 - first) + "
  • \n"); } if (i < begin) { sb.append("
  • ...
  • \n"); } } // 在循环中生成 中间的页码,如当前是第50页,46,47,48,49,50,51,52,53,54,并且50页不可点击 for (int i = begin; i <= end; i++) { if (i == pageNo) { sb.append("
  • " + (i + 1 - first) + "
  • \n"); } else { sb.append("
  • " + (i + 1 - first) + "
  • \n"); } } if (last - end > slider) { sb.append("
  • ...
  • \n"); end = last - slider; } // 在循环中生成 右边的页码。slider为1时,作用就是“尾页” for (int i = end + 1; i <= last; i++) { sb.append("
  • " + (i + 1 - first) + "
  • \n"); } if (pageNo == last) { // 如果是尾页,"下一页"不可点击 sb.append("
  • 下一页 »
  • \n"); } else { // 如果不是尾页,"下一页"可点击 sb.append("
  • " + "下一页 »
  • \n"); } sb.append("
  • 跳到 "); sb.append(" "); sb.append("共 " + count + " 条" + (message != null ? message : "") + "
  • \n"); sb.insert(0, "
      \n").append("
    \n"); sb.append("
    "); return sb.toString(); } /** * 获取总记录条数 */ public long getCount() { return count; } /** * 设置总记录条数 * * @param count 总记录条数 */ public void setCount(long count) { this.count = count; initialize();//这里需要initialize(),执行完求count的SQL时会调用setCount()方法,所以需要initialize() } /** * 获取当前页码 */ public int getPageNo() { return pageNo; } /** * 设置当前页码 * * @param pageNo */ public void setPageNo(int pageNo) { this.pageNo = pageNo; } /** * 获取页面大小 */ public int getPageSize() { return pageSize; } /** * 设置页面大小 * * @param pageSize -1表示不分页,是合法值 */ public void setPageSize(int pageSize) { } /** * 首页索引 */ @JsonIgnore public int getFirst() { return first; } /** * 尾页索引 */ @JsonIgnore public int getLast() { return last; } /** * 获取页面总数 * * @return getLast(); */ @JsonIgnore public int getTotalPage() { return getLast(); } /** * 是否为第一页 */ @JsonIgnore public boolean isFirstPage() { return firstPage; } /** * 是否为最后一页 */ @JsonIgnore public boolean isLastPage() { return lastPage; } /** * 上一页索引值 */ @JsonIgnore public int getPrev() { if (isFirstPage()) { return pageNo; } else { return pageNo - 1; } } /** * 下一页索引值 */ @JsonIgnore public int getNext() { if (isLastPage()) { return pageNo; } else { return pageNo + 1; } } /** * 获取本页数据对象列表 * * @return List */ public List getList() { return list; } /** * 设置本页数据对象列表 * * @param list list */ public Page setList(List list) { this.list = list; initialize(); return this; } /** * 获取查询排序字符串 * 可防止Order By部分的SQL注入 */ @JsonIgnore public String getOrderBy() { if (StringUtils.isBlank(orderBy)) { return null; } // SQL过滤,防止SQL注入 String reg = "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|" + "(\\b(select|update|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)"; Pattern sqlPattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE); if (sqlPattern.matcher(orderBy).find()) { return null; } return orderBy; } /** * 设置查询的排序条件 * 标准查询有效,实例: updatedate desc, name asc */ public void setOrderBy(String orderBy) { this.orderBy = orderBy; } /** * 设置提示消息,显示在“共n条”之后 * * @param message */ public void setMessage(String message) { this.message = message; } /** * 分页是否有效 * * @return this.pageSize==-1 */ @JsonIgnore public boolean isDisabled() { return this.pageSize == -1; } /** * 是否进行总数统计 * * @return this.count==-1 */ @JsonIgnore public boolean isNotCount() { return this.count == -1; } /** * 获取 Hibernate FirstResult,工作流模块要使用本方法 * SQLHelper类要使用本方法(重要) */ public int getFirstResult() { int firstResult = (getPageNo() - 1) * getPageSize(); if (firstResult >= getCount()) { firstResult = 0; } return firstResult; } /** * 获取 Hibernate MaxResults,工作流模块要使用本方法 * SQLHelper类要使用本方法(重要) */ public int getMaxResults() { return getPageSize(); } public String getPageURL() { return pageURL; } public int getLength() { return length; } public int getSlider() { return slider; } public String getMessage() { return message; } public boolean isBeyondPage() { return beyondPage; } public void setBeyondPage(boolean beyondPage) { this.beyondPage = beyondPage; } }




    © 2015 - 2024 Weber Informatics LLC | Privacy Policy