自定义标签
一、自定义标签概述
使用标准JSP访问、操作JavaBean,是实现展现(HTML)与业务实现(Java代码)分离的第一步。然而,标准方法功能不够强大,以至于开发者无法仅仅使用它们开发应用,还要在JSP页面中使用Java代码。
介于JavaBean中解决展现与业务实现分离的方法的不完善,就产生了JSP1.1中的自定义标签。自定义标签提供了在JavaBean中所不能实现的便利。其中就包括,自定义标签允许访问JSP隐藏的对象及它们的属性。
尽管自定义标签能编写无脚本的JSP页面,但是JSP1.1和JSP1.2中提供的经典自定义标签非常难用。直到JSP2.0,才增加两个特性,用于改善自定义标签实现。第一个特性是一个接口——SimpleTag。另一个特性是标签文件中定义标签的机制。
自定义标签的实现,叫做标签处理器,而简单标签处理器是指继承SimpleTag实现的标签处理器。
二、简单标签处理器
实现SimpleTag的标签处理器都叫作简单标签处理器;实现Tag、Iteration及BodyTag的标签处理器都叫作经典标签处理器。
简单标签处理器有着简单的生命周期,而且比经典标签处理器更加容易实现。SimpleTag接口中用于标签触发的方法只有一个——doTag,并且此方法只执行一次。业务逻辑、遍历及页面内容操作都在这里实现。简单标签处理器中的页面内容都在JspFragment类的实例中体现。
简单标签的生命周期如下:
JSP容器通过简单标签处理器的无参数构造器创建它的实例。
JSP容器通过setJspContext的方法,传入JspContext对象。
如果自定义标签被另一个自定义标签所嵌套,JSP容器就会调用setParent的方法。
JSP容器调用该标签中所定义的每个属性的set方法。
如果需要处理页面内容,JSP容器还会调用SimpleTag接口的setJspBody方法,把使用JSPFragment封装的页面内容传过来。
javax.servlet.jsp.tagext 包中也包含了一个SimpleTag的基础类:SimpleTagSupport。它提供了SimpleTag所有方法的默认实现。
三、实例
自定义标签需要有两个步骤:编写标签处理器及注册标签。
1. 编写标签处理器
packagecustomtag;importjava.io.IOException;importjava.util.StringTokenizer;importjavax.servlet.jsp.JspContext;importjavax.servlet.jsp.JspException;importjavax.servlet.jsp.JspWriter;importjavax.servlet.jsp.tagext.SimpleTagSupport;public class DataFormatterTag extendsSimpleTagSupport {private String header; //标签属性
privateString items;public voidsetHeader(String header) {this.header =header;
}public voidsetItems(String items) {this.items =items;
}public void doTag() throws IOException, JspException { //标签处理函数
JspContext jspContext = getJspContext(); //返回JspFragment关联的JspContext对象
JspWriter out = jspContext.getOut(); //通过JspContext实例中的getOut方法获取JspWriter对象
out.print("
" + header +" |
StringTokenizer tokenizer= new StringTokenizer(items,",");while(tokenizer.hasMoreElements()) {
String token=tokenizer.nextToken();
out.print("
" + token + "\n");}
out.print("
");}
}
2. 注册标签
Simple tag examples
1.0
1.1
My First Taglib Example
/firstTag
dataFormatter
customtag.DataFormatterTag
empty
header
true
items
true
3. 在JSP页面中使用自定义标签
1
2
3
4
5
TestingFormatterTag6
7
8
9
10
11
12
13
14 US,UK,Canada,Korea15
16
17
18
19
运行效果:
四.处理属性
实现SimpleTag接口或者扩展SimpleTagSupport的标签处理器都可以有属性。下面的例子展示了名为DateFormatTag的标签处理器可以将逗号分隔内容转换成HTML表格。
①标签处理器
1 packagecustomtag;2
3 importjava.io.IOException;4 importjava.util.StringTokenizer;5
6 importjavax.servlet.jsp.JspContext;7 importjavax.servlet.jsp.JspException;8 importjavax.servlet.jsp.JspWriter;9 importjavax.servlet.jsp.tagext.SimpleTagSupport;10
11 public class DataFormatterTag extendsSimpleTagSupport {12 privateString header;13 privateString items;14
15 public voidsetHeader(String header) {16 this.header =header;17 }18
19 public voidsetItems(String items) {20 this.items =items;21 }22
23 public void doTag() throwsIOException, JspException {24 JspContext jspContext =getJspContext();25 JspWriter out =jspContext.getOut();26
27 out.print("
" + header +" |
" + token + " |
34 out.print("
");35 }36 }②jsp页面实现
TestingFormatterTagUS,UK,Canada,Korea
③效果展示
五.访问标签内容
在SimpleTag中,可以通过JSP容器传入的JspFragment来访问标签内容。JspFragment类提供了多次访问Jsp中这部分代码的能力。JSP片段的定义不能包含脚本或者脚本表达式,他只能是文件模板或者JSP标准结点。
JspFragment类中有两个方法:getJspContext、invoke。定义如下:
public abstractJspContext getJspContext()public abstract voidinvoke(java.io.Writer writer)throws JspException, java.io.IOException
getJspContext方法返回这个JspFragment关联的JspContext对象。可以通过invoke方法来执行这个片段(标签的内容),然后通过指定的Writer对象把它直接输出。如果把null传入invoke方法中,那么这个Writer将会被JspFragment所关联的JspContext对象中的getOut方法返回的JspWriter所接管。下面看一个示例:
SelectElementTag
packagecustomtag;importjava.io.IOException;importjavax.servlet.jsp.JspContext;importjavax.servlet.jsp.JspException;importjavax.servlet.jsp.JspWriter;importjavax.servlet.jsp.tagext.SimpleTagSupport;public class SelectElementTag extendsSimpleTagSupport{private String[] countries = {"Australia", "Brazil", "China"};public void doTag() throwsIOException, JspException {
JspContext jspContext=getJspContext();
JspWriter out=jspContext.getOut();
out.print("\n");for(int i=0;i<3;i++){
getJspContext().setAttribute("value", countries[i]);
getJspContext().setAttribute("text", countries[i]);
getJspBody().invoke(null);
}
out.print("\n");
}
}
注册SelectElementTag
select
customtag.SelectElementTag
scriptless
selectElementTagTest页面
Testing SelectElementFormatterTag${text}
效果
六、编写EL函数
一般来说,编写EL函数需要以下两个步骤:
(1)创建一个包含静态方法的public类。每个类的静态方法表示一个EL函数。这个类可以不需要实现任何接口或者继承特定的类。可以像发布任何类一样发布这个类。这个类必须放在应用中的/WEB-INF/classes目录或者它的子目录下。
(2)用function节点在标签库描述其中注册这个函数。
function节点是taglib节点的下级节点,它有如下子节点:
description:可选,标签说明。
display-name:在XML工具中显示的缩写名字。
icon:可选,在XML工具中使用的icon节点。
name:函数的唯一名字。
function-class:该函数对应实现的Java类的全名。
function-signature:该函数对应实现的Java静态方法。
example:可选,使用该函数的示例说明。
function-extension:可以是一个或者多个节点,在XML工具中使用,用于提供该函数的更多的细节。
要使用这个函数,必须将taglib指令中的URI属性指向标签库描述,并指明使用的前缀。然后在JSP页面中使用如下语法来访问该函数:
${ prefix:functionName(parameterList) }
具体看以下示例:
StringFunction类中的reverseString方法
packagefunction;public classStringFunctions {public staticString reverseString(String s){return newStringBuffer(s).reverse().toString();
}
}
functiontags.tld文件
Function tag examples
1.0
Reverses a String
reverseString
function.StringFunctions
java.lang.String reverseString(java.lang.String)
使用EL函数
Testing reverseString function效果
七、发布自定义标签
可以吧自定义的标签处理器以及标签描述器打包到JAR包里,这样就可以把它发布出来给别人使用了,就像JSTL一样。这种情况下,需要包含其所有的标签处理器及描述它们的TLD文件。此外,还需要在描述其中的URI节点中指定绝对的URI。
为了在应用中使用这个库,需要把这个JAR文件拷贝到应用的WEB-INF/lib目录下。在使用的时候,任何使用自定义标签的JSP页面都要使用和这个标签库描述器中定义的URL。
------ 天若有情天亦老,人间正道是沧桑 ------