标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
_iCrQJ0"T Wp+lI1t 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
\ 4^zY' ,i|K} Y& 在这篇文章中,我们主要讨论:
63J3NwFt wVFa51a)yy · 什么是自定义tag标签?
{&XTa`C ~JNE]mg · 怎么使用tag标签?
i /I
pUS: HJk| o 声明要使用的tag库
uF1 4; lZ)6d-vK o 找到与之对应的tag处理类
)">#bu$ DU8\1( o tag标签的类型
$y,KDR7^ A,t g268 · 自定义tag标签
0Ze&GK'Hf 8t=O=l\ o tag处理类
kr|r-N` Mpyza%zj o tag库描述
H! 5Ka#B 9M'"q7Kh o tag标签示例
`GBJa k SP<Sv8Okj o 带属性的tag
j>?nL~{
$xdo=4;| o 带body的tag
re/u3\S Sz<:WY/(x o 定义了脚本变量的tag
/m;Bwu :h(3Ep o 具有协作关系的tag
?Fa$lE4 a@&qdp · 自定义tag标签
^ H2TSaJ; .sQV0jF { o 一个迭代tag的例子
[ ^\{>m7 N#jUqm o 一个模板tag库
>T*BEikC yK"\~t[@X: o tag处理类到底是怎样被调用的?
3I)oqS@q' 8YE4ln
|oSt%lQ1 什么是自定义的tag?
z1,#ma}. J Q*~le* 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
ZVJ6 {DS/ ;nbEV2Y< 自定义tag标签有很多特色,诸如:
%
q!i YqXN|& · 可以在JSP页面中自定义tag标签的属性
s/~pr.>-l N4-Y0BO · 访问JSP页面中的所有对象
*L>usLh z;@<J8I · 可以动态地修改页面输出
s0vcGh#w ]
s 2ec · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
DwFvM0O6\ )>b1%x} = · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
5N6R%2,A jt323hHth fM:bXR2Y' 使用tag标签
kO^ rk&oKd_&i pX>wMc+ 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
Ekrpg^3qp" W^ask[46R 要使用tag标签,JSP程序员必须做2件事:
o](ORS$~ !IC
.0I` · 声明此tag标签的tag库
H&F2[ j$T bzZdj6>kX · 实现此tag标签
@q]!C5
Sjwwc6_c 声明tag标签所在的tag库
^tm2Duv ;UX9Em 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
}V.fY3J- >.C$2bW<L <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
r
z@%rOWV v[x 5@$ uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
#3?"#),q Ue,eEer TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
23p.g5hJi 5HL>2
e[ 以下taglib指示符直接引用一个TLD:
a04S&ezj {/?{UbU <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
em^2\*sxpA WRAv>s9 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
>[T6/#M M_75bU <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
Ud>hDOJ3 hN1[*cF 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
n],cs 4T&Jlu?: <taglib>
p{r{}iYI 98<^!mwF <taglib-uri>/tutorial-template</taglib-uri>
ao2o!-?!t ;tD?a7 <taglib-location>
R5uz< pAN$c" /WEB-INF/tutorial-template.tld
x5U;i #&{)`+!" </taglib-location>
=5%}CbUU)4 Pm24;' </taglib>
*;t_VlaZ .J5or ;%u)~3B$JK 实现此tag标签
4=* ml}RP a5@lWpQsV ;]/cCi 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
OW> >6zM xxdxRy9/ N *n?hN tag标签类型
@(tuE zfml^N _8z 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
DB] ]6 Qm?o^%a <tt:tag>
h&{>4{ G&0JK ,Y body
0j'k%R[l 1g|6,J </tt:tag>
e=Kr>~q= !{oP'8Ax$ ou&7v<)x4 一个不带body的tag标签如下:
g[xn0rG
YwB\kN <tt:tag />
~x+24/qT >Gxu8,_; ;|K(6) 简单的tag标签
0`e- ; kI$X~s$r 一个没有body和属性的tag标签如下:
{D&:^f <.6$zcW <tt:simple />
K<Y-/t 7Rom#Kl: _$4vk 带属性的tag标签
/E6Tt "{(4 +f?xVW<h 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
gMZ?MG 4,R1}.?BzJ 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
7Y'.yn V|dKKb[Lve <loglic:present parameter = “Clear”>
D&&11Iz& )8Sm}aC 而另一个标签logic:iterate是用表达式来给属性赋值:
5fa_L'L# {R.@EFkZ <logci:iterate collection=”<%= bookDB.getBooks() %>”
o#&;,9 ^)/oDyO id=”book” type=”database.BookDetails”>
eTa[~esu. [ 5kaF" <?iwi[S 带body的tag标签
*YY:JLe -n$fh::^ 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
r`/tb^ w-MnJ(r 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
%!1:BQ,p,i +EgQj*F* <logic:present parameter=”Clear”>
!~k-Sexh niN$!k+Jr <% cart.clear(); %>
)Ikx0vDFQ ^?tF'l` <font color=”#ff0000” size=”+2”><strong>
>?A3;O] Lv
,Ls 你选择了清除购物车!
M0% ):P?x xpVYNS{c+| </strong></font>
$
V"7UA22 ojd/%@+u+Y </logic:present>
R|AGN*. 4E& 3{hnp *tT}y(M 到底是用属性还是用body来传递信息?
%.D@{O ve /Q6j{ 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
N~ XzgI nPUq+cXy]C {*%'vVv+ 定义脚本变量的tag标签
0$l D /z+}xRS 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
t=ry\h{Pc Hv1d4U"qM <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
Mzx y'UV X/nb7_M <% tx.begin(); %>
m:~s6c6H EmR#)c~(W ...
?<slB>8 e&u HU8k* %+9Mr ami 具有协作关系的tag标签
PF-
sb&q G}\E{VvWh 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
l$Y7CIH %-:6#bz <tt:tag1 attr1=”obj1” value1=”value” />
8P'>%G<m Piz/vH6M} <tt:tag2 attr1=”obj1” />
d+fig{<b 2,<!l(X 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
=GjxqIv )vk$]<$ <tt:outerTag>
t
<#Yr%a 8<uKzb(O: <tt:innerTag />
xFS`#1 dYJW`Q;j.| </tt:outerTag>
eW+z@\d9Gz R28h%KN Bf F$ Tag处理类
F/}PN1#T jfHVXu^M hC8'6h Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
=2{ ^qvP D{/GjFO 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
nQvv'%v0 %c(':vI# 下表说明不同类型的tag所需要不同的处理过程:
hun/H4f| l23#"gGb Tag处理类的方法
K$\]\qG6 4>>d
"<}C Tag标签类型
/W/ =OPe 所调用的方法
>9|/sH@W jzu1>*ok 基本标签
*A O/$K@Ma doStartTag, doEndTag, release
,?7URx* (_E<? 带属性的标签
Uw][ U doStartTag, doEndTag, set/getAttribute1...N, release
F\&R nDJ [*#ms=Zdc 带内容的标签
-pc*$oe doStartTag, doEndTag, release
BxO8oKe i%0Ml:Y 带内容的标签,且内容重复循环
y#^d8
}+ doStartTag, doAfterBody, doEndTag, release
kL,AY-Iu{@ SUfl`\O 带内容的标签,且内容与JSP交互
+kQ$X{+;8 doStartTag, doEndTag, release, doInitBody, doAfterBody, release
Ah28D!Gor ,`MUd0 n 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
xO6)lVd
grnlJ= 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
do%6P^qA 2|Hq[c=~ 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
RpR;1ktF> QkwBw^'_5 7\K=8G Tag库描述(简称TLD)
Dw?nf 7
rOziKZ" <`b)56v:+ Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
U*=ebZno 9=~"^dp54% TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
Y_)!U`>N? /N7j5v( 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
{o4m3[C7=} +EJIYvkFm <?xml version="1.0" encoding="ISO-8859-1" ?>
y'pAhdF kl_JJX6jPP <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
DnP>ed"M! TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
a&p|>,WS tD.md_E |28z4 . <taglib>的子元素
=h\,-8 ;dNKe.`Dg Element
cRK1JxU Description
[GX5jD# 4}Y2
B$ tlib-version
:e`;["(, Tag库的版本
~%B^`s =M)+O%`*6 jsp-version
u!];RHOp| Tag库所需要的jsp的版本
)}1J.>5 r%JJ5Al.S short-name
hdp;/Qz& 助记符,tag的一个别名(可选)
S.aSNH< 3@*J=LGhKc uri
^i2W=A'P 用于确定一个唯一的tag库
tpO%)* x-+Hy\^@| display-name
%%}U
-*b 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
%vDN{%h8 aRdzXq#x small-icon
|vw0:\/H 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
%,E\8{I+
PW x9CT large-icon
+;tXk
被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
U@!e&QPn +LCpE$H description
F?? })YX 对tag库的描述(可选)
o
nt8q8 D$+9` listener
T$)&8"Xya 参见下面listener元素
+Fp8cT=1 Fx*iAH\e tag
d:.S]OI0 参见下面tag 元素
x}$SB%9/ (;;%B = Listener元素
*Fb]lM7D k*d0ws#<l 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
@k>}h\w %{WS7(si Tag元素
9}p?h1NrY JwL}|o6 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
GSIRZJl oW3j|V 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
HKbyi~8N= m-4P*P$X Tag元素的子元素
D]\of#%T V}o`9R@tx} 元素名称
V6P2W0m 描述
ZgK[,<2 xr}3vJ7 name
?zGx]?1P1< 独一无二的元素名
dE~]%fUFy- mZQW>A]iE tag-class
,c<&)6FU] Tag标签对应的tag处理类
#$2{l,> n]^zIe^6 tei-class
AI0YK"c? javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
YEH /22 p'{B|ujj6 body-content
oJb${k<3 Tag标签body的类型
\H^DiF%f9 r==d^ display-name
IcRA[
g 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
d$qivct f]%:.N~1w small-icon
=jXBF. 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
jYDpJ##Zb q{T[|(! large-icon
f?vbIc` 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
@lpo$lN0R M#%l} description
OSreS5bg 此tag标签的描述
-5vg"|ia, AX($LIy9P variable
g27 iE 提供脚本变量的信息(同tei-class)(可选)
)#S;H$@$ nSY3=Edx= attribute
]Fi_v?42x Tag标签的属性名
Q*4{2oQ )E9[=4+*C$ 以下章节介绍对于不同类型的tag,如何具体地实现它们。
UMtnb:ek
ac 8J|2b; Vf 简单的tag
Nz/PAs7g6 JBqL0H U'~M(9uv: tag处理类
J5dwd,FQ NxY B)`~ 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
by07l5 uCkXzb9_z 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
e}l F#$ tVfZ~qJ )
uM*`% public SimpleTag extends TagSupport
6Qtyv jW]Q- {
BoJpf8e'-e bu0i# public int doStartTag() throws JspException
atr0hmQ u@&e{w~0 {
0O>T{< Qe,jK{Y<
- try{
o3 b=)E X1 DE pageContext.getOut().print(“Hello.”);
r2ZSkP. 5&)T[Q X` }catch(Exception e){
^mH:8_=(. To/6=$wto throw new JspTagException(“SimpleTag: “ + e.getMessage());
x%h4'Sm W%ml/ 4 }
1t+uMhy*y L6d^e53AP return SKIP_BODY;
-@7?N6~qZx mD5Vsy{Pb }
]{Y7mpdB <JUumrEo public int doEndTag()
c,>y1%V*S{ {L'uuG\9U {
3~q#P B*Z}=$1j return EVAL_PAGE;
osM[Xv {Jbouj?V! }
+{~cX]| %-?k [DL6 }
^%5;Sc1V d+45Y,| ,#Pp_f< 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
)7c/i+FsC 2CMWJi <body-content>empty</body-content>
c1tM(]& >o:y.2yCe hZIbN9)8A 带属性的tag标签