标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
_.K<#S 7N
I~47s|v 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
i")ucrf /\|Behif 在这篇文章中,我们主要讨论:
t.= 1<Ed -+Ab[ · 什么是自定义tag标签?
Zh3hCxXa +oR wXO3W · 怎么使用tag标签?
ad'C&^o5 wU)vJsOq o 声明要使用的tag库
7&{[Y^R]" @/0-`Y@? o 找到与之对应的tag处理类
5_= HtM[v] Bd-@@d.H< o tag标签的类型
Tq`rc"&7u 2JS&zF · 自定义tag标签
7S)u7 UsBtk o tag处理类
R[_UbN 28 ^Yu%JCN8g o tag库描述
y759S)U>>p O'~;|-Z< o tag标签示例
8sGaq [ 9#ZR0t.cY o 带属性的tag
D_)n\(3 P*zOt]T o 带body的tag
'}.Z' %; @?\[M9yK o 定义了脚本变量的tag
l8Ks{(wh (_$'e%G0 o 具有协作关系的tag
Ht!]% +-+%6O<C · 自定义tag标签
[
#1<W`95 KG8Km o 一个迭代tag的例子
yJGM"$ pQf5s7 o 一个模板tag库
BA t0YE`-, j`pX2S o tag处理类到底是怎样被调用的?
tsvh/)V N#"( qKL
mL2O 什么是自定义的tag?
}*s%|!{H "g>, X[g 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
;u
"BCW sAec*Q(R 自定义tag标签有很多特色,诸如:
c1L0#L/F6" mcFJ__3MAV · 可以在JSP页面中自定义tag标签的属性
z),@YJU"z B6gn(w3 · 访问JSP页面中的所有对象
"hi)p9 _cR ^B`*4 · 可以动态地修改页面输出
d iG kwKj pNIu;1M5a · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
ROc)LCA [c_o.`S_\ · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
sj& j\<( W|e$@u9 q"O4}4` 使用tag标签
yE4X6 fce~a\y0 EmO{lCENk 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
/$NZj"# 1?}5.*j< 要使用tag标签,JSP程序员必须做2件事:
M!j: 2dT" ?ot7_ vl · 声明此tag标签的tag库
oYn|>`+6:y 1FfSqd · 实现此tag标签
[9U:: gJUawK 声明tag标签所在的tag库
+P5\N,,7R PUJkC 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
{InD/l'v6n y.PsC ' <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
zm7IkYF B{ptP4As- uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
^vA"3Ixb! zs<2Ozv TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
^D.u ;Or]x?- 以下taglib指示符直接引用一个TLD:
gfY1:0 j{?ogFfi <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
V^[B=|56 aI'MVKwMk 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
+8#hi5e b|'{f? <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
rOyKugHe (SnrYO`# 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
]8;2Oh
(n+FEE< <taglib>
{dF_=`. ZFH; <taglib-uri>/tutorial-template</taglib-uri>
@7j$$ |Y")$pjz <taglib-location>
%c"t` N" =$S|Gs /WEB-INF/tutorial-template.tld
a58]#L~ ![l`@NH[U </taglib-location>
$(=0J*ND"
q0y#Y </taglib>
7q;wj~ u4QBD5T" z3mo2e 实现此tag标签
zS<idy F` |JVp(Kx Rxfhk,I 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
Mr6 q7 ucwUeRw, "t!_bma tag标签类型
)ld`2)
4 __OH
gp 1 OS]FGD3a 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
'U/X<LCl Y-fDYMm <tt:tag>
Vu1swq)l WTX!)H6Zv body
}*>xSb1 H2oD0f| </tt:tag>
l/6$BPU` W6Z3UJ- FNy-&{P2 一个不带body的tag标签如下:
/4wPMAlb FesUE_L2$ <tt:tag />
f C_H0h3 u|EHe"V" l`(pV ;{W 简单的tag标签
e4<[|B!O ^P~NE#p5 一个没有body和属性的tag标签如下:
S>nf]J` %RD%AliO}K <tt:simple />
Dxp.b$0t -hpC8YS A=bBI>GEYP 带属性的tag标签
W>cHZ. _ &T&>4I!'M sHn-#SGm 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
|:)ARH6l# [\,Jy8t)\ 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
yDmx)^En E*G{V j <loglic:present parameter = “Clear”>
aYrbB# }J m~b9j 而另一个标签logic:iterate是用表达式来给属性赋值:
)7;E,m<:tO i{2ny$55h <logci:iterate collection=”<%= bookDB.getBooks() %>”
eccJt kpLx?zW--q id=”book” type=”database.BookDetails”>
?v@pB>NZ 6H'W]T& rPXy(d1<`S 带body的tag标签
\wM8I-f! !v68`l15 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
F*J@OY8i 9D,/SZ-v 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
!63]t?QXMG ]aI <logic:present parameter=”Clear”>
Q1^kU0M } wq
=Ef <% cart.clear(); %>
Xn
#v! >&D}^TMYY <font color=”#ff0000” size=”+2”><strong>
5Zy%Nam'gN 'wd&O03& 你选择了清除购物车!
Un^3%=; @;`d\lQ </strong></font>
)Nnrsa .Hm1ispq </logic:present>
[/GCy0jk s]'EIw}mo wHE1Jqpo 到底是用属性还是用body来传递信息?
i>{.Y}; i(an]%'v 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
ihBIE Mi:i1i
cdn #iVr @|, 定义脚本变量的tag标签
|?<^4U8 9`T2 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
%[WOQ.Sh >eucQ] <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
?~=5x {vox
x&UX <% tx.begin(); %>
:)DvZx HE@ 5\.w\ ...
qt`HP3J& =cWg39$(I M+GtUE~" 具有协作关系的tag标签
rq![a};~ rtC:3fDy 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
g66x;2Q 0T.kwZ8 <tt:tag1 attr1=”obj1” value1=”value” />
W,bu=2K6 Tu&W7aoX5 <tt:tag2 attr1=”obj1” />
?F/)<r Y_,Tm 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
sj8lvIY5 O~4Q:#^c <tt:outerTag>
3S{3AmKj? Mt\.?V: <tt:innerTag />
:@#6]W w"
,ab j </tt:outerTag>
3='Kii=LA K8 Hj)$E61 (o518fmR Tag处理类
]6@6g>f? ;uN&yj<}a vpz l{ Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
6!Uk c'r v(~EO(n. 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
.tA=5QY, d5#z\E?? 下表说明不同类型的tag所需要不同的处理过程:
&}!AjA) 0S&C[I
o6 Tag处理类的方法
9=.7[-6i9 q_z ;kCHM Tag标签类型
Ib2n Bg>j 所调用的方法
#Q$e%VJ(c1 46gDoSS 基本标签
[
@9a doStartTag, doEndTag, release
k|3hs('y| [7h/ 2La# 带属性的标签
iiv`ji doStartTag, doEndTag, set/getAttribute1...N, release
hr`,s!0Y z
LZHVvL3 带内容的标签
Mw|lEctN0 doStartTag, doEndTag, release
FXh*!%"* OXS.CFZM 带内容的标签,且内容重复循环
cS(=wC doStartTag, doAfterBody, doEndTag, release
GC7W7B o ]@'R<F(u 带内容的标签,且内容与JSP交互
Qq3>Xv < doStartTag, doEndTag, release, doInitBody, doAfterBody, release
?^WX]SAl 6f)7*j~ 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
tY%T ~T!D:2G 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
qJ[wVNHh! uTNy{RBD+ 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
{hVc,\A \0.!al0 k,LaFe`W Tag库描述(简称TLD)
1pP q)}=+
t|C?=:_ 6\USeZh Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
4@=[rZb9 L'O=;C"f TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
$ZlzS`XF7 6W9lKD_i 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
=yZ6 $ hK <K
<|G <?xml version="1.0" encoding="ISO-8859-1" ?>
.p%V]Ka *1h@Jb34 <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
WF-^pfRq~ TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
y\R-=Am". &/?OP)N,} T;v^BVn <taglib>的子元素
[nLd> 2P c=aVYQ"2 Element
wlpcuz@ Description
zS'{F>w rh T!8dTk tlib-version
et<@3wyd] Tag库的版本
u.2^t:A '![VA8 jsp-version
`HILsU=| Tag库所需要的jsp的版本
uTrQ<|}# 8#IEE|1 short-name
g{JH5IZ~ 助记符,tag的一个别名(可选)
w:2yFC B-V uri
Mo\nY5 用于确定一个唯一的tag库
J]|S0JC` [ZD`t,x( display-name
lHO.pN`2 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
zLg_0r*h1 0OBwe6* small-icon
lM.k*`$ 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
v1$}JX tDtqTB} large-icon
&Qt1~#1 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
z5W;-sCz @'"7[k!y; description
xLw[
aYy4 对tag库的描述(可选)
X
[;n149o KJ_L>$
]* listener
XlJ+:st 参见下面listener元素
CFeAKjG S9 @*g3 tag
wD SSgk 参见下面tag 元素
jR{t=da hroRDD Listener元素
9HAK Nrc-@ ] 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
[yVcH3GcjI \{1Vjo Tag元素
s"l ^v5 kp*BAQ 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
jyC>~}? )T@+"Pw8t 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
`7'=~BP?X [}y"rs`! Tag元素的子元素
i>;6Z s>S Job&qW9W` 元素名称
=A;79@bY 描述
MsA)Y 5S4`.' name
sJ|IW0Mr 独一无二的元素名
7` t, }:+P{ tag-class
(Jk:Qz5 Tag标签对应的tag处理类
s$VLVT*6
EZ^M?awB4 tei-class
y |Tv;v1L javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
,tuZ_"?M < !]7Gt body-content
%xt\|Lt Tag标签body的类型
UFUm-~x` e{d$OzT) V display-name
vo2 T P: 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
q|e<b "`5BAv;u small-icon
[Kd"M[1[< 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
*.
;
}v@ n:YA4t7S large-icon
t8-LPq 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
@fSqGsSk 9wv 7HD| description
#NWc<Dd 此tag标签的描述
9_pOV%Qs ) 2Hl\"F variable
ow,=M%x"0 提供脚本变量的信息(同tei-class)(可选)
8 9f{8B]z jVdB- y/r attribute
xsXf_gGu Tag标签的属性名
oOK&+r7 Di #E m[ 以下章节介绍对于不同类型的tag,如何具体地实现它们。
Q?W}]RW )9>E} SU/ ?:sQ]S/Er 简单的tag
ca8.8uHY\ XJi^gT N R8R,!3 N tag处理类
W>`#`u Fv9n>%W& 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
}4"T#
[n# MM4Eq>F/ 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
e5fzV.' 5 fHwr6"DJ /h73'"SpDy public SimpleTag extends TagSupport
8p~G)J3U f}F
{
&sJ%ur+G 7 {#^zr public int doStartTag() throws JspException
]Q0+1'yuK uSK<{UT~3 {
o9uir"= z8hAZ?r1` try{
' fP`ET5 &c1zEgl pageContext.getOut().print(“Hello.”);
ZtqN8$[6n Lj03Mx.2S }catch(Exception e){
ar|!iU 6@o *"4~Q throw new JspTagException(“SimpleTag: “ + e.getMessage());
_m|Tr*i8 G[5z3 }
O<?z\yBtS^ lGtTZcg return SKIP_BODY;
\4|o5, +(@
S^4T#/ }
MUd
9R " tUF,G(< public int doEndTag()
#q%V|Ajq *(sFr E {
"FT(U{^7d g}=opw6z return EVAL_PAGE;
2k$~Mv@L )~l`%+ }
<i!7f26r Cn>RUGoUsI }
nJ-U* yz Y^@Nvt$<K
6:vdo~ 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
dLnMd0 i5 F9* <body-content>empty</body-content>
V,CVMbn/%N kX^Y{73 b)Px 带属性的tag标签