为我们的项目写的一个轻量的分页API。目的在于将分页与数据查询的逻辑完全剥离。我以前看过robbin发的通过detachedCriteria实现的分页那片贴子,里面把分页和数据查询结合在一起了。而我觉得分开更轻量,而且替换也比较容易。但是这个实现中有一个反模式,在逻辑中生成了代码,无奈之选,为了简便。其中字符生成可以自己扩展i18n实现,应该非常容易。
分页实现的接口:
package com.goldnet.framework.util.paging;
/** *//**
* 分页操作的接口
* @author Tin
*/
public interface IPagination {
/** *//**
* 默认的分页大小
*/
public static final int DEFAULT_PAGE_SIZE = 15;
/** *//**
* 默认的分页参数,指URL中用到的参数名
*/
public static final String PAGE_SIZE_KEY = "pageSize";
/** *//**
* 默认的页码参数,指URL中用到的参数名
*/
public static final String PAGE_NO_KEY = "pageno";
/** *//**
* 获取总页数
* @return 总页数
*/
int getPageSum();
/** *//**
* 下一页的页码
* @return
*/
int getNextPageNo();
/** *//**
* 上一页的页码
* @return
*/
int getPrevPageNo();
/** *//**
* 是否有下一页,即是否为最后一页
* @return 是否有下一页
*/
boolean hasNextPage();
/** *//**
* 是否有上一页,即是否为第一页
* @return 是否有上一页
*/
boolean hasPrevPage();
/** *//**
* 添加参数名称、值对,如果页面需要使用parameters传递分页外的附加参数
* @param parameterName 参数名
* @param parameterValue 参数值
*/
void addPageParameter(String parameterName, String parameterValue);
String getPageUrl();
String getPageHtmlStr();
int getItemSum();
void setItemSum(int itemSum);
String getPageExtension();
void setPageExtension(String pageExtension);
String getPageName();
void setPageName(String pageName);
int getPageNo();
void setPageNo(int pageNo);
int getPageSize();
void setPageSize(int pageSize);
} 抽象基类:
/** *//**
*
*/
package com.goldnet.framework.util.paging;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/** *//**
* 对PagingString的重构
* @author Tin
*
*/
public abstract class AbstractPagination implements IPagination {
/** *//**
* Page上显示的List中的domainModel的总数
*/
protected int itemSum = -1;
/** *//**
* 分页的大小
*/
protected int pageSize = DEFAULT_PAGE_SIZE;
/** *//**
* 页数
*/
protected int pageNo = 0;
/** *//**
* 分页的页面的相对URL,不包括后缀
*/
protected String pageName = null;
/** *//**
* 页面的URL的后缀
*/
protected String pageExtension = ".action";
/** *//**
* 参数列表
*/
protected List<PageParameter> parameterList = new LinkedList<PageParameter>();
/** *//**
* 返回的分页信息的字符串
*/
protected String pageHtmlStr = null;
/** *//**
* 默认的构造函数
* @param pageName 分页的页面的相对URL,不包括后缀
* @param pageExtension 页面的URL的后缀
* @param itemSum Page上显示的List中的domainModel的总数
* @param pageNo 页数
* @param pageSize 分页的大小
*/
public AbstractPagination(String pageName, String pageExtension,
int itemSum, int pageNo, int pageSize) {
super();
this.pageName = pageName;
this.pageExtension = pageExtension;
this.itemSum = itemSum;
this.pageNo = pageNo;
this.pageSize = pageSize;
}
/** *//**
* 无PageSize构造函数,使用默认PageSize为15
* @param pageName 分页的页面的相对URL,不包括后缀
* @param pageExtension 页面的URL的后缀
* @param itemSum Page上显示的List中的domainModel的总数
* @param pageNo 页数
*/
public AbstractPagination(String pageName, String pageExtension,
int itemSum, int pageNo) {
super();
this.pageName = pageName;
this.pageExtension = pageExtension;
this.itemSum = itemSum;
this.pageNo = pageNo;
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#getPageSum()
*/
public int getPageSum() {
if ((itemSum != -1) && (pageSize > 0)) {
return ((itemSum % pageSize) == 0) ? (itemSum / pageSize)
: ((itemSum / pageSize) + 1);
}
return 0;
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#getNextPageNo()
*/
public int getNextPageNo() {
return (pageNo < (getPageSum() - 1)) ? (pageNo + 1) : (getPageSum() -
1);
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#getPrevPageNo()
*/
public int getPrevPageNo() {
return (pageNo > 0) ? (pageNo - 1) : 0;
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#hasNextPage()
*/
public boolean hasNextPage() {
if (getPageSum() <= pageNo) {
return false;
}
return true;
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#hasPrevPage()
*/
public boolean hasPrevPage() {
if (pageNo <= 0) {
return false;
}
return true;
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#addPageParameter(java.lang.String, java.lang.String)
*/
public void addPageParameter(String parameterName, String parameterValue) {
PageParameter pp = new PageParameter(parameterName, parameterValue);
this.parameterList.add(pp);
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#getPageUrl()
*/
public String getPageUrl() {
String url = pageName + pageExtension;
if (parameterList.size() > 0) {
Iterator<PageParameter> iterator = parameterList.iterator();
PageParameter pageFirstParameter = iterator.next();
url += ("?" + pageFirstParameter.getParameterName() + "=" +
pageFirstParameter.getParameterValue());
while (iterator.hasNext()) {
PageParameter pageParameter = iterator.next();
url += ("&" + pageParameter.getParameterName() + "=" +
pageParameter.getParameterValue());
}
} else {
//补充一个?解决附加分页参数时无?的问题
url += "?";
}
if (pageSize != DEFAULT_PAGE_SIZE) {
url += ("&" + PAGE_SIZE_KEY + "=" + pageSize);
}
return url;
}
/** *//**
* 子类必须覆盖的方法,用来计算分页的字符的方法
*/
public abstract void compilePaginationString();
/** *//**
* Getters & Setters
*/
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#getPageHtmlStr()
*/
public String getPageHtmlStr() {
compilePaginationString();
return pageHtmlStr;
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#getItemSum()
*/
public int getItemSum() {
return itemSum;
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#setItemSum(int)
*/
public void setItemSum(int itemSum) {
this.itemSum = itemSum;
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#getPageExtension()
*/
public String getPageExtension() {
return pageExtension;
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#setPageExtension(java.lang.String)
*/
public void setPageExtension(String pageExtension) {
this.pageExtension = pageExtension;
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#getPageName()
*/
public String getPageName() {
return pageName;
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#setPageName(java.lang.String)
*/
public void setPageName(String pageName) {
this.pageName = pageName;
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#getPageNo()
*/
public int getPageNo() {
return pageNo;
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#setPageNo(int)
*/
public void setPageNo(int pageNo) {
this.pageNo = pageNo;
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#getPageSize()
*/
public int getPageSize() {
return pageSize;
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.IPagination#setPageSize(int)
*/
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public List<PageParameter> getParameterList() {
return parameterList;
}
public void setParameterList(List<PageParameter> parameterList) {
this.parameterList = parameterList;
}
/** *//**
* 分页参数,页面的QueryString形式都是?parameter=value的形式,此处为一对
* 数据的抽象
* @author Tin
*
*/
private class PageParameter {
/** *//**
* 参数名称
*/
private String parameterName;
/** *//**
* 参数值
*/
private String parameterValue;
/** *//**
* 唯一构造函数
* @param parameterName 参数名称
* @param parameterValue 参数值
*/
public PageParameter(String parameterName, String parameterValue) {
this.parameterName = parameterName;
this.parameterValue = parameterValue;
}
public String getParameterName() {
return parameterName;
}
public String getParameterValue() {
return parameterValue;
}
}
} 默认的分页实现:
package com.goldnet.framework.util.paging;
/** *//**
* 默认的分页实现
* @author Tin
*
*/
public class DefaultPagination extends AbstractPagination {
/** *//**
* 默认的构造函数
* @param pageName 分页的页面的相对URL,不包括后缀
* @param pageExtension 页面的URL的后缀
* @param itemSum Page上显示的List中的domainModel的总数
* @param pageNo 页数
* @param pageSize 分页的大小
*/
public DefaultPagination(String pageName, String pageExtension,
int itemSum, int pageNo, int pageSize) {
super(pageName, pageExtension, itemSum, pageNo, pageSize);
}
/** *//**
* 无PageSize构造函数,使用默认PageSize为15
* @param pageName 分页的页面的相对URL,不包括后缀
* @param pageExtension 页面的URL的后缀
* @param itemSum Page上显示的List中的domainModel的总数
* @param pageNo 页数
*/
public DefaultPagination(String pageName, String pageExtension,
int itemSum, int pageNo) {
super(pageName, pageExtension, itemSum, pageNo);
}
@Override
public void compilePaginationString() {
String pageUrl = getPageUrl();
pageHtmlStr = "\u5171 " + itemSum + " \u6761 \u7b2c " +
(pageNo + 1) + " \u9875 / \u5171 " + getPageSum() +
" \u9875 <a href=\"" + pageUrl + "&" + PAGE_NO_KEY +
"=0\">\u9996\u9875</a> <a href=\"" + pageUrl + "&" +
PAGE_NO_KEY + "=" + getPrevPageNo() +
"\">\u4e0a\u4e00\u9875</a> <a href=\"" + pageUrl + "&" +
PAGE_NO_KEY + "=" + getNextPageNo() +
"\">\u4e0b\u4e00\u9875</a> <a href=\"" + pageUrl + "&" +
PAGE_NO_KEY + "=" + (getPageSum() - 1) +
"\">\u5c3e\u9875</a> \u6bcf\u9875\u663e\u793a" +
pageSize + "\u6761";
}
}
数字风格的实现:
/** *//**
*
*/
package com.goldnet.framework.util.paging;
/** *//**
* 数字页码风格的分页实现
* @author Tin
*
*/
public class PageNumberPagination extends AbstractPagination {
/** *//**
* 默认的构造函数
* @param pageName 分页的页面的相对URL,不包括后缀
* @param pageExtension 页面的URL的后缀
* @param itemSum Page上显示的List中的domainModel的总数
* @param pageNo 页数
* @param pageSize 分页的大小
*/
public PageNumberPagination(String pageName, String pageExtension,
int itemSum, int pageNo, int pageSize) {
super(pageName, pageExtension, itemSum, pageNo, pageSize);
}
/** *//**
* 无PageSize构造函数,使用默认PageSize为15
* @param pageName 分页的页面的相对URL,不包括后缀
* @param pageExtension 页面的URL的后缀
* @param itemSum Page上显示的List中的domainModel的总数
* @param pageNo 页数
*/
public PageNumberPagination(String pageName, String pageExtension,
int itemSum, int pageNo) {
super(pageName, pageExtension, itemSum, pageNo);
}
/**//* (non-Javadoc)
* @see com.goldnet.framework.util.paging.AbstractPagination#compilePaginationString()
*/
@Override
public void compilePaginationString() {
String pageUrl = getPageUrl();
StringBuffer returnString = new StringBuffer();
returnString.append("\u5171 " + itemSum + " \u6761 \u7b2c " +
(pageNo + 1) + " \u9875 / \u5171 " + getPageSum() +
" \u9875 <a href=\"" + pageUrl + "&" + PAGE_NO_KEY + "=" +
getPrevPageNo() + "\"><<</a> ");
for (int page = 0; page < getPageSum(); page++) {
if(page!=pageNo){
returnString.append("<a href=\""+pageUrl +"&"+PAGE_NO_KEY + "=" + page +"\">"+(page+1)+"</a> ");
} else {
returnString.append("<a href=\""+pageUrl +"&"+PAGE_NO_KEY + "=" + page +"\"><span style=\"background:black;color:#eee;font-size:120%;padding-left:5px;padding-right:5px;text-align:center;\">"+(page+1)+"</span></a> ");
}
}
returnString.append(" <a href=\"" + pageUrl + "&" +
PAGE_NO_KEY + "=" + getNextPageNo() +
"\">>></a> \u6bcf\u9875\u663e\u793a" + pageSize +
"\u6761");
pageHtmlStr = returnString.toString();
}
}
测试类,用的JUnit3,其实JUnit4更优雅:D
package com.goldnet.test.unittest.framework.paging;
import junit.framework.TestCase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.goldnet.framework.util.paging.DefaultPagination;
import com.goldnet.framework.util.paging.IPagination;
import com.goldnet.framework.util.paging.PageNumberPagination;
public class TestPagination extends TestCase {
protected transient final Log log = LogFactory.getLog(getClass());
protected void setUp() throws Exception {
super.setUp();
}
protected void tearDown() throws Exception {
super.tearDown();
}
public void testDefaultPainationWith3Parameters() {
IPagination p = new DefaultPagination("test",".action",50,2);
p.addPageParameter("a","b");
p.addPageParameter("c","234");
p.addPageParameter("e.ddd","34234adbb");
log.info(p.getPageHtmlStr());
}
public void testDefaultPainationWith1Parameters() {
IPagination p = new DefaultPagination("test",".action",50,2);
p.addPageParameter("a","b");
log.info(p.getPageHtmlStr());
}
public void testDefaultPainationWithNoParameters() {
IPagination p = new DefaultPagination("test",".action",50,2);
log.info(p.getPageHtmlStr());
}
public void testDefaultPainationWith3ParametersAndCustomPageSize() {
IPagination p = new DefaultPagination("test",".action",50,2,5);
p.addPageParameter("a","b");
p.addPageParameter("c","234");
p.addPageParameter("e.ddd","34234adbb");
log.info(p.getPageHtmlStr());
}
public void testDefaultPainationWithNoParametersAndCustomPageSize() {
IPagination p = new DefaultPagination("test",".action",50,2,5);
log.info(p.getPageHtmlStr());
}
public void testPageNumberPainationWith3Parameters() {
IPagination p = new PageNumberPagination("test",".action",50,2);
p.addPageParameter("a","b");
p.addPageParameter("c","234");
p.addPageParameter("e.ddd","34234adbb");
log.info(p.getPageHtmlStr());
}
public void testPageNumberPainationWith1Parameters() {
IPagination p = new PageNumberPagination("test",".action",50,2);
p.addPageParameter("a","b");
log.info(p.getPageHtmlStr());
}
public void testPageNumberPainationWithNoParameters() {
IPagination p = new PageNumberPagination("test",".action",50,2);
log.info(p.getPageHtmlStr());
}
public void testPageNumberPainationWith3ParametersAndCustomPageSize() {
IPagination p = new PageNumberPagination("test",".action",50,2,5);
p.addPageParameter("a","b");
p.addPageParameter("c","234");
p.addPageParameter("e.ddd","34234adbb");
log.info(p.getPageHtmlStr());
}
public void testPageNumberPainationWithNoParametersAndCustomPageSize() {
IPagination p = new PageNumberPagination("test",".action",50,2,5);
log.info(p.getPageHtmlStr());
}
}
说实话这么丑陋的东西本不愿意现眼……但是实在没什么可发的,应朋友所托共享出来。
特点就是分页逻辑不管你用hibernate、JDBC、iBatis或者什么其他的,都可以和它一起工作,因为我任为对于DAO或者Action来说分页逻辑就应该是pageSize、Pageno、itemSum这几个参数的传递,具体的显示上的问题应该交给第三方来负责,如taglib什么的,所以才写了这样的实现。而且这个实现应该容易扩展。配合js跳转(css也应该抽出)等可以实现更多风格:D