jsp自定义分页标签
首先声明我也是参考了在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