首先聲明我也是參考了在Struts2中實現自定義分頁標簽全攻略(一)后才寫的此文,做了點小改動,非原創也非抄襲,只是記錄下學習的過程。源碼在jar包中,最后有鏈接。
首先看看分頁的效果圖吧,

然后開始標簽的開發。
第一步,先創建一個tld文件,這個文件的作用是定義標簽,表明標簽的名字,處理類,引用URI還有屬性等信息。此文件放在/WEB-INF/下。
pager.tld
<?xml version="1.0" encoding="UTF-8"?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0"> <tlib-version>1.0</tlib-version> <short-name>pager</short-name> <uri>http://page.way2a.com/tag</uri> <tag> <!-- 標簽名 --> <name>page</name> <!-- 對應的標簽處理類 --> <tag-class>com.way2a.common.util.PageTag</tag-class> <!-- 標簽主體類型 --> <body-content>empty</body-content> <!-- 標簽屬性描述 --> <attribute> <!-- 屬性名 當前頁數 --> <name>pageNo</name> <!-- 是否是必須的 --> <required>true</required> <!-- 設置屬性的值是否可以在jsp編譯時動態生成 --> <rtexprvalue>true</rtexprvalue> <!-- 屬性的數據類型 --> <type>int</type> </attribute> <attribute> <!-- 總記錄條數 --> <name>totalRecord</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>int</type> </attribute> <attribute> <!-- 每頁展示的條數 --> <name>pageSize</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>int</type> </attribute> <attribute> <!-- 點擊分頁鏈接后跳轉的地址 --> <name>url</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>String</type> </attribute> </tag> </taglib>
第二步,根據上面tld文件的<tag-class>標簽創建標簽處理類 com.way2a.common.util.PageTag.java
package com.way2a.common.util; import java.io.IOException; import java.util.Enumeration; import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.TagSupport; /** * 分頁標簽處理類 * @author way2a * */ public class PageTag extends TagSupport{ private static final long serialVersionUID = 6179314241821348095L; private int pageNo = 1; private int pageSize = 10; private int totalRecord ; private String url; @Override public int doStartTag() throws JspException { if(pageSize <= 0){ pageSize = 10; } //計算總的頁數 int pageCount = (totalRecord % pageSize == 0)?(totalRecord / pageSize):(totalRecord / pageSize + 1); //設置最多能顯示多少個頁數按鈕 int maxShowButton = 5; StringBuilder sb = new StringBuilder(); //拼接分頁樣式 sb.append("<style type=\"text/css\">"); sb.append(".pagination {clear:both;color:#323232;padding: 10px;float:right;font-size:13px;}"); sb.append(".pagination a, .pagination a:link, .pagination a:visited {padding:2px 5px;margin:2px;border:1px solid #b5b5b5;text-decoration:none;color:#006699;}"); sb.append(".pagination a:hover, .pagination a:active {background:#fff; text-decoration:none;}"); sb.append(".pagination span.current {padding: 2px 5px;margin: 2px;border: 1px solid #b5b5b5;font-weight: bold;background-color: #fdfdfd;box-shadow:1px 4px 6px rgba(0,0,0,0.2) inset;}"); sb.append(".pagination span.disabled {padding: 2px 5px;margin: 2px;border: 1px solid #eee; color: #ddd;}"); sb.append("</style>\r\n"); if(this.totalRecord == 0){ sb.append("<div style=\"width:100%;text-align:center;display:block;font-size:15px;\" >\r\n"); sb.append("<Strong>沒有可顯示的項目</Strong>\r\n"); }else{ sb.append("<div class=\"pagination\" >\r\n"); //對頁數進行越界處理 if(pageNo > pageCount){ pageNo = pageCount; } if(pageNo < 1){ pageNo = 1; } sb.append("<form method=\"post\" action=\"").append(this.url) .append("\" name=\"paramForm\">\r\n"); //獲取當前頁面request里的所有請求參數 HttpServletRequest request = (HttpServletRequest)this.pageContext.getRequest(); Enumeration<String> paramNames = request.getParameterNames(); //遍歷枚舉里面的參數,與分頁有關的直接設置到屬性上,其他參數放置到type為hidden的input中 String name = null; String value = null; while(paramNames.hasMoreElements()){ name = paramNames.nextElement(); value = request.getParameter(name); if("pageNo".equals(name)){ if(value != null && !"".equals(value)){ this.pageNo = Integer.parseInt(value); } }else { sb.append("<input type=\"hidden\" name=\"").append(name) .append("\" value=\"").append(value).append("\" />\r\n"); } } sb.append("<input type=\"hidden\" name=\"").append("pageNo") .append("\" value=\"").append(this.pageNo).append("\" />\r\n"); sb.append("</form>\r\n"); sb.append("<a href=\"javascript:turnOverPage(").append(1) .append(")\">首頁</a>\r\n"); //當前頁面為第一頁時不顯示上一頁 if(pageNo == 1){ sb.append("<span class=\"disabled\">上一頁</span>\r\n"); }else { sb.append("<a href=\"javascript:turnOverPage(").append(this.pageNo -1) .append(")\" >上一頁</a>\r\n"); } //設置顯示按鈕的數量 int showButton = maxShowButton; //當頁數不夠maxShowButton時 if(pageCount < maxShowButton){ showButton = pageCount; } //標識顯示的按鈕上的開始下標 int startPageIndex = 1; //當頁數為第一頁或第二頁時 if(this.pageNo ==1 || this.pageNo ==2){ startPageIndex = 1; }else{ startPageIndex = this.pageNo - 2; } //當頁數為倒數第一或第二頁時 6 7 8 [9] 10 6 7 8 9 [10] 其他都是從當前頁面的前2個開始,展示maxShowButton個. //當總頁數不足maxShowButton時也適用,因為此時showButton等於pageCount,開始下標一直為1. if(this.pageNo == pageCount || this.pageNo == pageCount - 1 ){ startPageIndex = pageCount - showButton + 1; } //循環將按鈕拼接到HTML上 for (int i = 0; i < showButton; i++) { int pageIndex = startPageIndex++; //如果是當前頁,則改變樣式,不可點擊。 if(pageIndex == this.pageNo){ sb.append("<span class=\"current\">").append(pageIndex).append("</span>\r\n"); }else{ sb.append("<a href=\"javascript:turnOverPage(").append(pageIndex).append(")\">").append(pageIndex).append("</a>\r\n"); } } //如果到達了最后一頁,則下一頁按鈕不可用 if(this.pageNo == pageCount){ sb.append("<span class=\"disabled\">下一頁</span>\r\n"); }else{ sb.append("<a href=\"javascript:turnOverPage(").append(this.pageNo + 1) .append(")\" >下一頁</a>\r\n"); } sb.append("<a href=\"javascript:turnOverPage(").append(pageCount) .append(")\">末頁</a>\r\n"); //拼接總記錄條數和總頁數 sb.append("共<strong>").append(this.totalRecord).append("</strong>條,").append("共<strong>") .append(pageCount).append("</strong>頁"); sb.append("<script type=\"text/javascript\">\r\n"); sb.append("function turnOverPage(no){\r\n"); sb.append("if(no>").append(pageCount).append("){"); sb.append("no=").append(pageCount).append(";}\r\n"); sb.append("if(no<1){ no=1;}\r\n"); sb.append("document.paramForm.pageNo.value=no;\r\n"); sb.append("document.paramForm.submit();\r\n"); sb.append("}\r\n"); sb.append("</script>\r\n"); } sb.append("</div>\r\n"); try { this.pageContext.getOut().println(sb.toString()); } catch (IOException e) { throw new JspException(e); } return 0; } 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 getTotalRecord() { return totalRecord; } public void setTotalRecord(int totalRecord) { this.totalRecord = totalRecord; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }
這個java類會在引用了這個標簽的地方輸出HTML代碼替換掉標簽。
第三步,在jsp頁面頭部引入標簽
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib uri="http://page.way2a.com/tag" prefix="pager" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head><title></title></head> <body> <h2>hello</h2> <pager:page pageSize="10" pageNo="1" url="/PageTag/HelloServlet" totalRecord="200"/> </body> </html>
由於只是演示,就把參數寫死了,實際中用${}獲取request中相應的參數值。
然后說個問題,我在ssm項目中使用時發現,url參數這里填寫<%=contextPath%>/xxx/xxx時,訪問頁面會報錯,org.apache.jasper.JasperException:attribute value for [url] is not properly terminated。
上網查了后發現好像這里不能用<%=xxx%>與/xxx混合,要么使用純字符串路徑 xxx/xxx,要么只用表達式<%=url%>。應該是不支持解析表達式值后再拼接字符串。
還有一個點就是點擊頁數按鈕使用的是表單post提交,所以@RequestMapping()不要寫method=RequestMethod.GET,否則報405。
到這里就開發完了,但是如果每個項目要用到都去建這個類和tld文件顯然是很麻煩的,因此只需要把這個class文件和tld文件放到classpath上就行了,可以打包成一個jar包。
tld文件放在META-INF文件夾,然后cmd中進入到所在文件夾下,使用以下命令進行打包:jar -cvf xxx-xxx.jar *
最后把我的jar包放上來給有需要的人參考下。
鏈接: https://pan.baidu.com/s/1o76RFHw 密碼: 7fh8
