标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
,L$,d _qsg2e}n 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
ok(dCAKP L[O.]2 在这篇文章中,我们主要讨论:
9;tY'32/ |6!L\/}M% · 什么是自定义tag标签?
*#7]PA Qw ?(>fB2^ · 怎么使用tag标签?
Qb?eA ev9ltl{ o 声明要使用的tag库
y28 e=i #?fKi$fS;L o 找到与之对应的tag处理类
E@7);i5K #SqU>R o tag标签的类型
rixt_}aE Jq_AR!} % · 自定义tag标签
Q=#N4[W' E{xcu9 o tag处理类
L<Q>:U.@\ ;ji["b o tag库描述
zaG1 LW*v/`@ o tag标签示例
Wph@LRB] 4Bk9d\z o 带属性的tag
$n* wS, =jkiM_<h o 带body的tag
dQJ)0!B vY2^*3\<D o 定义了脚本变量的tag
Z Z9D6+R P;
9{; o 具有协作关系的tag
89\DS!\x9 V~fPp"F · 自定义tag标签
}N0v_Nas;v XxLauJP
K o 一个迭代tag的例子
PAS0 D
# +AYB0`X) o 一个模板tag库
9}jezLI/3 $HP<C>^Z8 o tag处理类到底是怎样被调用的?
oe,yCdPs 0{qe1pb w 6D/K=- 什么是自定义的tag?
9qI#vHA Eh&-b6: 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
Ft 6{g
JBG rObg:(z&\ 自定义tag标签有很多特色,诸如:
{3eg4j.Z R?iC"s! · 可以在JSP页面中自定义tag标签的属性
XU|>SOR@z q}cm"lO$ · 访问JSP页面中的所有对象
T&+y~c[au Mq52B_ · 可以动态地修改页面输出
4KB>O)YNg' D|D)782 · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
S,vh odhcU5 · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
!yD$fY R3hyz~\x& .>
5[; 使用tag标签
0bl 8J5Ar5 uYCWsw/ ,vB~9^~ 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
85qD~o?O r mJ`^6V 要使用tag标签,JSP程序员必须做2件事:
W]I+Rlv)U v@QfxV2 · 声明此tag标签的tag库
`l0"4[? qh#?a' · 实现此tag标签
Td5yRN! ? vbEO pYCS 声明tag标签所在的tag库
fVz0H1\J& z
-uW, 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
(O"-6`w[ `Ha<t. v( <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
M`p[ Zq 98XlcI# uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
T&^b~T(y X.eocy TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
/~3kkM(Ty T\w{&3ONm 以下taglib指示符直接引用一个TLD:
65U&P5W 4(&sw<k <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
ZKt`>KZ J*4T|#0 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
YK>?;U+| @1s
2#)l( <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
Xxr"Gc[ GTke<R 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
[oOV@GE 6cXZ3;a <taglib>
#vzt6x@* /kAbGjp0 <taglib-uri>/tutorial-template</taglib-uri>
B7(bNr KJ
cuZ."wX <taglib-location>
}#2I/dn w^MiyX /WEB-INF/tutorial-template.tld
?*&5`Xh yOO@v6jO) </taglib-location>
y wmC>`0p I ;F\'P)e </taglib>
#|K5ma DFp">1@`PR Y'yGhpT~ 实现此tag标签
(BGflb B-h@\y 4 {+47=n 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
B/I1<%Yk rPK 1# gWfMUl tag标签类型
WHcw5_3# G
UK%RC8 #N'bhs 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
vngn^2 F#a'N c9 <tt:tag>
gwDVWhq !M}ZK( body
|LirjC4 7A^L$TY </tt:tag>
%7
$X
* > ,x``- |%@pjJ`3 一个不带body的tag标签如下:
yM*_"z!L "EnxVV <tt:tag />
A().1h1_k >cH}sNHy %*OQH?pyx} 简单的tag标签
{Rq5=/b C?g<P0h 一个没有body和属性的tag标签如下:
%[on.Q'1]2 x#fv<Cj4 <tt:simple />
D!mx &O9 as"@E>a "] ]aF1 带属性的tag标签
0+NGFX\p
CP
Ju= "
f.9u 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
7GRPPh<4 p21li}Iu 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
e6Kyu* +|qw>1J( <loglic:present parameter = “Clear”>
P?J\pJ1|7 q-qz-cR 而另一个标签logic:iterate是用表达式来给属性赋值:
bycnh !:a^f2^= <logci:iterate collection=”<%= bookDB.getBooks() %>”
i4mP*RwC xn anca id=”book” type=”database.BookDetails”>
@_
Tq>tOr& ^GNL:D%6d 4jW <*jM 带body的tag标签
's$/-AV ])?[9c 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
r-,u)zf" 8Yf=) 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
8zQN[[#n P?+
VR=t <logic:present parameter=”Clear”>
8Fv4\dr :(;ho.zz <% cart.clear(); %>
yeA]j[ # Se>v|6 <font color=”#ff0000” size=”+2”><strong>
mp8Zb&Ggb Q}#xfrprF 你选择了清除购物车!
o_&Qb^W G4uA&"OE </strong></font>
0B"_St}3D w`[`:H_z </logic:present>
:VE0eJ]J6 j|LO g @ X5#? 到底是用属性还是用body来传递信息?
Px&)kEQ I2z6iT4nB 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
Nb)Mh goc; .~? ptlag&Z 定义脚本变量的tag标签
luJNdA:t& R,8Tt!n 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
o0TB>DX$` k=9k4l <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
TjOK8
t [ ^gb6W9Y <% tx.begin(); %>
;f
/2u 9&{HD ...
DuIgFp iB + _+A h$p}/A 具有协作关系的tag标签
ysFp$!9Ux fJ+4H4K 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
ps33& zICrp <tt:tag1 attr1=”obj1” value1=”value” />
9/{ 8Y& zm#%]p80f <tt:tag2 attr1=”obj1” />
|Rz}bsrZ 2\CZ"a#[ 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
7Ac.^rv5 [X kWPx` <tt:outerTag>
o)8VJ\ & XpPcQIM* <tt:innerTag />
(O/W`qo =69sWcC8 </tt:outerTag>
0Z{u;FI ?O0,)hro y:k7eE" Tag处理类
O6ltGtF sn+ kFvk}S E,QD6<?[ Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
;rl61d}NH# H%ScrJ#V 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
u $qazj &:~9'-O 下表说明不同类型的tag所需要不同的处理过程:
?8)k6: +No Ve# Tag处理类的方法
&UAYYH 5kCXy$"% Tag标签类型
)"%J~:`h} 所调用的方法
(]-RL
A> qR
kPl!5 基本标签
zuF]E+ doStartTag, doEndTag, release
WfQZ7e uEkGo5 带属性的标签
I p|[ doStartTag, doEndTag, set/getAttribute1...N, release
f]2;s#cu %K0Wm#) 带内容的标签
?y,KN}s_ doStartTag, doEndTag, release
u ^M'[<{ dwb ^z+ 带内容的标签,且内容重复循环
[B j\h7G doStartTag, doAfterBody, doEndTag, release
/xd|mo)D &Y3ZGRT 带内容的标签,且内容与JSP交互
eTI?Mu>C doStartTag, doEndTag, release, doInitBody, doAfterBody, release
E9]*!^=/ )U{\c2b 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
WUb] 8$n JO~62='J 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
~6{U^3 *P?Rucg 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
gI/(hp3ob ]Mvpec_B >|mZu)HIY; Tag库描述(简称TLD)
ak{XLzn xEufbFAN? ViU5l*n; Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
:g{ybTSEe k{bC3)'$#R TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
'Jd*r(2d AmrVxn4 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
bQdu= s[ zX6Q7Bc <?xml version="1.0" encoding="ISO-8859-1" ?>
k h6n(B\ V/RV,K1/ <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
SQ<{X/5 TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
N l^uA Xm<|m# '_ys4hz} <taglib>的子元素
4jzjrG pk6<wAs*?# Element
4h
T!DS Description
z}Um$'. = c7nbHJi tlib-version
[MF&x9Ss?% Tag库的版本
L0Ajj= ER;\Aes*? jsp-version
R`,|08E Tag库所需要的jsp的版本
-8v:eyc z6|kEc"{ short-name
B &3sV+ 助记符,tag的一个别名(可选)
*a-KQw
)!;20Po uri
Hxn#vAc 用于确定一个唯一的tag库
Bve',.xH tRNMiU display-name
U[z2{\ 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
2SlI5+u y[GqV_~?Y small-icon
fh`}~ aQ 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
x+v&3YF t_+owiF)M large-icon
QQD7NN> 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
7/iN`3Bz FytGg[#] description
0n\AUgVPF 对tag库的描述(可选)
O^_CqT% d+"F(R9 listener
+}eK8>2 参见下面listener元素
$"va8, iDdR-T| tag
bm h@SB 参见下面tag 元素
^2i$AM1t H|/"'t
OZ Listener元素
+o35${ V;gC[7H 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
%g69kizoWi )~IOsTjI Tag元素
|hX\ep o\fPZ`p-m~ 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
g"`jWSt7Q qHPinxewx 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
L]l?_#*x S'`RP2P Tag元素的子元素
->Fsmb+R l~[
K.p& 元素名称
%vUUx+ 描述
# wyjb:Ql ZA}!Rzo name
F2Gg_u@7M 独一无二的元素名
r4fd@<=g r]Lj@0F>8 tag-class
L@J$kqWY Tag标签对应的tag处理类
"]q0|ZdOwH "![KQ tei-class
vzF6e eaD javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
bAUYJPRpy O9RnS\ body-content
Z%
]LZ/O8 Tag标签body的类型
NOf{Xx<#k +~7[T/v+n display-name
<3Rq!w/ 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
pp2 Jy{\d ,+x\NY2d small-icon
@6-3D/= 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
W#kLM\2L TN/&^/ large-icon
hMgk+4* 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
pV1;gqXNS
"#pN
description
^ '_Fd 此tag标签的描述
lq?N>~PG xXJzE|)1h! variable
%Rf{v5 提供脚本变量的信息(同tei-class)(可选)
{;o54zuKf dvglh?7d attribute
ebLt:gGo Tag标签的属性名
Kr`.q:0GK mS.!lkV 以下章节介绍对于不同类型的tag,如何具体地实现它们。
rLbFaLeQ wkp$/IZKMj $?9u;+jIR 简单的tag
)=5*iWe `:2np{ 1yeD-M"w tag处理类
J3'0^JP* S<5.}c R 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
mn(MgJKQ\ QRF:6bAxsL 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
@?</8;%3W C*Qx GT3}'`f B public SimpleTag extends TagSupport
[7[$P.MS{ >f;oY9 {m {
UM'JK#P" [mF=<G" public int doStartTag() throws JspException
}(WUZ^L buHUBn[3) {
YP{mzGdE&