1. 要开发一个自定义行为,需要使用一系列的类和接口,这些类和接口在jsp1.1规范中被称为标记扩展机制(tag extension mechanism)。实现标记处理程序所需要的所有接口和类都是在javax.servlet.jsp.tagext包中定义的。两个主要的接口分别是tag和bodytag。为了使开发标记处理程序更加容易,api定义了两个起支持作用的类:tagsupport和bodytagsupport。这两个类分别为上面的两个接口提供了默认的实现。
2. 标记库是一个自定义行为的集合。在标记库中除了标记处理程序的类文件以外,标记库里还必须包括一个tld文件。这是一个xml文件,它把所有的自定义行为的名称映射到相应的标记处理程序类,而且对每一个自定义行为所支持的所有属性进行了描述。类文件和tld可以被打包到一个jar文件中以方便安装。
3. 开发,配置和使用一个简单的自定义行为通常需要做这几部分工作。
(1) 实现一个标记处理程序类。对这个类进行编译,然后把生成的类文件放到应用程序的web-inf/classes目录下。
(2) 创建tld文件。看下面这个简单的实例。
<?xml version=”1.0” encoding=”iso-8859-1” ?>
<!doctype taglib
public “-//sun microsystems, inc.//dtd jsp tag library 1.1//en”
http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd>
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>test</shortname>
<tag>
<name>hello</name>
<tagclass>com.mycompany.hellotag</tagclass>
<bodycontent>empty</bodycontent>
<attribute>
<name>name</name>
</attribute>
</tag>
</taglib>
把这个文件取名为*.tld,并把它放在应用程序的web-inf/tlds目录下。
(3) 现在你可以这样在jsp页面中使用自定义行为。
<%@ taglib uri=”/web-inf/tlds/mylib.tld” prefix=”test” %>
<html>
<body bgcolor=”white”>
<test:hello name=”maojb”/>
</body>
</html>
当这个页面被请求时,jsp容器就使用这个tld来发现与自定义行为相对应的类。然后它将调用所有相应的方法,将相应的文本加入到应答中去。以上就是在最简单的情况下我们要做的所有事情。
4. 先来看一下最重要的tag接口的方法:
public void setpagecontext(pagecontext pagecontext);
public int dostarttag() throws jspexception;
public int doendtag() throws jspexception;
然后我们了解一下tagsupport类提供的对这些方法的实现。
public class tagsupport implements tag , serializable {
protected pagecontext pagecontext;
…….
public void setpagecontext(pagecontext pagecontext) {
this.pagecontext = pagecontext;
} //这个方法是在使用标记处理程序之前被jsp容器调用的。
public int dostarttag() throws jspexception {
return skip_body;
} //当遇到开始标志时,jsp容器将调用dostarttag()方法。
public int doendtag() throws jspexception {
return eval_page;
} //当遇到结束标志时,jsp容器将调用doendtag()方法。
}
5. 开发一个不需要对行为元素体做任何事情的标记处理程序是非常简单的。然而,对于一个需要处理行为体的标记处理程序来说,还需要一些方法。这些方法是由bodytag接口定义的,该接口扩展了tag接口。
6. 一个有行为体的标记处理程序的执行过程。
(1) setattr1(“value1”)
(2) setattr2(“value2”)
(3) dostarttag()
(4) setbodycontent()
(5) doinitbody()
(6) doafterbody()
(7) doendtag()
7. bodytagsupport类有许多实用的方法来处理行为体。
如:getbodycontent() , getpreviousout()
8. 如何让多个行为互相协作。
内层行为是如何告诉外层行为自己定义参数信息之类的东西呢?这个问题的答案就在由tagsupport类实现的一些tag接口方法和一个工具方法里。
这些tag接口的方法是setparent()和getparent() 。一个嵌套的标记处理程序通常有一个对容纳它的父元素的引用。所以,一个在任意嵌套层次上的标记处理程序可以使用getparent()方法来得到它的父元素,然后可以得到父元素的父元素。可以一直这样下去,直到到达一个没有父元素的tag(即getparent()返回了null)。这意味着已经到达了最外层。
通常说来,一个标记处理程序只对那个它要与之协同工作的父元素感兴趣。所以,一个好的想法是开发一个方法,该方法将沿着层次结构不断向上追溯,直到找到标记处理程序感兴趣的那个父元素。而这正是tagsupport类所实现的findancestorwithclass()方法所做的工作。
public static final tag findancestorwithclass(tag from , class klass) {
boolean isinterface = false;
if(from == null || klass == null || (!tag.class.isassignablefrom(klass) &&
!(isinterface = klass.isinterface()))) {
return null;
}//假如from或者klass为null , 或者klass是一个类并且没有实现tag接口,显然当前tag找不到klass类的父元素。
for(;;) {
tag tag = from.getparent();
if(tag == null) {
return null;
} //表示没有父元素
if((isinterface && klass.isinstance(tag)) || klass.isassignablefrom(tag.getclass()))
return tag; //假如klass是接口并且当前tag实现了该接口,那么找到了。
//或者当前tag是klass类型的,那么找到了。
else
from = tag;
}
}
9. 通过行为创建新的变量
当自定义行为创建一个变量时,它必须与jsp容器合作。
对于一个标记处理程序来说,创建一个新的对象并使得其他行为和jsp脚本代码可以访问这个对象,需要两件事情:
(1) jsp容器必须知道对象的名称和java类型,这样它才能为变量声明生成代码。
(2) 变量必须被放置在某个jsp作用域内,这样才能通过findattribute()方法找到它,并能赋值给这个变量。
第一件事由一个名为tagextrainfo的类来完成。当你为一个引入对象的行为开发标记处理程序时,你必须创建tagextrainfo类的一个子类。jsp容器在生成代码的时候就需要这样一个类的实例。
10. 开发迭代行为
开发迭代行为时,通常也需要一个tagextrainfo子类,这样才能在loop的过程中访问loopid变量。
11. 如何创建tld
当jsp容器将自定义行为元素转化成创建并调用正确的标记处理程序的代码时,jsp容器还需要关于哪个标记处理程序实现哪个自定义行为元素的信息。而这些信息都是从tld那里获得的。另外,jsp容器还使用tld信息来验证行为元素的属性列表是否正确。
tld是一个xml文件,它包含了一个库中所有自定义行为的信息。使用自定义行为的jsp页面必须能识别相应的tld,还能够利用taglib指令元素在页面中识别出用于行为的名称空间前缀。如:
<%@ taglib uri=”/web-inf/tlds/orataglib_1_0.tld” prefix=”ora” %>
….
<ora:redirect page=”main.jsp”/>
jsp页面里遇到前缀匹配的行为时,jsp页面就会用tld来查找它需要的信息。
tld文件中的内容:
(1) 最顶部:标准的xml声明和一个doctype声明。(这两个声明指定了文件的文档类型定义document type definition , dtd)。
(2) <taglib>元素: tld的主元素,它包含了描述库的所有特定元素。
(3) <tlibversion>元素:指定标记库的版本。必须
(4) <jspversion>元素:指定了库所依赖的jsp规范的版本。默认值为1.1。可选
(5) <shortname>元素:必须元素。这个元素的值中不能包含空格或其他特殊字符,也不能以数字或下划线开头。
(6) <uri>元素:可选,字符规则同上。
(7) <info>元素:可选,
(8) tld中至少还必须包括一个<tag>元素。<tag>元素中包含了描述自定义行为的各个方面的其他元素:<name> <tagclass> <teiclass> <bodycontent> <info> <attribute>
l <name>元素是必须的。它包含了自定义行为元素对应的名称,这个名称是唯一的。
l <tagclass>元素也是必须的。
l 如果行为引入了变量,或者需要进行语法验证,那么就要使用<teiclass>元素。这个元素是可选的,用来制定tagextrainfo子类的全名。
l <bodycontent>元素是一个可选元素,它的三个可能值为:empty , jsp或tagdependent。
l <info>元素是可选的,用来描述行为的目的。
l tag元素还必须为行为的每个属性设置<attribute>元素。当然每个元素中也包含了描述属性的另外一些元素:<name>,<required>和<rtexprvalue>
12. 语法验证
(1) 最简单的语法验证是:
当jsp容器将一个jsp页面转化成servlet时,它会将自定义行为元素和tld中行为元素的规范进行比较。这样就可以验证语法上的错误。
(2) 某些语法验证就要复杂许多了。如:一些属性依赖于其他属性是否出现。有些属性是排他的,如果使用了这个就不能使用那个。某个可选的属性必须和其它的可选属性一起使用。为了验证这些依赖性,jsp容器必须向标记处理程序的tagextrainfo子类寻求支持。
在jsp容器检查完一切它自己能检查的以后,它会为行为查找tagextrainfo子类(由<teiclass>元素定义)。如果定义了tagextrainfo子类,它就将所有属性信息放到tagdata类的一个实例中,并调用tagextrainfo的isvalid()方法,参数是装有信息的tagdata类。
13. 如何重用标记处理程序
建议在release()方法中完成重置所有属性的工作。
14. 如何打包和安装标记库
在完成开发后,你可能希望将所有的标记处理程序类,tagextrainfo类,标记处理程序类中使用的bean和tld打包到一个jar文件里。这样可以使得在应用程序中安装库更加容易。tld在jar文件中必须被存为/meta-inf/taglib.tld。
(1) 为了创建jar文件,按照下面的结构来安排目录下的文件。
meta-inf下:taglib.tld
将所有类放在com目录上
文件结构设置好就使用jar命令创建一个jar文件:
jar cvf maojb.jar meta-inf com
(2) 将jar文件拷贝到应用程序的web-inf/lib目录下。