长了就用...隐藏一部分,我把这一串数字提取出来做一个数据容器,取名分页条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,用户继承这个类然后重写两个方法以提供数据,框架会在运行时先从缓存里读取数据,然后用一个分页标签显示分页条。