标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
q,&T$Tw 4^^rOi0 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
ay|{!MkQ ghj~r 在这篇文章中,我们主要讨论:
\ \}/2#1=c kweTK]mT · 什么是自定义tag标签?
I@M^Wu]wW Z!eq / · 怎么使用tag标签?
F
;&e5G k4rBS o 声明要使用的tag库
B'/ >Ax&
>MrU^t o 找到与之对应的tag处理类
-Lb^O/ fMaNv6( o tag标签的类型
h'KtG<+ ybO,~TQ · 自定义tag标签
{jf~?/< A$6b=2hc> o tag处理类
-=IM8Dny d]`,}vi#E9 o tag库描述
N|S xAg Uroj%xN o tag标签示例
9#6/c ;#j82 o 带属性的tag
IBh~(6 RY<b]| o 带body的tag
w\*/(E<:
p]eD@3Wz o 定义了脚本变量的tag
>6+K"J-@ N@)~j+Pz o 具有协作关系的tag
QovC*1' ]H2aYi$ · 自定义tag标签
Y_sVe q04Dj-2< o 一个迭代tag的例子
0g-ESf``{n Z+(V \ o 一个模板tag库
mA@+4& B,,d~\ o tag处理类到底是怎样被调用的?
edx'p`%d5 gwT,D.'Ut ~#\#!H7 什么是自定义的tag?
NhX.yLb$ 2z3A"HrlA 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
ze N!*VG /
u6$M/Cf> 自定义tag标签有很多特色,诸如:
926oM77 [rU8
#4.
· 可以在JSP页面中自定义tag标签的属性
S
'+"+%^tj MX,0gap · 访问JSP页面中的所有对象
TVwYFX Xm'K6JH' · 可以动态地修改页面输出
ifZNl, A8GlE · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
%$| k3[4V HH@xnd · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
.
*xq = @8yFM% );H[lKy 使用tag标签
uf]$@6) Qe.kNdT+_ Z]\^.x9S 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
RQNi&zX/ Q}]kw}b 要使用tag标签,JSP程序员必须做2件事:
?ovGYzUZ {][7N p!y · 声明此tag标签的tag库
@A'1D@f# |9$'?4F · 实现此tag标签
)m;qv'=! ODA#vAc! 声明tag标签所在的tag库
#q.G_-H4J@ F@roQQu 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
n3j h\ z
]N~_9w <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
R9G)X] u@u.N2H.% uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
})vr*[ G<6grd5PP TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
8lSn*;S, q*TKs#3 以下taglib指示符直接引用一个TLD:
C?|3\@7 `h5eej&s( <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
)Hm[j)YI &})d%*n 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
m>dcb
6B+g C-^%g[# <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
3N0X?* (x| 7e{X$' 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
/uXRZ 3_*Xk.
.d <taglib>
t^_{5 ^ lc}FN <taglib-uri>/tutorial-template</taglib-uri>
QXxLe* Ld3Bi2d| <taglib-location>
'
ra B 0Q-
Mxcj /WEB-INF/tutorial-template.tld
={E!8" &*]{"^ </taglib-location>
}8F$&
AFt h$7Fe +#I# </taglib>
!Xx<~lIC feI[M;7u v;bP8)mI 实现此tag标签
%6IlE.*, ZG/8 Ds *&dW\fx 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
Ce5w0&VlS k#Ez <[y$D=n tag标签类型
W93JY0Ls9| k Kp6 >4|c7z4 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
<{NYD. ,v}?{pc <tt:tag>
1ntkM? k$-~_^4m body
v :+8U[x l4mUx`! </tt:tag>
~6-"i0k
u3*NO
)O :(l $^
M 一个不带body的tag标签如下:
W`Q$t56 5rfH;` <tt:tag />
QlRoe|{ Zc%foK{ {7=WU4$ 简单的tag标签
Q$3\ /mz 1qLl^DW 一个没有body和属性的tag标签如下:
KM/U?`6>: 0;FqX* <tt:simple />
Xb=2/\}|f ]|,q|c , ~&DB!6* 带属性的tag标签
r:c@17 3`fJzS% O crJ7pe9 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
_(oP{wgB ?E+:]j_ 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
15xd~V?ai: *2,e=tY> <loglic:present parameter = “Clear”>
<G~}N =% q?Cr 而另一个标签logic:iterate是用表达式来给属性赋值:
m"gni # 1p7cv~#95 <logci:iterate collection=”<%= bookDB.getBooks() %>”
Ew
%{ i(d CxbSj, id=”book” type=”database.BookDetails”>
n#+%!HTh 7Wwp )D #`jE%ONC 带body的tag标签
N5 SLF4R1 bBUbw *DF) 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
bp]^EVx 7P<r`,~k- 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
`z|=~ M}Nb|V09 <logic:present parameter=”Clear”>
-}{%Q?rYj E?3 0J3S <% cart.clear(); %>
0jxO |N2) r0\cc6 <font color=”#ff0000” size=”+2”><strong>
:+~KPn>w5 =X-^YG3x 你选择了清除购物车!
=?/N5O( 7 I_1 #O </strong></font>
'[Mlmgc5 #yW.o'S+ </logic:present>
YfE>Pn'r $[Tt#CJw zRwb" 到底是用属性还是用body来传递信息?
`]*%:NZP@ WnD^F> 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
ry.;u*F wYZT D*A2h 0:Ar|to$m 定义脚本变量的tag标签
tIq>Oojdx duX0Mc.0P 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
e8$l0gzaD ;mEwQ <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
MaZM%W8Z
pv$mZi4i <% tx.begin(); %>
gRBSt
M&hU a%Uw;6|{ ...
_p\629` B\\6# _|N}4a 具有协作关系的tag标签
{jvOHu :6XguU 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
c\At0.QCA 94\t1fE <tt:tag1 attr1=”obj1” value1=”value” />
Rv=DI&K%n m23+kj)+VY <tt:tag2 attr1=”obj1” />
LH4>@YPGE# ,Du@2w3Cq 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
fX_#S|DlSG COR;e`%, <tt:outerTag>
{jjSJIV1 0axxQ!Ivx <tt:innerTag />
q# MM !lAD
q|$ </tt:outerTag>
_2b9QP p zbNA\.y dm6~ Tag处理类
eqq`TT#Z *l{yW"Su S='
wJ@?; Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
"< v\M85& ['z!{Ez 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
n|Pr/ddL ?>af'o: 下表说明不同类型的tag所需要不同的处理过程:
x[QZ@rGIW 9M_(He
- Tag处理类的方法
Z`Pd2VRp 'Gjq/L/x Tag标签类型
petW
M@ 所调用的方法
n"6;\ 2#3^skj 基本标签
v!H:^!z doStartTag, doEndTag, release
LOr|k8tL%
B$^7h! 带属性的标签
.x!T+`l>8I doStartTag, doEndTag, set/getAttribute1...N, release
i(*I@ku *5e+@rD` 带内容的标签
Bd@'e7{ doStartTag, doEndTag, release
3J{vt"dS ZQ3_y $ 带内容的标签,且内容重复循环
%r;w;`/hA doStartTag, doAfterBody, doEndTag, release
?vgH"W~3> G/vC~6x 带内容的标签,且内容与JSP交互
m#f{]+6U
doStartTag, doEndTag, release, doInitBody, doAfterBody, release
z%1{ 9I`Y-D 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
*:_P8G; Q/ZkW 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
+R6a}d/K n-o3 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
DdSSd@,x* |9Yi7. `Gd$:qV Tag库描述(简称TLD)
!g>.i` ]u#JuX e'2Y1h Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
|%1?3Mpn fQ+\;iAU TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
cX:HD+wO xY\0zQ 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
auHFir8f u3J?bR <?xml version="1.0" encoding="ISO-8859-1" ?>
T@[! A); f?56=& pHY <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
K=?VDN TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
RKZ6}q1n x0Yse:RE^ S[,8TErz <taglib>的子元素
|.P/:e9 Fl3#D7K Element
WKmbNvN^ Description
K>2 #UzW AW,OHSXh6 tlib-version
K-eY|n Tag库的版本
"&~
0T# TZRcd~ 5$ jsp-version
U7iuY~L Tag库所需要的jsp的版本
PUdM[-zjh M2@b1; short-name
W`z 0" 助记符,tag的一个别名(可选)
:q#K} / Y[Ltrk{ uri
UsQ4~e 4- 用于确定一个唯一的tag库
BVw Wj-, (k`{*!:1a display-name
FP^{=0 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
Xm1[V& cK`"lxO small-icon
>T jJA# 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
*[+)7 RDM`9&V!jp large-icon
c+dg_*^ 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
<#+44>h &<pKx! description
a j\nrD1 对tag库的描述(可选)
=~KsS}`1, !yOeW0/2[ listener
SC &~s$P; 参见下面listener元素
C\ZkGX !? 5U| tag
sZ&G%o 参见下面tag 元素
%\$;(#h os lJC$cy' Listener元素
a`(a)9i =PHIpFIuk 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
7piuLq+ !T,AdNa8 Tag元素
o>/O++7R a } MbH3ufC 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
AJ^#eY5 {yA$V0`N{ 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
76cG90!Z X+k}2HvNG Tag元素的子元素
8ho[I] 3q:n'PC)C 元素名称
-62'}%?A<C 描述
eP.Vd7ky {nT^tAha name
u{N,Ib
8 独一无二的元素名
L6Wt3U`l dsx]/49< tag-class
BvrB:%_: Tag标签对应的tag处理类
fFvF\ CzCQFqXI tei-class
xVL5'y1g B javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
)vg5((C Mb1t:Xf^g body-content
YwY74w: Tag标签body的类型
[+m?G4[ l7{oi! display-name
^ci3F<?Q= 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
1?* 0[?ny`Y small-icon
&UCsBqIY 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
4MuO1W- *'Y@3vKE large-icon
m!z|h9Ed 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
f
h#C' sn h:zK(; description
NLPkh,T: 此tag标签的描述
:j')E`#
!o=U19) variable
<s5qy- 提供脚本变量的信息(同tei-class)(可选)
5]I| DHmu zk*c)s attribute
##Q/I| Tag标签的属性名
[.hyZ}B h_1T,f( 以下章节介绍对于不同类型的tag,如何具体地实现它们。
c gzwx G0u LmW70 g,o?q:FL 简单的tag
'0y9MXRT "<_0A f] iRg7*MQu tag处理类
=[\s8XH, A1P
K 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
>>aq,pH 8d*/HF)h 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
fFjgrK8 1&;QyTN -[U1]R public SimpleTag extends TagSupport
{~|OE-X][ Ev7J+TmXM {
mWR4|1( oI)GKA_Ng7 public int doStartTag() throws JspException
?Kvl!F!` p ~noM/*2r {
uZfnzd)c +dA ,P\ try{
P =3RLL<l W^3uEm&l!) pageContext.getOut().print(“Hello.”);
F":r4`5D"K `qd+f{Q }catch(Exception e){
b=~i)` D+_oVob\ throw new JspTagException(“SimpleTag: “ + e.getMessage());
~4P%%b0,o K=!Bh* }
fwK}/0% s Y?,0T_m return SKIP_BODY;
bAKiq}xG%i OHiQ7#y }
z'uK3ng\hH vad12WrG< public int doEndTag()
x.8TRMk^ 8
k3S {
'*\|;l#1 zC_<(4$-" return EVAL_PAGE;
6[ OzU2nB 3~nnCR[R }
Fu&EhGm6 L\y;LSTU }
v1a6?- gX0R)spg r$]HIvJD 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
dnV[ P 1hcjSO <body-content>empty</body-content>
Or
!+._3i .U T@p %W@v2 带属性的tag标签