标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
rQncW~ "!yKX(aTX 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
&zCqF=/9U "hRY+{m 在这篇文章中,我们主要讨论:
T4W"!4[ j15TavjGh · 什么是自定义tag标签?
S;o U'KOY ,tEvz · 怎么使用tag标签?
OFJ
T Y:nF.An3 o 声明要使用的tag库
!lSxBr[dQ /S]W<8d o 找到与之对应的tag处理类
&h7q=-XU ;w(]z o tag标签的类型
ZKGS?z ?kICYtY:_b · 自定义tag标签
)P^5L<q>| u}QB-oU o tag处理类
e JMD8# (%fl o tag库描述
)shzJ9G _v=@MOI/J o tag标签示例
tQ7DdVdix :!a9|Fh~ o 带属性的tag
Nxu10 mm3goIi;Y o 带body的tag
:E|HP#iwu q Yg4H|6 o 定义了脚本变量的tag
U!F~>< .+G),P) o 具有协作关系的tag
r)|X? 5Wj+ey^^w · 自定义tag标签
'3>kD H+ 28[dTsd% o 一个迭代tag的例子
\lK iUy/ khl(9R4a o 一个模板tag库
<z N (o_fY. o tag处理类到底是怎样被调用的?
4C(v BKl =2#a@D6Bl 7N^9D
H{` 什么是自定义的tag?
TB] %?L: M/5e4b 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
@18"o"c7j c=l
3Sz? 自定义tag标签有很多特色,诸如:
N2_j[Pe SGW2' · 可以在JSP页面中自定义tag标签的属性
v{ .-x\; bz_Zk · 访问JSP页面中的所有对象
w>T1D Lj"~6l`) · 可以动态地修改页面输出
sXI_!)H Q>nq~#3? · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
(Q !4\Gy >Fm}s, · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
mt7}1s,i[ PY:
l %R5APMg1 使用tag标签
@.fuR# P}o:WI4.cB 1)u
3 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
[7?K9r\# CzxU
@ 要使用tag标签,JSP程序员必须做2件事:
vV1F| ]#N2:ych · 声明此tag标签的tag库
fGJPZe :W,6zv(..u · 实现此tag标签
4VPL
-":6 cu|gM[ 声明tag标签所在的tag库
gd[jYej'RP s
z/7cLo 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
^.,pq?_ <CJua1l\ <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
cD^n}'ej .MuS"R{y uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
m8H|cQ@Uu y]9
3z!#Z TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
o:_}=1nh Mn $TWhg' 以下taglib指示符直接引用一个TLD:
S2K_>kvG)~ +Y,>ftN <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
L5"" ?:Y{c#w> 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
CJk$o K{Q st(l85 <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
bT}P":*y LF
<fp&C)h 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
a ^<W
?Z Dna0M0 <taglib>
< i*v |\2zw _o <taglib-uri>/tutorial-template</taglib-uri>
X>EwJ"q# /K2VSj3\ <taglib-location>
%d*k3f
} ),0_ C\ /WEB-INF/tutorial-template.tld
QIF|pZ+^ ]K0<DO9 </taglib-location>
V(1Ldl'a :y%%Vx~ </taglib>
EsXCi2]1 :U)q(.53 v9INZ1# v 实现此tag标签
K>6#MI FGu:8`c9 eX7Ev'(H 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
Z+)R%Z'aL 'YQ"Lf 5#s?rA%u tag标签类型
9kL'"0c /8@JWK^I{ k'}}eu/ q 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
T[B@7$Dp* ?JDZDPVJ) <tt:tag>
#o_`$'> |_8::kir: body
vC[)/w 7$WO@yOsh </tt:tag>
TAlpy$ *DObtS_
6 #K'3`dpL 一个不带body的tag标签如下:
y 562g`"U T!eeMsI <tt:tag />
=\`g<0 q3JoU/Sf N_Cu%HP 简单的tag标签
g
#u1.|s&p "12.Bi.O"[ 一个没有body和属性的tag标签如下:
UOSa`TZbZ e5maZ(.;F <tt:simple />
]H0BUg 2+
F34 E9HA8 带属性的tag标签
n?_!gqK }legh:/*?O v' .:?9 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
PF*<_p" j ]S<eO6z 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
^-cj=on=Q 5_ -YF~ <loglic:present parameter = “Clear”>
<iunDL0 +'Pl?QyH 而另一个标签logic:iterate是用表达式来给属性赋值:
SLpB$puS wX@&Qv <logci:iterate collection=”<%= bookDB.getBooks() %>”
cOcF VPQ f;`pj`-k% id=”book” type=”database.BookDetails”>
SY>i@s+ML &H$
3`"p5u 5s_7P"&H 带body的tag标签
4\4onCzuT lrB@n?hk 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
\~d|MP}"F: I]bqle0M 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
<at/z9b dawe!w! <logic:present parameter=”Clear”>
w V-1B\m K@Q_q/(%; <% cart.clear(); %>
^5j| ?r0#{x~ <font color=”#ff0000” size=”+2”><strong>
/:d03N\9k [H)NkR;I 你选择了清除购物车!
l-xKfp` 7YsBwo </strong></font>
0'*whhH 0{#,'sc; </logic:present>
ojU:RRr4l$ =k6zUw;5 U Vd~{SS2> 到底是用属性还是用body来传递信息?
\.y|=Ql_u /KjRB_5~q} 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
$r)+7i n#t{3qzpD EKoAIC*?p 定义脚本变量的tag标签
By(:%=. 2.CjjI 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
98eiYh l:mC'aR <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
j@1cllJkh <-62m8N| <% tx.begin(); %>
eKi/Mt
rTYDa3 ...
?nJ7lLQA |@?B%sY 8"/5Lh( 具有协作关系的tag标签
c9imfA+e
/B)ZB})z 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
bg;NBoZd ss63/ <tt:tag1 attr1=”obj1” value1=”value” />
X{zg-k(@ }[XzM/t <tt:tag2 attr1=”obj1” />
P.Pw.[:3 l0AgW_T 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
s2A3.SN >ch{u{i6 <tt:outerTag>
Kk+IUs J.Mj76\_ <tt:innerTag />
=S/$h}Vi iL(rZT&^ </tt:outerTag>
''Fy]CwH( meunAEe RaT(^b( Tag处理类
;@p2s'( ._@Scd 6OR5zXpk Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
U">J$M@ -BUxQ8/, 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
$O" S*)9 nB"r<?n< 下表说明不同类型的tag所需要不同的处理过程:
AY4ZU CqI eUlF4l<] Tag处理类的方法
D>M
a3g `&$"oW{HW Tag标签类型
, f9V`Pz) 所调用的方法
N^7Qn*qt[ pOP`n3m0 基本标签
&.z: i5&o! doStartTag, doEndTag, release
|_L\^T|6 =H6"\`W 带属性的标签
}[ LME Z doStartTag, doEndTag, set/getAttribute1...N, release
YW55iyM tdSy&]P 带内容的标签
kbzzage6L doStartTag, doEndTag, release
J'^H@L/E 4cJ7W_ >i6 带内容的标签,且内容重复循环
xCwd*lsM doStartTag, doAfterBody, doEndTag, release
YT\x'`>Q D /ysS$!{ 带内容的标签,且内容与JSP交互
#<df!) doStartTag, doEndTag, release, doInitBody, doAfterBody, release
~]f+ 8 tMfh 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
r&sm&4)p-5 19-|.9m( 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
>qh8em ,!+>/RlJ 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
QX}O{LQR =9$hZ c eh_{- Tag库描述(简称TLD)
SKf9
yS# '>dsROB-> lZoy(kdc Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
x+Vp& !K a!f1 TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
l`c&nf6 dw{L,u`68 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
j8WMGSrrF :SFcnYv0 <?xml version="1.0" encoding="ISO-8859-1" ?>
USF&; M3 oE:9}]N_ <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
ZL[~[ TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
{2wfv2hQ BR\3ij {pJ{UJKv? <taglib>的子元素
dIk/vg uNnx
i Element
9pAklD 4 Description
A[20ic s))L^|6 tlib-version
On%21L;JG Tag库的版本
hE.NW <vS J<WY jsp-version
l)y$c}U Tag库所需要的jsp的版本
N"-</kzV S[!sJ-rG short-name
&"!s +_ 助记符,tag的一个别名(可选)
|eS5~0<` p.{9OrH(4 uri
^rF{%1 DT 用于确定一个唯一的tag库
c_$9z>$ E`vCYhf{ display-name
i=b<Mz7| 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
-h=K]Y{` ;-SFK+)R" small-icon
4`Com~`6" 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
so[i"ZM) $`7cs}# large-icon
QLNQE 6- 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
yEYlQ= [# 1&{]jG{# description
7WZ).,qxY 对tag库的描述(可选)
Z}#,E; k-5Enbkr listener
tK9_]663 参见下面listener元素
29:1crzx~ osKM3}Sb tag
z[xi 参见下面tag 元素
Gb)!]:8 K9JW&5Q Listener元素
Wi a%rm =4RXNWkud 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
!Jh/M^ B8Ob~? Tag元素
4-P'e%S Jjt'R`t%t 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
hoy+J/ =,Yi" E 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
F8e]sa$K\ /I[?TsXp Tag元素的子元素
T
KpX]H` <b 0;Nf
元素名称
pJM~'tlHV 描述
nAc02lJh| t*<@>] k name
JZ#O"rF 独一无二的元素名
')pXQ !<!5;f8 tag-class
:W'Yt9v) Tag标签对应的tag处理类
b21c} rI3 1r6>.&p tei-class
9f
,$JjX[ javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
tb;!2$ anwMG0 body-content
#{973~uj Tag标签body的类型
"9=F/o9 #X&`gDW display-name
sSVgDQ~q 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
:r0?[#r?N, Q+e|;Mj small-icon
0!v+ + 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
g'G"`)~ 2 (_^pX large-icon
sjBP#_lW 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
@eQIwz _c*0Rr description
ElNKCj<M 此tag标签的描述
g~FA:R &WW|! 6 variable
<^j,jX 提供脚本变量的信息(同tei-class)(可选)
H]@M00C xA|72!zk0P attribute
><odBM- Tag标签的属性名
V+7x_>!&) l4c9.'6 以下章节介绍对于不同类型的tag,如何具体地实现它们。
83,ATQg ~9.0:Fm< --SlxV/x 简单的tag
(<f`},
QxD zcCX;N BbA7X tag处理类
0)/L+P5 ^6=y4t=%F 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
p|Po##E}g^ FX
QUj&9 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
o#V}l^uU= Bob K>db +o]DT7W public SimpleTag extends TagSupport
8^26g3 T%kr&XsQX {
, VT& !Yx9=>R public int doStartTag() throws JspException
HIUB: \v(}@zcB| {
5VWyc9Q &6-udZB- try{
_U%a`%tU. eh=.Q<N pageContext.getOut().print(“Hello.”);
1m$:Rn^ \A@Mlpe&t }catch(Exception e){
x9UF v8Ga@* throw new JspTagException(“SimpleTag: “ + e.getMessage());
37Z@a!# ttlFb]zZh }
z;? 32K !9yOFd_ return SKIP_BODY;
:77dl/d% SGi(Zkc }
1n+C'P" $n |)M+d public int doEndTag()
qx,>j4yw oWg"f* {
EqW/Wxv7b X6lkz*M. return EVAL_PAGE;
8G&'ED_& WCc7 MK }
C"`,?K(U Bp
#:sAG }
x<_uwL2a b^WTX !Z f<
j 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
x+niY;Z E [wHGt?R <body-content>empty</body-content>
8_yhV{ =1qM`M :Fe}.* t 带属性的tag标签