v 自定义标记库
Ø 自定义标记库让你可以把逻辑封装起来,并且以网页设计师熟悉的格式拉使用这些逻辑。
Ø 使用自定义标记库,可以将JSP页面中的Java代码量缩减到最少,使整个应用程序更易
于调试和维护。
Ø 标记扩展基础
ª 自定义行为是一个自定义行为的的标记处理器类,它从本质上来说是一个bean。
ª 标记处理器类必须实现由JSP规范定义的3个Java接口中的一个。
i) Tag :定义了在任何行为中都需要实现的方法
ii) IterationTag:增加了行为体上迭代所需的方法
iii) BodyTag:增加了方法行为体的方法
ª 实现标记处理器所需的所有接口和类都是在javax.servlet.jsp.tagext程序包中定义的。
ª 为了使开发标记处理器更加容易,API定义了两个继承以上接口,起支持作用的类
i) TagSupport: 为Tag和IterationTag接口提供了方法的默认实现
ii) BodyTagSupport:为BodyTag接口提供了方法的默认实现
ª 实践中应把标记处理器实现成对支持类的扩展。
ª 标记库包括
i) 标记处理器类
ii) 标记库描述符文件,TLD:XML文件,映射所有自定义行为的名称到相应的标记处理器类中。而且对自定义行为支持的属性进行描述。
ª JSP页面中的自定义行为元素是由一个开始标记(可能含有属性)、一个行为体和一
个结束标记组成的。
<prefix:actionName attr1=”value1” attr2=”value2”>
The Body
</prefix:actionName>
ª 如果行为元素没有行为体,可用简写形式代替开始标记和结束标记
<prefix:actionName attr1=”value1” attr2=”value2”/>
ª 标记处理器类实现了该行为的行为。
<prefix:actionName
attr1=”value1” ——〉 setAttr1(“value1”)
attr2=”value2” ——〉 setAttr1(“value2”)
> ——〉 doStartTag()
The body
</prefix:actionName> ——〉doEndTag()
ª 标记处理器需要访问关于请求和作用域的所有信息,以及这个性为元素的属性值(如
果有的话)。容器会调用Tag接口中定义的方法,从而为其提供这些信息。
ª 实现了Tag接口的标记处理器可以向应答主体中添加动态内容,设置应答首部,添
加或删除一个JSP作用域中的变量,并告诉容器在应答中包括行为元素的行为体,
或者忽略该行为体。
ª 下面是最重要的Tag接口的方法
© public void setPageContext(PageContext pageCOntext);
这个方法在使用标记处理器之前被JSP容器调用。PageContext提供了对请求
和应答对象,以及JSP作用域内所有变量的访问途经。
© public int doStartTag() throws JspExceptioin;
当遇到开始标记时,JSP容器将调用doStartTag()方法。
返回值:
i) SKIP_BODY:告诉JSP容器忽略掉整个行为体。
ii) EVAL_BODY:告诉JSP容器对行为体进行处理(例如执行行为体中的脚本元素和其他行为元素),并把结果放到一个应答中。
©public int doEndTag() throws JspException;
无论doStartTag()方法返回什么值,当遇到相应行为元素的结束标记时,JSP
容器都会调用doEndTag()方法。
返回值:
i) SKIP_PAGE:告诉JSP容器放弃对页面其余部分的处理。
如果标记处理器要把处理过程转发到另一个页面,或要发送给浏览器一个重定向应答,就可以使用这个值。
ii) EVAL_PAGE:告诉JSP容器继续处理页面中的其余部分
© 标记中的必须的属性属性应该在自定义行为中被设定好,否则JSP容器拒绝处
理这个页面。
ª 要求容器反复对行为元素的行为体求值,需要实现IterationTag接口,它只包含一个
方法:
© public int doAfterBody throws JspException
该方法在容器处理了行为元素的行为体后,由该容器调用
©对于IterationTag接口,调用doStartTat()方法后,在最后调用doEndTag()方法
之前还要调用doAfterBody()方法。
<prefix:actionName
attr1=”value1” ——〉 setAttr1(“value1”)
attr2=”value2” ——〉 setAttr1(“value2”)
> ——〉 doStartTag()
The body ——〉 doAferBody()
</prefix:actionName> ——〉doEndTag()
© 其中的doStartTag()方法可以返回EVAL_BODY_INCLUDE,这告诉容器要向应
答中添加循环元素的行为体内容,然后调用doAfterBody()。
© doAfterBody()方法可以返回EVAL_BODY_AGAIN(在行为体上迭代),或返回
SKIP_BODY(以停止迭代)。
© 当doAfterBody()方法返回SKIP_BODY时,容器调用doEndTag()方法。
ª 读取和处理行为体的标记处理器,需要BodyTag接口
© BodyTag继承了IterationTag接口,还增加了两个新方法
i) public void setBodyContent(BodyContent bodyContent)
ii) public void doInitBody() throws JspException
<prefix:actionName
attr1=”value1” ——〉 setAttr1(“value1”)
attr2=”value2” ——〉 setAttr1(“value2”)
> ——〉 doStartTag()
The body ——〉setBodyContent()
——〉doInitBody()
——〉 doAferBody()
</prefix:actionName> ——〉doEndTag()
© 在这里的doStartTat()方法可以返回EVAL_BODY_TAG,,该值意味着不仅行为体应
该得到处理,并且容器还必须使处理的结果可以被标记处理器使用,只有实现了
BodyTag接口的类,EVAL_BODY_TAG,,才有效。
© BodyContent对象来缓冲行为体内容
© BodyContent提供了几个工具方法
i) getBodyContent()
返回BodyContent对象的一个引用,其内容由getString()方法读取
ii) getReader()方法
获取Reader的内容
iii) getPreviousOut()方法
返回主要的JspWriter
ª TryCatchFinally接口
© 当doStartTag() , doEndTag(), doinitBody()或doAfterBody()方法中的任何一个抛出一个异常,容器都会调用doCathc()方法。doFinally()方法总是有容器调用,如果执行正常,就在doEndTag()后,如果出现异常,就在doFinally()方法后。
ª 如果行为引入了变量,那么处理标记处理器之外,还需要使用TagExtraInfo子类,可选的<tei-class>元素用来指定TagExtraInfo子类的完全限定类名。在JSP1.2中,很少用到这个类。
ª 一般应该替换掉TagExtraInfo子类,而使用新的<variable>元素
ª 通用库的元素
© <short-name>:必需的元素,包含了行为元素的默认轻缀<prefix:>
© <body-content>:有3个可能的值
i) empty:行为体必须为空
ii) JSP :行为体包括JSP元素,行为体中的JSP元素都会被处理,该值为默认值
iii) Tagdependent:意味着行为体中的JSP元素不需要处理
©<variable>:提供了自定义行为要将之作为脚本变量的变量的有关信息。
© <tag>元素为行为体的每个属性都包含了<attribute>元素。
© <rtexprvalue>,它和<required>元素的取值相同,true:由请求时表达式来指定属
性的值,默认为false
© <type>元素可以指定属性的Java类型。
ª 组成标记库(TLD和所有的类文件)的打包和安装。
© 在开发过程中,可以将标记库类文件放在WEB-INF/classes中,TLD必须作为扩展
名为.tld文件,可以存放在WEB-INF/tlds。
© 在开发完后,可以将所有标记处理类和TLD都打包到一个JAR文件中。这使得在
应用程序中安装库变得容易,此时,TLD必须作为一个扩展名为.tld的文件存放在
JAR文件的META-INF目录中,如META-INF/taglib.tld。然后将JAR文件放在
WEB-INF/lib目录中。
© JSP1.2,当web应用程序启动时,容器会扫描整个WEB-INF目录结构来寻找带有
.tld的文件,并在META-INF目录中寻找含有.tld的文件的JAR文件,容器会查找
TLD的<rui>元素,并创建一个从URI到包含它的TLD的映射。
© 在JSP1.2之前,需要在web.xml中手工定义。