-
分页标签的开发
一直想写一个自己用的顺手的分页标签。网上的标签大部分都是在标签内部自成体系,不方便和页面上的查询条件结合在一起,即使有这样的标签,也不一定符合自己的实际需要。在这种需求的驱使下,决定写一个自己的分页标签,能够方便的和页面查询结合在一起,也能满足项目中的大部分需要。
在参考网上其他人的自定义分页标签的基础上,加上自己的一些个性化需求,完成了自定义分页标签的编写。分页标签的样式如下:
分页标签分为四部分:第一部分是记录数和总页数;第二部分是分页页码;第三部分是修改设置每页显示的记录数;第四部分是直接输入页码跳转。
STRUTS2下的自定义标签开发细节就不再复述,简单描述一下开发过程:
- 第一步:建立一个WEB工程
- 第二部:java部分的代码和普通WEB开发一样,路径在src目录的具体包中;
- 第三部:tld文件放置在/WEB-INF/下。
通过上述步骤的完成后,就可以直接利用建立的工程进行测试标签是否正确。多的不说了,直接把代码贴出来:
PagerTag.java
/**
* TODO
* Struts2Pager.java
* Administrator2012-12-18
*/
package com.citybug.tag;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.components.Component;
import org.apache.struts2.views.jsp.ComponentTagSupport;
import com.opensymphony.xwork2.util.ValueStack;
/**
* @author Administrator
*
*/
public class PagerTag extends ComponentTagSupport {
/**
*
*/
private static final long serialVersionUID = 1L;
private String pageSize;
private String pageNo;
private String recordCount;
private String pageCount;
private String recordNum;
private String showChangePageSize;
private String showJumpPage;
private String formId;
public String getPageSize(){
return pageSize;
}
public void setPageSize(String pageSize){
this.pageSize=pageSize;
}
public String getPageNo(){
return pageNo;
}
public void setPageNo(String pageNo){
this.pageNo=pageNo;
}
public String getRecordCount(){
return recordCount;
}
public void setRecordCount(String recordCount){
this.recordCount=recordCount;
}
public String getPageCount(){
return pageCount;
}
public void setPageCount(String pageCount){
this.pageCount=pageCount;
}
public String getShowChangePageSize(){
return showChangePageSize;
}
public void setShowChangePageSize(String showChangePageSize){
this.showChangePageSize=showChangePageSize;
}
public String getShowJumpPage(){
return showJumpPage;
}
public void setShowJumpPage(String showJumpPage){
this.showJumpPage=showJumpPage;
}
public String getFormId(){
return formId;
}
public void setFormId(String formId){
this.formId=formId;
}
public String getRecordNum(){
return recordNum;
}
public void setRecordNum(String recordNum){
this.recordNum=recordNum;
}
@Override
public Component getBean(ValueStack arg0, HttpServletRequest arg1,
HttpServletResponse arg2) {
return new Pager(arg0,arg1);
}
protected void populateParams(){
super.populateParams();
Pager pager=(Pager)component;
pager.setPageNo(pageNo);
pager.setPageSize(pageSize);
pager.setRecordCount(recordCount);
pager.setPageCount(pageCount);
pager.setShowChangePageSize(showChangePageSize);
pager.setShowJumpPage(showJumpPage);
pager.setFormId(formId);
pager.setRecordNum(recordNum);
}
}
Pager.java
/**
* TODO
* Pager.java
* Administrator2012-12-18
*/
package com.citybug.tag;
import java.io.IOException;
import java.io.Writer;
import java.util.Enumeration;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.StrutsStatics;
import org.apache.struts2.components.Component;
import org.apache.struts2.dispatcher.StrutsRequestWrapper;
import com.opensymphony.xwork2.util.ValueStack;
/**
* @author Administrator
*
*/
public class Pager extends Component {
private HttpServletRequest request;
private String pageNo; //当前页码
private String pageSize; //每页记录数
private String recordCount; //总记录数
private String pageCount; //总页数
private String showChangePageSize;
private String showJumpPage;
private String formId;
private String recordNum;
public HttpServletRequest getRequest() {
return request;
}
public void setRequest(HttpServletRequest request) {
this.request = request;
}
public String getPageNo(){
return pageNo;
}
public void setPageNo(String pageNo){
this.pageNo=pageNo;
}
public String getPageSize(){
return pageSize;
}
public void setPageSize(String pageSize){
this.pageSize=pageSize;
}
public String getRecordCount(){
return recordCount;
}
public void setRecordCount(String recordCount){
this.recordCount=recordCount;
}
public String setPageCount(){
return pageCount;
}
public void setPageCount(String pageCount){
this.pageCount=pageCount;
}
public Pager(ValueStack arg0, HttpServletRequest request) {
super(arg0);
this.request = request;
}
public String getShowChangePageSize(){
return showChangePageSize;
}
public void setShowChangePageSize(String showChangePageSize){
this.showChangePageSize=showChangePageSize;
}
public String getShowJumpPage(){
return showJumpPage;
}
public void setShowJumpPage(String showJumpPage){
this.showJumpPage=showJumpPage;
}
public String getFormId(){
return formId;
}
public void setFormId(String formId){
this.formId=formId;
}
public String getRecordNum(){
return recordNum;
}
public void setRecordNum(String recordNum){
this.recordNum=recordNum;
}
@Override
public boolean end(Writer writer,String body) {
boolean result = super.start(writer);
int iPageNo;
int iRecordCount;
int iPageCount;
int iPageSize;
boolean bShowChangePageSize;
boolean bShowJumpPage;
StringBuilder sb = new StringBuilder();
try {
//从ValueStack中取出数值
Object obj=this.getStack().findValue(pageNo);
pageNo = String.valueOf((Integer)obj);
obj=this.getStack().findValue(recordCount);
recordCount = String.valueOf((Integer)obj);
obj=this.getStack().findValue(pageSize);
pageSize=String.valueOf((Integer)obj);
obj=this.getStack().findValue(showChangePageSize);
bShowChangePageSize=Boolean.valueOf(String.valueOf(obj));
obj=this.getStack().findValue(recordNum);
recordNum=String.valueOf((Integer)obj);
obj=this.getStack().findValue(showJumpPage);
bShowJumpPage=Boolean.valueOf(String.valueOf(obj));
iPageSize=Integer.valueOf(pageSize);
iPageNo=Integer.valueOf(pageNo);
iRecordCount=Integer.valueOf(recordCount);
iPageCount=(iRecordCount+iPageSize-1)/iPageSize;
sb.append("<style type=\"text/css\">");
sb.append(".pagination {padding: 5px;float:right;font-size:10px;}");
sb.append(".pagination a, .pagination a:link, .pagination a:visited {padding:2px 5px;margin:2px;border:1px solid #aaaadd;text-decoration:none;color:#006699;}");
sb.append(".pagination a:hover, .pagination a:active {border: 1px solid #ff0000;color: #000;text-decoration: none;}");
sb.append(".pagination span.current {padding: 2px 5px;margin: 2px;border: 1px solid #ff0000;font-weight: bold;background-color: #ff0000;color: #FFF;}");
sb.append(".pagination span.disabled {padding: 2px 5px;margin: 2px;border: 1px solid #eee; color: #ddd;}");
sb.append("</style>\r\n");
sb.append("<div class=\"pagination\">\r\n");
if(iRecordCount == 0){
sb.append("<strong>没有可显示的项目</strong>\r\n");
}else{
//页号越界处理
if(iPageNo > iPageCount){ iPageNo = iPageCount; }
if(iPageNo < 1){ iPageNo = 1; }
// 把当前页号设置成请求参数
sb.append("<input type=\"hidden\" name=\"").append("pageNo")
.append("\" value=\"").append(pageNo).append("\"/>\r\n");
// 输出统计数据
sb.append("共 <strong>").append(recordCount)
.append("</strong> 项")
.append(", 共 <strong>")
.append(iPageCount)
.append("</strong> 页: \r\n");
//上一页处理
if (iPageNo == 1) {
sb.append("<span class=\"disabled\">« 上一页")
.append("</span>\r\n");
} else {
sb.append("<a href=\"javascript:turnOverPage(")
.append((iPageNo - 1))
.append(")\">« 上一页</a>\r\n");
}
//如果前面页数过多,显示"..."
int start = 1;
if(iPageNo > 4){
start = iPageNo - 1;
sb.append("<a href=\"javascript:turnOverPage(1)\">1</a>\r\n")
.append("<a href=\"javascript:turnOverPage(2)\">2</a>\r\n")
.append("…\r\n");
}
//显示当前页附近的页
int end = iPageNo + 1;
if(end > iPageCount){
end = iPageCount;
}
for(int i = start; i <= end; i++){
if(iPageNo == i){ //当前页号不需要超链接
sb.append("<span class=\"current\">")
.append(i)
.append("</span>\r\n");
}else{
sb.append("<a href=\"javascript:turnOverPage(")
.append(i)
.append(")\">")
.append(i)
.append("</a>\r\n");
}
}
//如果后面页数过多,显示"..."
if(end < iPageCount - 2){
sb.append("…\r\n");
}
if(end < iPageCount - 1){
sb.append("<a href=\"javascript:turnOverPage(")
.append(iPageCount - 1)
.append(")\">")
.append(iPageCount - 1)
.append("</a>\r\n");
}
if(end < iPageCount){
sb.append("<a href=\"javascript:turnOverPage(")
.append(iPageCount)
.append(")\">")
.append(iPageCount)
.append("</a>\r\n");
}
//下一页处理
if (iPageNo == iPageCount) {
sb.append("<span class=\"disabled\">下一页 »")
.append("</span>\r\n");
} else {
sb.append("<a href=\"javascript:turnOverPage(")
.append((iPageNo + 1))
.append(")\">下一页 »</a>\r\n");
}
if(bShowChangePageSize){
//每页记录数
sb.append("每页记录数:<select id=\"recordNum\" name=\"recordNum\" onChange=\"turnOverPage(" + pageNo + ")\">");
if(recordNum.equals("20")){
sb.append("<option value=\"20\" selected>20</option>");
}else{
sb.append("<option value=\"20\">20</option>");
}
if(recordNum.equals("50")){
sb.append("<option value=\"50\" selected>50</option>");
}else{
sb.append("<option value=\"50\">50</option>");
}
if(recordNum.equals("100")){
sb.append("<option value=\"100\" selected>100</option>");
}else{
sb.append("<option value=\"100\">100</option>");
}
if(recordNum.equals("150")){
sb.append("<option value=\"150\" selected>150</option>");
}else{
sb.append("<option value=\"150\">150</option>");
}
if(recordNum.equals("200")){
sb.append("<option value=\"200\" selected>200</option>");
}else{
sb.append("<option value=\"200\">200</option>");
}
sb.append("</select>");
}
if(bShowJumpPage){
//跳转页
sb.append(" 跳转到<input id=\"pageNum\" type=\"text\" name=\"pageNum\" size=\"2\" length=\"5\" ")
.append("onKeyPress=\"inputInt(event)\" ")
.append(">")
.append("<a href=\"javascript:jumpPage();")
.append("\">跳转 »</a>\r\n");
}
// 生成提交表单的JS
sb.append("<script language=\"javascript\">\r\n")
.append(" function turnOverPage(no){\r\n")
.append(" if(no>").append(iPageCount).append("){")
.append(" no=").append(iPageCount).append(";}\r\n")
.append(" if(no<1){no=1;}\r\n")
.append(" document.getElementById('" + formId + "').pageNo.value=no;\r\n")
.append(" document.getElementById('" + formId + "').submit();\r\n")
.append(" }\r\n")
.append(" function inputInt(event){\r\n")
.append(" var keyNum;\r\n")
.append(" var keyCode;\r\n")
.append(" if(window.event){\r\n")
.append(" keyNum=event.keyCode;\r\n")
.append(" }else if(event.which){\r\n")
.append(" keyNum=event.which;\r\n")
.append(" }\r\n")
.append(" if(keyNum<46 || keyNum>57){\r\n")
.append(" if(window.event){\r\n")
.append(" event.returnValue=false;\r\n")
.append(" }else{\r\n")
.append(" event.preventDefault();\r\n")
.append(" }\r\n")
.append(" }\r\n")
.append(" }\r\n")
.append(" function jumpPage(){\r\n")
.append(" var no=1;\r\n")
.append(" if(document.getElementsById('pageNum').value==''){\r\n")
.append(" alert('跳转页码必须填写!');\r\n")
.append(" }else{\r\n")
.append(" no=parseInt(document.getElementsById('pageNum').value);\r\n")
.append(" }\r\n")
.append(" turnOverPage(no);\r\n")
.append(" }\r\n")
.append("</script>\r\n");
}
sb.append("</div>\r\n");
writer.write(sb.toString());
} catch (IOException ex) {
ex.printStackTrace();
}
return result;
}
}
Pager.tld
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>cb</short-name>
<uri>/citybug-tags</uri>
<display-name>"自定义分页标签"</display-name>
<tag>
<name>pager</name>
<tag-class>com.citybug.tag.PagerTag</tag-class>
<body-content>jsp</body-content>
<description>分页标签</description>
<attribute>
<name>pageNo</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>recordCount</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>pageSize</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>showChangePageSize</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>showJumpPage</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>formId</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
2.自定义标签的打包
自定义标签经过测试没有问题后,就要打包成JAR文件用到项目中去了,如何打包呢?方法比较简单:
- 建立一个空目录
- 到部署服务器下,把组成标签的java的class类复制到建立的目录中,当然,要保持class类的路径和tld中的类路径一致
- 把部署服务器下的“META_INF”复制到建立的目录中
- 把tld文件复制到META_INF目录中
- 选中目录中的全部文件,使用winrar压缩软件,把选中的文件制作成压缩包。压缩格式选择为“ZIP”,如果是“RAR”格式,项目运行时,会出现“打不开文件”的错误信息。然后将要锁文件后缀改为JAR即可。
- 把新建的JAR文件复制到项目的LIB目录下,就可以使用了。
3. 页面上如何使用
页面上使用和struts2自己的标签没有什么区别:
在页面的开头引用标签:
<%@ taglib prefix="cb" uri="/citybug-tags" %>
这个自定义标签由于要达到和查询条件融合在一起,所以需要把标签和查询条件放置在同一个form中。
<cb:pager pageNo="page.pageNo" pageSize="page.pageSize" formId="form1" recordCount="page.recordCount" showChangePageSize="true" showJumpPage="true"/>
在上面的标签使用中,有page对象,这就是action中用于返回分页信息的对象。这个对象的代码非常简单,仅仅包含三个属性和这三个属性的getter和setter方法。代码如下:
Page.java
/**
* TODO
* Page.java
* Administrator2012-12-20
*/
package com.citybug.comm;
/**
* @author Administrator
*
*/
public class Page {
private int pageNo;
private int pageSize;
private int recordCount;
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 getRecordCount(){
return recordCount;
}
public void setRecordCount(int recordCount){
this.recordCount=recordCount;
}
}
那么在action中,需要一个通用方法,把page中的各个参数之间的逻辑关系表述清楚,我的代码如下:
private Page setPagePro(int recordCount){
Page page=null;
int pageCount;
int iPageNum;
try{
pageNo=this.getPageNo();
pageSize=this.getPageSize();
recordNum=this.getRecordNum();
pageNum=this.getPageNum();
if(pageSize==0){
pageSize=20;
}
if(pageNo==0){
pageNo=1;
}
if(recordNum!=0){
if(pageSize!=recordNum){
pageSize=recordNum;
}
}
if(pageNum!=null && !pageNum.equals("")){
iPageNum=Integer.valueOf(pageNum);
if(iPageNum>0){
if(pageNo!=iPageNum){
pageNo=iPageNum;
}
}
}
pageCount=(recordCount+pageSize-1)/pageSize;
if(pageNo>pageCount){
pageNo=pageCount;
}
page=new Page();
page.setPageNo(pageNo);
page.setPageSize(pageSize);
page.setRecordCount(recordCount);
}catch(Exception ex){
ex.printStackTrace();
}
return page;
}
为什么上面要这么写,是因为标签中可以改变每页的记录数和页码的跳转,每页记录数是以默认值为准,还是以页面上“每页记录数”下拉框中选择的数量为准?是以默认的页码为准还是以跳转中输入的页码为准?就是上面这个过程要解决的问题。其中的逻辑并不复杂。
那么接下来,只要把记录list和page对象返回给jsp页面,分页就成功了!
4。分页标签开发中的几个注意事项:
- list如何传入标签?
在我们开发自定义标签时,可能会碰到要把一个list对象传给标签,然后由标签进行处理后,给出一个结果。但是struts2中却是把所有的参数认为是String。那么就会出现在自定义标签的java中要获得list对象时,就不知道如何才能获得这个list。在参照struts2的core中源码情况下,有了下面的解决办法:
在继承自“ComponentTagSupport”的类中,把list的变量类型设置为Object。
private Object list;
在继承自“Component”的类中,在方法“end(Writer writer,String body)”中获取list的对象时,用下面的语句进行转换:
obj=this.getStack().findValue((String)list);
ArrayList<?> beanList = (ArrayList<?>)obj;
这样,就可以获得list的队列内容。至于如何使用,可以使用反射,也可以对队列进行类型转换等等,这就要看具体的需要了。
- 在标签中,传入的是字符串或者具体的值,而不是变量时,如何获取到值?
看完上面的自定义标签,在end过程中,看到取值使用的是 Object obj=this.getStack().findValue(pageNo); 的方法。那么就会形成一种思维定势,认为获取标签传入的值都是采用这样的方式获取值。但是并不是如此,这是因为JSP页面上是这么写的 pageNo=”page.pageNo".那么,如果是直接写成 pageNo=“1”,就不用再使用findValue这个方法了,而是直接使用pageNo变量即可。这本不是个问题,只是在此给提个醒.