package com.skyline.common.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.skyline.common.bean.Page;
/**
* 分页标签
*
* @author wuqh
*/
public class PageTag extends TagSupport {
private static final long serialVersionUID = 6328083803585909955L;
private static final Log LOGGER = LogFactory.getLog(PageTag.class);
/** 分页对象 */
private Page page;
/** 当前页的class(例如<span class="currentPage">中的currentPage) */
private String curClass;
/** 当前页的style */
private String curStyle;
/** 非前页的style */
private String normalClass;
/** 当前页的style */
private String normalStyle;
/** 围在页数外面的字符串(写法XX%sYY,例如 第%s页,最后会变成 第2页 这样) */
private String decStr;
/** 页面url(xxx.html/xxx.html?a=x&b=y) */
private String url;
/** 当前页是否显示链接(true则当前页也是<a>标签,否则为<span>) */
private Boolean arcCur;
/** 显示的最多页数(例如5,则显示1,2,3,4,5或者2,3,4,5,6等等) */
private Integer maxSize;
/** url是否含有参数,有就在原有的基础上加&curpage=x,否侧加?curpage=x */
private boolean hasParam;
/** 显示最前的maxSize页,即第一页在显示范围之内,且最后一页在显示范围之外 */
private static final int START = 1;
/** 显示中间的maxSize页,即第一页和后一页都在显示范围之外 */
private static final int MIDDLE = 2;
/** 显示最后的maxSize页,即第一页在显示范围之外,且最后一页在显示范围之内 */
private static final int END = 3;
/** 只显示maxSize页 */
private static final int NONE = 0;
/** 当前显示属于START、MIDDLE、END、NONE中的哪种 */
private int type = NONE;
@Override
public int doEndTag() throws JspException {
// 多于一页才显示分页
if (null == page || 1 == page.getTotalPage()) {
return SKIP_BODY;
}
String linkStr = generateTotalStr();
try {
pageContext.getOut().println(linkStr);
} catch (IOException e) {
LOGGER.warn("调用page出错", e);
}
setToDefault();
return EVAL_BODY_INCLUDE;
}
private void setToDefault() {
page = null;
curClass = null;;
curStyle = null;
normalClass = null;
normalStyle = null;;
decStr = null;
url = null;;
arcCur = false;
maxSize = 5;
hasParam = false;
type = NONE;
}
/**
* 组合所有的链接,产生最后需要显示的链接
*/
private String generateTotalStr() {
StringBuilder builder = new StringBuilder();
// 必须放第一位,只有它调用getIndexAarry,刷新type
String mainLink = generateMainLinkStr();
String firstLink = generateFirstLinkStr();
String preLink = generatePreLinkStr();
String nextLink = generateNextLinkStr();
String lastLink = generateLastLinkStr();
// 超链接格式为 [上一页][ 1(同主体的第一页) ... ]主体(即 1 2 3 等等)[ ... X(同主体的最后一页)][下一页]
builder.append(preLink);
builder.append(' ');
builder.append(firstLink);
builder.append(' ');
if (!firstLink.equals("")) {
builder.append("... ");
}
builder.append(mainLink);
builder.append(' ');
if (!lastLink.equals("")) {
builder.append("... ");
}
builder.append(lastLink);
builder.append(' ');
builder.append(nextLink);
return builder.toString();
}
/**
* 产生上一页的链接(当前页非第一页才会有链接,否则为空串)
*
*/
private String generatePreLinkStr() {
if (page.isFirst()) {
return "";
} else {
return generateLinkStr(true, normalClass, normalStyle, page
.getCurpage() - 1, url, "上一页");
}
}
/**
* 产生下一页的链接(当前页非最后页才会有链接,否则为空串)
*
*/
private String generateNextLinkStr() {
if (page.isLast()) {
return "";
} else {
return generateLinkStr(true, normalClass, normalStyle, page
.getCurpage() + 1, url, "下一页");
}
}
/**
* 产生第一页的链接(第一页不在显示返回之内才产生)
*
*/
private String generateFirstLinkStr() {
if (type == START || type == NONE) {
return "";
} else {
return generateLinkStr(true, normalClass, normalStyle, 1, url,
decStr);
}
}
/**
* 产生最后页的链接(最后页不在显示返回之内才产生)
*
*/
private String generateLastLinkStr() {
if (type == END || type == NONE) {
return "";
} else {
return generateLinkStr(true, normalClass, normalStyle, page
.getTotalPage(), url, decStr);
}
}
/**
* 产生maxSize页的超链接
*/
private String generateMainLinkStr() {
Integer[] index = getIndexAarry(page, maxSize);
StringBuilder linkStr = new StringBuilder();
int length = index.length;
for (int i = 0; i < length; i++) {
if (index[i] == page.getCurpage()) {
linkStr.append(generateLinkStr(arcCur, curClass, curStyle, page
.getCurpage(), url, decStr));
} else {
linkStr.append(generateLinkStr(true, normalClass, normalStyle,
index[i], url, decStr));
}
linkStr.append(' ');
}
return linkStr.toString();
}
/**
* 产生某一页的超链接
*
* @param arcCur
* 该页是否是超链接,是就用<a>否则用<span>
* @param curClass
* 该页的class属性
* @param curStyle
* 该页的style属性
* @param curpage
* 该页是第几页
* @param url
* 该页的超链接
* @param decStr
* 围在页数外面的字符串(写法XX%sYY,例如 第%s页,最后会变成 第2页 这样)
*/
private String generateLinkStr(Boolean arcCur, String curClass,
String curStyle, Integer curpage, String url, String decStr) {
if (arcCur == null) {
arcCur = false;
}
// 把decStr结合页码后产生的串
String dec = curpage.toString();
decStr = StringUtils.trimToNull(decStr);
if (null != decStr) {
dec = decStr.replace("%s", dec);
}
StringBuilder cur = new StringBuilder();
if (arcCur) {
// url是否含有参数,有就在原有的基础上加&curpage=x,否侧加?curpage=x
cur.append("<a href=\"").append(url);
if (hasParam) {
cur.append('&');
} else {
cur.append('?');
}
cur.append("curpage=").append(curpage).append('\"');
} else {
cur.append("<span");
}
if (null != StringUtils.trimToNull(curClass)) {
cur.append(" class=\"").append(curClass.trim()).append('\"');
}
if (null != StringUtils.trimToNull(curStyle)) {
cur.append(" style=\"").append(curStyle.trim()).append('\"');
}
cur.append('>').append(dec).append("</");
if (arcCur) {
cur.append("a>");
} else {
cur.append("span>");
}
return cur.toString();
}
/**
* 获取需要的页的数组(同时刷新type),比如:一共10页,最多显示5页,当前页为第6也,那么显示[4,5,6,7,8]这几页,如果当前页为9,那么显示[6,7,8,9,10]
*
* @param page
* 分页类,用于获取总页数和当前页数
* @param maxSize
* 最多显示多少页
*/
private Integer[] getIndexAarry(Page page, Integer maxSize) {
int total = page.getTotalPage();
int current = page.getCurpage();
// 如果总页数小于最多显示页数,则全部显示
if (total <= maxSize) {
type = NONE;
Integer[] index = new Integer[total];
for (int i = 0; i < total; i++) {
index[i] = i + 1;
}
return index;
}
/**
* <pre>
* 分情况讨论:
* (1)、何时永远显示1...maxSize:
* 如果maxSize为偶数,则当前页在1...maxSize/2时;
* 如果maxSize为奇数,则当前页为1...(maxSize/2 +1)时,
* 故得当前页为(maxSize + 1) / 2
* (2)、何时永远显示最后maxSize页:
* 不论奇偶,当前页在(total-maxSize/2)...total时
* (3)、中间时从哪页开始显示:
* 如果maxSize为偶数,则从 当前页-maxSize/2+1 开始显示
* 如果maxSize为奇数,则从 当前页-maxSize/2 开始显示
* 故从 当前页-(maxSize+1)/2+1 开始显示
* </pre>
*/
// 当前页靠前则middle=(maxSize + 1) / 2;否则middle = maxSize / 2;
// 前面几页不需要动
int middle = (maxSize + 1) / 2;
if (current <= middle) {
type = START;
Integer[] index = new Integer[maxSize];
for (int i = 0; i < maxSize; i++) {
index[i] = i + 1;
}
return index;
}
// 后面几页也不需要动
middle = maxSize / 2;
if ((current + middle) >= total) {
type = END;
Integer[] index = new Integer[maxSize];
for (int i = 0, value = (total - maxSize + 1); i < maxSize; i++, value++) {
index[i] = value;
}
return index;
}
// 中间的需要动
type = MIDDLE;
middle = (maxSize + 1) / 2;
Integer[] index = new Integer[maxSize];
int startIndex = current - middle + 1;
for (int i = 0; i < maxSize; i++, startIndex++) {
index[i] = startIndex;
}
return index;
}
public void setPage(Page page) {
this.page = page;
}
public void setCurClass(String curClass) {
this.curClass = curClass;
}
public void setCurStyle(String curStyle) {
this.curStyle = curStyle;
}
public void setNormalClass(String normalClass) {
this.normalClass = normalClass;
}
public void setNormalStyle(String normalStyle) {
this.normalStyle = normalStyle;
}
public void setUrl(String url) {
this.url = url;
if (url.indexOf('?') != -1) {
hasParam = true;
} else {
hasParam = false;
}
}
public void setArcCur(Boolean arcCur) {
this.arcCur = arcCur;
}
public void setMaxSize(Integer maxSize) {
this.maxSize = maxSize;
}
public void setDecStr(String decStr) {
this.decStr = decStr;
}
public static void main(String... args) {
Page page = new Page();
page.setCurpage(4);
page.setSize(20);
page.setTotal(200);
PageTag tag = new PageTag();
tag.setPage(page);
tag.setMaxSize(5);
tag.setUrl("*.do");
System.out.println();
System.out.println(page.getCurpage());
System.out.println(tag.generateMainLinkStr());
System.out.println(tag.generatePreLinkStr());
System.out.println(tag.generateNextLinkStr());
System.out.println(tag.generateFirstLinkStr());
System.out.println(tag.generateLastLinkStr());
System.out.println(tag.generateTotalStr());
}
}