WEB容器在编译JSP网页时,如果遇到自定义的标签,将会在由JSP页面生成的Servlet中调用这个标签处理类,处理标签的类必须是javax.servlet.jsp.tagext.TagSupport类的直接或间接子类javax.servlet.jsp.tagext.BodyTagSupport,继承关系如图所示。

图 BodyTagSupport的继承关系
一、标签处理类
在TagSupport中定义了一些与Servlet容器处理TAG开关相关的方法,主要有如下一些:
1. doStartTag()
Servlet容器遇到自定义标签的起始标志时调用该方法。
2. doEndTag()
Servlet容器遇到自定义标签的结束结志时调用该方法。
3. setValue(String k,Object o)
在标签处理类中设置key / value。
4. getValue(String k)
在标签处理类中根据参数key返回相应的value。
5. removeValue(String k)
删除标签处理类中的相应的key / value 。
6. setPageContext(PageContext pc)
设置PageContext对象,该方法由Servlet容器在调用doStartTag或doEndTag方法前调用
7. setParent(Tag t)
设置嵌套了当前标签的上层标签的处理类,该方法由Servlet容器在调用doStartTag或doEndTag方法前调用。
8. getParent()
返回嵌套了当前标签的上层标签的处理类。
标签处理类中有两个比较重要的属性:
1. parent:代表了嵌套了当前标签的上层标签的处理类。
2. pageContext:代表了Web应用中的javax.servlet.jsp.PageContext对象。
pageContext类提供了保存及访问WEB应用共享数据的方法,包括下面两个常用的方法:
方法一:public void setAttribute(String name,Object value, int scope)
表示在PageContext中设置属性的值。
方法二:public Object getAttribute(String name, int scope)
表示从PageContext中取得属性的值。
scope用来指定数据的作用范围。可选值如下:
l PageContext.PAGE_SCOPE:表示作用范围为一个JSP页面。
l PageContext.REQUEST_SCOPE:表示请求作用域,就是客户端的一次请求。
l PageContext. SESSION_SCOPE:会话作用域,当用户首次访问时,产生一个新的会话,以后服务器就可以记住这个会话状态。生命周期结束或会话超时,服务器端会强制使会话失效。
l PageContext.APPLICATION_SCOPE:全局作用范围,整个应用程序共享,就是在部署文件中同一个WEB目录下应用的共享,生命周期为应用程序启动到停止。
以上作用范围按顺序越来越大, request和page的生命周期都是短暂的,他们之间的区别就是:一个request可以包含多个page页。
Servlet容器在调用doStartTag()或doEndTag()方法前,会先调用setPageContext()和setParent()方法,设置pageContext和parent的值。
在doStartTag()或doEndTag()方法中可以通过getParent()方法获取上层标签的处理类,在TagSupport类中定义了protected类型的pageContext成员变量,因此在标签处理类中可以直接访问pageContext变量。
二、JSP标签的实现
要实现自定义的标签,应该要实现前面介绍的描述文件、标签处理类、修改web.xml文件以及在JSP页面中引用自定义的标签。下面为一个简单的自定义标签,当JSP页面中引用了自定义标签时,把标签的内容用“Hello Kitty!!”代替,代码如下所示。
“Hello Kitty”标签
Gw]A8d1|%~0//1. JSP页面
B!jj:?OP]@0<%@ page contentType="text/html;charset=UTF-8"%>
nx!\:l5^'f0<%@ taglib prefix="message" uri="http://www.free.com/taglibs/HelloKitty" %>ITPUB个人空间 a1sBS"_6Ov
<html>
5k5r
y;{M` d0 <title><message:sayHello/></title>
Zuhs,FVp~9m0 <body>ITPUB个人空间
H3B"gH
t0D#z)a
message : <message:sayHello/>ITPUB个人空间Bc]|*G@)CT
</body>ITPUB个人空间}DN6m:^1R
</html>
//2. web.xml文件标签定义
@}@?X"@Ol0 <taglib>
#z.LY9z9`t'PK0 <taglib-uri>http://www.free.com/taglibs/HelloKitty</taglib-uri>ITPUB个人空间
J`5l"P2n_(N$e
<taglib-location>/WEB-INF/HelloKitty.tld</taglib-location>
Zmc7c)Gm"kWET x0 </taglib>
//3. 标签描述文件ITPUB个人空间@aL YlG@ c/o@K1w
<?xml version="1.0" encoding="UTF-8"?>ITPUB个人空间T"AA7^ M1[6e
<!DOCTYPE taglibITPUB个人空间(E
{(Hk3H|k)H
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"ITPUB个人空间&l-ej0R8f%y
"http://java.sun.com/j2ee/dtd/web-jsptaglibrary_1_2.dtd">
H0^.a)@8O!G2]f&k0
~ Zd$h UH,O0<taglib>ITPUB个人空间 ufH'Hv
<tlibversion>1.0</tlibversion>
-Z\Ts+b(XYC+p0 <jspversion>1.2</jspversion>
,SJb'OQJ1WS0 <shortname>message</shortname>ITPUB个人空间(kO/p6s@d9a
W
<uri>http://www.free.com/taglibs/HelloKitty</uri>ITPUB个人空间
}0d+f
WzZ^Gn(L0t!O
ITPUB个人空间6N)B+MJoC#t+P9B
<tag>
Y6j1`$D%@0 <name>sayHello</name>
ioAM0z/S` t0 <tagclass>com.free.taglib.HelloKittyTag</tagclass>ITPUB个人空间O&fB@U1u
<bodycontent>empty</bodycontent>
(\uM9C6f&Km0 </tag>ITPUB个人空间3rm+Jb'[%JF?+X(^
</taglib>
//4. 标签实现类ITPUB个人空间xj mt1^%w(b-S
public class HelloKittyTag extends TagSupport {
6Nc;E!VgxbC%U0 public int doEndTag() {ITPUB个人空间&wwVG(To$Y\&BY1a
try {
pageContext.getOut().print("Hello Kitty!!");ITPUB个人空间!eb~h0y
u4z:u?AP
} catch (IOException ignored) {ITPUB个人空间/Z#NuSAW^
}
9?N1@] w
BB;lRW`0 return EVAL_PAGE;
,w"eLn6R1W9V'sSRZ0 }
2X7c0gS]u/Ue0}
上例通过JSPàweb.xmlà标签描述文件à标签实现类完整的展示了一个自定义标签的实现,JSP文件的显示效果如图所示。

图 JSP引用自定义标签的显示效果
提示:在标签处理类中还能处理非常复杂的逻辑,从而把复杂和重复的代码从JSP页面中分离出来,这也是标签存在的理由之一。