标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
/':64#' [hpkE lE 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
E{e ?6nB=B)/ 在这篇文章中,我们主要讨论:
QT73=>^B =Ry8E2NuM · 什么是自定义tag标签?
+kEM%z cQ1Axs TO · 怎么使用tag标签?
-$:*!55:j ;Ss!OFK o 声明要使用的tag库
/\uopa 'UxI-Lt o 找到与之对应的tag处理类
/Z!$bD 5/i/.
0?n o tag标签的类型
0bc>yZ\R ~Dz:n]Vk/ · 自定义tag标签
}o7- 3!{L! O"EL3$9V o tag处理类
#1\`!7TO3 Bos}
`S![ o tag库描述
U#K4)(C ~o|sm a5. o tag标签示例
1cMLl6Bp> =EM<LjO o 带属性的tag
5@
td0 :t9![y[=| o 带body的tag
t']/2m.&p %t!r
pyD o 定义了脚本变量的tag
(Fuu V{x| TOKt{`2} o 具有协作关系的tag
_e;bB?S *i#N50k*j' · 自定义tag标签
p-)@#hE DNqV]N_W o 一个迭代tag的例子
)V>zXy}Y ~n) | o 一个模板tag库
GD
d'{qE6 %e0X-tXcmX o tag处理类到底是怎样被调用的?
[OUV!o aG~zMO_)] ?I?~BWu 什么是自定义的tag?
kONn7Itbu 7][fciZN 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
#I.~+M }vx,i99W? 自定义tag标签有很多特色,诸如:
$joGda 8v8-5N · 可以在JSP页面中自定义tag标签的属性
LVm']_K(f NIQ}+xpC · 访问JSP页面中的所有对象
ZsXw]Wa ("j;VqYUL · 可以动态地修改页面输出
5lP8#O?= N~IAm:G}[ · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
9+@z:j ((#BU=0iK · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
D_$N2>I- DbB<8$ C9MK3vtD. 使用tag标签
Qjnh;uBO d}Guj/cx, -AD`(b7q 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
'%ZKvZ- _Li.}g@Bd 要使用tag标签,JSP程序员必须做2件事:
He4HIZ qzA_ ~=g · 声明此tag标签的tag库
$kHXt]fU 7t#Q8u? · 实现此tag标签
V#.pi zb MZf?48"f 声明tag标签所在的tag库
4gev^/^^ &=M4Z/Ao 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
.o]I^3tfc cC/32SmY4 <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
sq(5k+y*J rr\u)D#) uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
a3w6&e` K;rgLj0m TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
yS4VgP'W qrj f 以下taglib指示符直接引用一个TLD:
e1JHN }Rh%bf7, <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
'U ZzH$h "s] 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
XRQ1Uh6 OgQ8yKfDB <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
i%<NKE;v7m 0QPY+6 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
`+vQ5l$;L *,:2O&P <taglib>
RFFbS{U* g@s`PBF7` <taglib-uri>/tutorial-template</taglib-uri>
,YBO}l )p;t
'*] <taglib-location>
8EdaqF +e*C`uP! /WEB-INF/tutorial-template.tld
J?dz>3Rhx9 3)o>sp)Ji$ </taglib-location>
RyukQY~<W 3]lq#p: </taglib>
1i.3P$F }|) N5bGQe 0m.`$nlV- 实现此tag标签
<*^|Aj|# Hhk`yX c_ s?S e]?i 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
yX{7<\x
?q Q.Wj6Mj "[fPzIP9 tag标签类型
fr04nl [:(O`# K
re*~ " 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
[PiMu,O[v SEg{Gso9b <tt:tag>
[Y.JC'F# g$"x,:2x{ body
'-n
Iy$> F !OD*] </tt:tag>
|&-*&)iD|w D$H&^,?N ''q;yKpaz 一个不带body的tag标签如下:
Eul3 {+] s 72yu} <tt:tag />
Ei+lVLoC qBK68B) 2G5|J{4w 简单的tag标签
Evg#sPu\ KVEc:<|x 一个没有body和属性的tag标签如下:
_99 +Vjy :(/1,]bF <tt:simple />
L>WxAeyu1K AB+lM;_> >$CNR*}@ 带属性的tag标签
lH/"47 [N%InsA9k ?G~rYETvw 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
bf1$:09 j"TEp$x 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
CKFr9bT{ sh` 3$ { <loglic:present parameter = “Clear”>
{2 T:4i5 F=*t]X[z} 而另一个标签logic:iterate是用表达式来给属性赋值:
\Wppl,"6c <jYyA]Zy5 <logci:iterate collection=”<%= bookDB.getBooks() %>”
<?L5bhq IN#/~[W id=”book” type=”database.BookDetails”>
FqnD"]A + `'wY? U+4[w`a} 带body的tag标签
]g oVQ'Y 4, Vx3QFZ 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
=s'H o QZ7W:%r(4 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
Xa;wx3]t H=WB6~8) <logic:present parameter=”Clear”>
?5lO1( n!X%i+|4x <% cart.clear(); %>
HpUJ_pZ B>d49(jy <font color=”#ff0000” size=”+2”><strong>
yHs9J1Sf ]{{%d4 你选择了清除购物车!
.}+3A~ MZA%ET,l,< </strong></font>
Bonj K# =F/ R*5:T </logic:present>
ds+2z=!!e _(io8zqe{j 1g,gilc 到底是用属性还是用body来传递信息?
9PO5GYU 4XJ']M(5; 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
=Y!.0)t;* v1}ijls Td7Q%7p: 定义脚本变量的tag标签
~+BU@PHv 'h~IbP 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
%zEy.7Ux %'=TYvB 2 <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
U Lq`!1{
:U'n0\ <% tx.begin(); %>
VB8eGMo /Hm/%os ...
/J!hKK^k &pz`gna e,#5I(E 具有协作关系的tag标签
HD$`ZV K~^o06 Y 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
LSXsq} 5OOXCtIKf <tt:tag1 attr1=”obj1” value1=”value” />
,?%Y*?v )ytP$,r![S <tt:tag2 attr1=”obj1” />
"~6&rt I7|a,Q^f 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
ev/)#i#s{ Dq!YB[Z$: <tt:outerTag>
?aTC+\= CJ)u#PmkJ <tt:innerTag />
$SFreyI;Uf ]eFNR1<OP </tt:outerTag>
#zSNDv` h.- o$+Sa 0CX9tr2J Tag处理类
r"x}=# b! -(%Xq{ >oEFuwE Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
7VkjnG^!: 6BQq|:U 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
YCzH@94QeV |Df`Aq(eYJ 下表说明不同类型的tag所需要不同的处理过程:
mc,HliiJ ,L>{(Q) Tag处理类的方法
9v
,y XC/M:2$ Tag标签类型
6B>*v`T: 所调用的方法
NJoHrhC=' QOJ5 基本标签
OMYbCy^ doStartTag, doEndTag, release
NW21{}=4 )B~{G\jS 带属性的标签
}>YEtA doStartTag, doEndTag, set/getAttribute1...N, release
^QHgc_oDm K3rsew
n 带内容的标签
6BXZGE doStartTag, doEndTag, release
mwz!7Q H6$pA^ 带内容的标签,且内容重复循环
_R
;$tG, doStartTag, doAfterBody, doEndTag, release
'=K~M
^fS_h`B 带内容的标签,且内容与JSP交互
biQ~q$E doStartTag, doEndTag, release, doInitBody, doAfterBody, release
nvodP"iV _71I9V& 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
w>RwEU+w=@ >7W8_6sC< 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
Gh%dVP9B@P [$\VvRu% 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
:FS~T[C; d,j)JnY3V ukD:4sv Tag库描述(简称TLD)
2Aa W7 T2j+] `j.-hy>s Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
.^rsVNG =`V9{$i TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
S^i<_?nwg v:9Vp{) 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
MP
Q?Q]' 5'(#Sf <?xml version="1.0" encoding="ISO-8859-1" ?>
ET6}V"UD zj1_#=] <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
pM!cF TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
<2I<Z'B,e 0{Zwg0& = o1&.v2j <taglib>的子元素
nC9xN :+fW#: Element
?V)M! Description
dW|S\S'& _ukBp*u tlib-version
~c>]kL(, Tag库的版本
C7
9~@%T ITU6Eq jsp-version
anUH'mcK* Tag库所需要的jsp的版本
<a
D}Ko( :C#(yp short-name
K7
tSSX<N 助记符,tag的一个别名(可选)
>>h0(G| XO/JnJ^B uri
gvxOo#8] 用于确定一个唯一的tag库
QUc&f+~ nN[QUg display-name
_w9:([_ 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
@ c%h fI ~t.i;eu small-icon
O-<nLB!Wf 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
~NwX,-ri )TkXdA?. large-icon
gJ5|P
. 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
nrz2f7d$ 59a7%w description
L' x[wM0w; 对tag库的描述(可选)
0tN/P+!| H3BMN}K~ listener
9M .cTIO{ 参见下面listener元素
m' L8z
fX XSo$;q\ tag
tWI4x3&2 参见下面tag 元素
9,AHC2kn% 8lT2qqlr Listener元素
f9b[0L >iWw
i'T= 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
u-X P` CDRz3Hu U Tag元素
h%%dRi ^36m$J $ 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
0BHSeO, ]}N&I_mU 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
ZG-[Gz ZfWF2%]< Tag元素的子元素
X}j_k=, C dWDf(SS 元素名称
}!5+G:JAh 描述
<0^L L ':?MFkYC name
DzK%$#{< 独一无二的元素名
:g"UG0]; 7D)i]68E tag-class
mMtX: Tag标签对应的tag处理类
B ez 7 G\o*j| tei-class
ZklZU,\!|v javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
%0^taA ch:0qgJ body-content
oxgh;v* Tag标签body的类型
UhF+},gU sT% ^W display-name
oi/bp#(fa 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
^-pHhh|g "_36WX small-icon
=jW=Z$3q 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
Bis'59?U_ $+Vp> large-icon
pe7R1{2Q_s 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
4l"oq"uc RS1c+]rr description
hG%J:} 此tag标签的描述
}SF<. A N'e3< variable
%oN5 jt 提供脚本变量的信息(同tei-class)(可选)
#~>ykuq YA4;gH + attribute
}6^d/nE*T
Tag标签的属性名
[%yCnt dQH9NsV7g 以下章节介绍对于不同类型的tag,如何具体地实现它们。
P[bj{lo J+20]jI #[aHKq:?b 简单的tag
v6_fF5N/ 9)]asY xr'gi(.o tag处理类
j5qrM_Chg |dQ-l ! 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
vB9v8@[I& vd}Y$X 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
I~P]_DmM r1QLSD]i6 j@+QwZL| public SimpleTag extends TagSupport
xHY#" ` p)$7! {
G^=C#9c.m CHX- 4-84{ public int doStartTag() throws JspException
j6{9XIRo_ :")iS?l {
4!
V--F tHV81F1J try{
ag\xwS#i5H NU?05sF pageContext.getOut().print(“Hello.”);
12MWO_'g8 } :8{z`4H }catch(Exception e){
\gjYh2> 0($ O1j~$ throw new JspTagException(“SimpleTag: “ + e.getMessage());
y7)$~R):- w-M,@[G }
z&r@c-l@ \9GJa"xA` return SKIP_BODY;
*D$[@-7 'qT[,iQ }
9EqU
2~ 1:r 8p6 public int doEndTag()
P7`sJ("# */JMPw& {
Y
&"rf
.W)%*~ O!; return EVAL_PAGE;
|X$O'Gf#n Nn%[J+F }
LU=`K4 r#CQCq }
0j)D[K "<y0D!& Lupug"p0
注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
3HP o*~"] {x#I&ra <body-content>empty</body-content>
G
uLU7a `78:TU~5S L]C|&KP 带属性的tag标签