分页,以JavaEye为例子,长得像这两幅图:
长了就用...隐藏一部分,我把这一串数字提取出来做一个数据容器,取名分页条PageBar,里面就是一串数字,比如存放上面图片中的1,2,3 545,546,...用-1代替,得到一个类
public class CssPageBar {
private int [] linkNums;
public int[] getLinkNums() {
return linkNums;
}
public void setLinkNums(int[] linkNums) {
this.linkNums = linkNums;
}
}
分页只是滚动导航数据记录,但是用户真正想看到的记录内容必须用一个对象来表示,取名Page,泛化一下,运行时装入各种类型的待显示数据,同时把判断当前这个Page是否有下页和上页的责任付给它,因为各个Page在数据记录中的位置是可以确定的,所以这个很好计算,于是Page类代码如下
public class Page<T> {
private int pageNo = 1;// 第几页
private int pageSize = 3;// 每页显示的记录数
private int totalCount;// 数据中记录的总条数
private List<T> result = new ArrayList<T>();// 每页需要显示的真实数据记录
private String orderBy = null;
private boolean asc = true;
private Map queryParams = new HashMap();// 封装页面的查询参数
public Page() {
}
public Page(int pageNo) {
this.pageNo = pageNo;
}
// 每页的第一条记录在结果集中的位置
public int getPageFirst() {
return ((pageNo - 1) * pageSize);
}
// 总页数,这个是根据totalcount和pageSize计算的
public int getTotalPages() {
if (totalCount == 0)
return 0;
int count = totalCount / pageSize;
if (totalCount % pageSize > 0) {
count++;
}
return count;
}
/**
* 是否还有下一页.
*/
public boolean isHasNext() {
return (pageNo + 1 <= getTotalPages());
}
/**
* 返回下页的页号,序号从1开始.
*/
public int getNextPage() {
if (isHasNext())
return pageNo + 1;
else
return pageNo;
}
/**
* 是否还有上一页.
*/
public boolean isHasPre() {
return (pageNo - 1 >= 1);
}
/**
* 返回上页的页号,序号从1开始.
*/
public int getPrePage() {
if (isHasPre())
return pageNo - 1;
else
return pageNo;
}
/**
* 设置查询参数
*/
public void setQueryParam(String paramName, String paramValue) {
this.queryParams.put(paramName, paramValue);
}
/**
*
* 多条件查询的URL参数
*/
public String getUrlParam() {
StringBuilder urlParam = new StringBuilder();
Map params = this.getQueryParams();
Iterator<String> keys = params.keySet().iterator();
if (params != null && keys.hasNext()) {
String key = keys.next();
urlParam.append(key).append("=").append(params.get(key));
while (keys.hasNext()) {
key = keys.next();
urlParam.append("&").append(key).append("=").append(
params.get(key));
}
}
return urlParam.toString();
}
/**
* 单个的排序字段.
*/
public String getOrderBy() {
return orderBy;
}
public void setOrderBy(String orderBy) {
this.orderBy = orderBy;
}
public boolean isOrderBySetted() {
return this.orderBy != null;
}
/**
* 是否升序,默认为true.
*/
public boolean isAsc() {
return asc;
}
public void setAsc(boolean asc) {
this.asc = asc;
}
public int getPageNo() {
return pageNo;
}
public void setPageNo(int pageNo) {
this.pageNo = pageNo;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public List<T> getResult() {
return result;
}
public void setResult(List<T> result) {
this.result = result;
}
public Map getQueryParams() {
return queryParams;
}
}
把这两个对象放到页面的渲染上下文中就可以实现分页了,因为后台只提供数据,前端可用各种CSS来控制显示样式,改名刚才那个PageBar为CssPageBar,这个对象是通过分析Page对象得到的,所以另外需要一个工具类来做这个事情,代码如下
public class PageProcessor {
public static int THRESHOLDFORELLIPSIS = 5;// 预设值,系统默认为5
public <T> CssPageBar process(Page<T> page) {
int totalPage = page.getTotalPages();
int currentPage = page.getPageNo();
CssPageBar cssPageBar = new CssPageBar();
cssPageBar.setLinkNums(this.linkNums(totalPage, currentPage));
return cssPageBar;
}
private int[] linkNums(int totalPage, int currentPage) {
int[] pre = new int[0]; // 当前页的前组,包含当前页
int[] next = new int[0];// 当前页的后组,不包含当前页
if (totalPage > 0) {
// 处理前组
if (currentPage <= THRESHOLDFORELLIPSIS) {
pre = new int[currentPage];
for (int i = 0; i < pre.length; i++) {
pre[i] = i + 1;
}
} else if (currentPage == totalPage) {
pre = new int[THRESHOLDFORELLIPSIS + 1];
pre[0] = 1;
pre[1] = 2;
pre[2] = -1;
pre[3] = currentPage - 2;
pre[4] = currentPage - 1;
pre[5] = currentPage;
} else {
pre = new int[THRESHOLDFORELLIPSIS];
pre[0] = 1;
pre[1] = 2;
pre[2] = -1;
pre[3] = currentPage - 1;
pre[4] = currentPage;
}
// 处理后组
if ((totalPage - currentPage) <= (THRESHOLDFORELLIPSIS - 1)) {
next = new int[totalPage - currentPage];
for (int i = 0; i < next.length; i++) {
next[i] = currentPage + i + 1;
}
} else if (currentPage == 1) {
next = new int[THRESHOLDFORELLIPSIS];
next[0] = 2;
next[1] = 3;
next[2] = -1;
next[3] = totalPage - 1;
next[4] = totalPage;
} else {
next = new int[THRESHOLDFORELLIPSIS - 1];
next[0] = currentPage + 1;
next[1] = -1;
next[2] = totalPage - 1;
next[3] = totalPage;
}
}
// 合并
int[] linkNums = new int[pre.length + next.length];
int index = 0;
for (int num : pre) {
linkNums[index++] = num;
}
for (int num : next) {
linkNums[index++] = num;
}
return linkNums;
}
}
前端显示,可用jsp或者模板引擎,用CommonTemplate的代码如下
<div id="pagination" align="center" class="pagination">
${page.totalCount}条记录,每页显示${page.pageSize}条记录,一共${page.totalPages}页:
$if{page.hasPre == true}<a href="/jdonmvcdemo?page.pageNo=${page.prePage}">上一页</a>$end
$if{page.hasPre != true}<span class=disabled >上一页</span>$end
$for{number : cssPageBar.linkNums}
$if{number == -1}<span class="disabled">...</span>$end
$if{number == page.pageNo}<span class="current">${page.pageNo}</span>$end
$if{number != -1 && number != page.pageNo}<a href="/jdonmvcdemo?page.pageNo=${number}"/>${number}</a>$end
$end
$if{page.hasNext == true}<a href="/jdonmvcdemo?page.pageNo=${page.nextPage}">下一页</a>$end
$if{page.hasNext != true}<span class=disabled >下一页</span>$end
</div>
用Jsp的代码如下
<div id="pagination" align="center" class="pagination">
${page.totalCount}条记录,每页显示${page.pageSize}条记录,一共${page.totalPages}页:
<c:if test="${page.hasPre}"><a href="/jdonmvcdemo?page.pageNo=${page.prePage}">上一页</a></c:if>
<c:if test="${!page.hasPre}"><span class=disabled >上一页</span></c:if>
<c:forEach var="number" items="${cssPageBar.linkNums}">
<c:if test="${number == -1}"><span class="disabled">...</span></c:if>
<c:if test="${number == page.pageNo}"><span class="current">${page.pageNo}</span></c:if>
<c:if test="${number != -1 && number != page.pageNo}"><a href="/jdonmvcdemo?page.pageNo=${number}"/>${number}</a></c:if>
</c:forEach>
<c:if test="${page.hasNext}"><a href="/jdonmvcdemo?page.pageNo=${page.nextPage}">下一页</a></c:if>
<c:if test="${!page.hasNext}"><span class=disabled >下一页</span></c:if>
</div>
用Velocity的代码如下
<div id="pagination" align="center" class="pagination">
$page.totalCount条记录,每页显示$page.pageSize条记录,一共$page.totalPages页:
#if($page.hasPre == true)<a href="/jdonmvcdemo?page.pageNo=$page.prePage">上一页</a>#end
#if($page.hasPre != true)<span class=disabled >上一页</span>#end
#foreach($number in $cssPageBar.linkNums)
#if($number == -1)<span class="disabled">...</span>#end
#if($number == $page.pageNo)<span class="current">$page.pageNo</span>#end
#if($number != -1 && $number != $page.pageNo)<a href="/jdonmvcdemo?page.pageNo=$number"/>$number</a>#end
#end
#if($page.hasNext == true)<a href="/jdonmvcdemo?page.pageNo=$page.nextPage">下一页</a>#end
#if($page.hasNext != true)<span class=disabled >下一页</span>#end
</div>
另外附上前端的CSS,你可以用你的想象力,或者找美工做这个样式,我们项目就是美工给我做
DIV.pagination { padding:3px; margin:3px; font-size: 10px; font-weight: bold; font-family: Verdana; } DIV.pagination a { padding: 2px 5px 2px 5px; margin-right: 2px; border: 1px solid #9aafe5; text-decoration: none; color: #2e6ab1; } DIV.pagination a:hover, .pagination a:active { border: 1px solid #dd6900; color: #000; background-color: lightyellow; text-decoration: none; } DIV.pagination .current { padding: 2px 5px 2px 5px; margin-right: 2px; border: 1px solid navy; font-weight: bold; background-color: #2e6ab1; color: #FFF; } DIV.pagination .disabled { padding: 2px 5px 2px 5px; margin-right: 2px; border: 1px solid #929292; color: #929292; }
我再Jdon也贴过代码,链接如下http://www.jdon.com/jivejdon/thread/36398
顺便提一下Jdon框架中的分页实现,Jdon框架有CQRS的味道,banq在查询端抽象了一个ModelListAction,用户继承这个类然后重写两个方法以提供数据,框架会在运行时先从缓存里读取数据,然后用一个分页标签显示分页条。