首先我们需要大致了解开发自定义标签所涉及到的接口与类的层次结构(其中SimpleTag接口与SimpleTagSupport类是JSP2.0中新引入的),下图大致结构
一、TagSupport
简单标签的开发我们只要实现Tag接口即可,为了简单起见可以直接继承实现了此接口的TagSupport类。
标签类说明:
图一
图二
图一作为1中的补充: 在doAfterBody()如果返回值是EVAL_BODY_AGAIN那么将重新执行此方法。
setPageContext() 将所在jsp页面的pageContext注入进来,目的是为了在后面的方法中可以访问到jsp页面
对象的pageContext属性
setParent() 设置此标签的父标签
setAttribute() 将标签中的属性注入到此class的属性,不需要自己实现但要提供属性的get与set方法
doStartTag() 在开始标签属性设置后调用,如果返回SKIP_BODY则忽略标签之中的内容,如果返回
EVAL_BODY_INCLUDE则将标签体的内容进行输出
doEndTag() 在结束标签之前调用,返回SKIP_PAGE跳过整个jsp页面后面的输出,返回EVAL_PAGE执
行页面余下部分
release() 生命周期结束时调用
特别说明:在tomcat4.1之后的版本中默认开启了标签缓冲池(websphere和weblogic并不会这么做),所以执
行完标签后并不会执行release()方法(_jspDestroy()时才释放),也就是说同一个jsp页面自定义标签不管
使用多少次只会存在一个实例,但也并不是每一个标签都会为其创建一个缓冲池,要根据参数来判断,例如
:
<myTag:UserInfoTag user=”…” />
<myTag:UserInfoTag />
上面例子中由于参数不同就会创建两个标签缓冲池。
这个问题可以通过设定tomcat的配置文件加以解决:
在%tomcat%\conf\web.xml加入enablePooling参数,并设置为false(不缓存自定义标签)。
<init-param>
<param-name>enablePooling</param-name>
<param-value>false</param-value>
</init-param>
清空%tomcat%\conf\目录
TagSupport类已经为我们实现并扩展了一些方法(比如在上述方法中我们可以直接使用pageContext对象,调用父标签getParent()等),所以一般情况下我们只需重写doStartTag(),doEndTag() 即可
TLD文件说明:
<!--版本号-->
<tlib-version>1.0</tlib-version>
<jsp-version></jsp-version>
<short-name></short-name>
<tag>
<!—指定标签名 -->
<name></name>
<!—指定标签类文件的全路径 -->
<tag-class></tag-class>
<!--如果不需要标签体则设置empty,反之设定jsp -->
<body-content>empty</body-content>
<!—设定属性(如果有的话) -->
<attribute>
<!—指定标签名 -->
<name></name>
<!—是否是必须,如果非必须没设置则为空 -->
<required>true</required>
<rtexprvalue>true</rtexprvalue><!—是否可在属性中使用表达式 -->
</attribute>
</tag>
二、BodyTagSupport
如果我们需要在<test> …. </test>之间的标签体的头部和尾部加上一些标记或者是其他处理,一般的处
理方法是在doStartTag和doEndTag方法中进行, 但是如果是个迭代标签,标签体的每段内容在循环输出时每
次都需要在头部和尾部加上一些标记,我们使用BodyTagSupport就很方便了,
此接口在doStartTag()方法返回值多了一个EVAL_BODY_BUFFERED,它将对主体进行计算,并输出到缓冲区(注
:此处是缓冲区并非直接输出到客户端,需要我们手动(this.bodyContent.getEnclosingWriter().write
(this.bodyContent.getString());)进行输出客户端的调用,否则主体内容不会进行显示)
标签类说明: 关于BodyTagSupport接口的说明
BodyTag接口
接口BodyTag的实现类,它是负责操作主体内容(bodyContent).
定义方法:public void doInitBody();
public int doAtferBody();
提示,那些在doStartTag()方法之后被调用的方法依赖于doStartTag()方法返回值并且看在JSP页面上是否自定义Action元素,而不是怎样在TLD文件中去申明
在TLD文件中, 若<body-content>empty</body-content>的话,doStartTag()方法只能返回SKIP_BODY
body-content有三个可选值:empty , JSP , tagdependent
若没有设置的话,那么doStartTag()可以返回SKIP_BODY, EVAL_BODY_INCLUDE, or EVAL_BODY_BUFFERED.
返回值的说明:
若SKIP_BODY返回的情况下,body不会被evaluated并且doEndTag()被调用;
若EVAL_BODY_INCLUDE 返回,并且自定义action元素不为空的时候,那么doInitBody(),setBodyContent()不会被调用,而body evaluated并且"通过"当前的out对象,还有当action元素为空的时候,只有doStartTag(),doEndTag();
当EVAL_BODY_BUFFERED 返回,并且自定义的action元素不为空的时候,setBodyContent(),doInitBody()被调用,body被evaluated,doAfterBody()被调用,直到大于0次迭代后,doEndTag()才被调用,还有当action元素为空的时候,只有doStartTag(),doEndTag();