标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
w+vYD2a pf.T{/% 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
F*WWv&\X 22?9KZ`Z= 在这篇文章中,我们主要讨论:
]1] 7QiJ1P.z · 什么是自定义tag标签?
C 3`2{1 >c~~i-= · 怎么使用tag标签?
64s9Dy@%F 7Kx3G{5ja o 声明要使用的tag库
5utMZ>%w_# o5+N_5OE}E o 找到与之对应的tag处理类
dy u brIG D]+tr% o tag标签的类型
7`3he8@ze 8;3T65KY · 自定义tag标签
z41
p$ ;F@dN,Y o tag处理类
x9PEYhL? [!>2[bbl o tag库描述
;(3fr0cr: hB:R8Y^?H o tag标签示例
DvnK_Q! WU1I>i o 带属性的tag
Py 8o8* H 6USet`# o 带body的tag
%j=E}J<H5* LV=!nF0 o 定义了脚本变量的tag
-W>zON|l hIa@JEIt o 具有协作关系的tag
<PkDfMx2 ?Gr<9e2Eo · 自定义tag标签
|::kC3= aisX56Lc o 一个迭代tag的例子
NWB/N* }/G~"&N[ o 一个模板tag库
C<A82u;t%@ nLkC-+$tM o tag处理类到底是怎样被调用的?
WT(R =bLw e*vSGT$KgL ~I/7{B|yX 什么是自定义的tag?
_p{ag
1gP {U=za1Ga 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
iZ[o2Tre >'^l>FPc 自定义tag标签有很多特色,诸如:
I_xJ[ALdm /S9Mu
)1Y · 可以在JSP页面中自定义tag标签的属性
N|q:wyS| ?MeP<5\A · 访问JSP页面中的所有对象
ik~hL/JD\ UR-e'Z&] · 可以动态地修改页面输出
n*D)RiW pM[UC{ · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
4$.UVW\ :[(X!eP · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
C bG"8F|4 (B]Vw+/ ~"EkX 使用tag标签
& A9psc(,& #=t:xEz Q+ G=f 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
sut j
G`m )X\3bPDJR 要使用tag标签,JSP程序员必须做2件事:
/[nt=#+
U$VTk · 声明此tag标签的tag库
|#5JI#,vX scL7PxJ5 · 实现此tag标签
!9iVe7V Jc9SHCJ 声明tag标签所在的tag库
(U/[i.r5Cj >1s:F5u" 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
RWTv,pLK oF
V9t{~j <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
g;]2'Rj lu-VBVwR uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
r(vk2Qy AH=6xtS- TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
;5y4v a3Es7R+S 以下taglib指示符直接引用一个TLD:
pJ_Z[}d)c .M:,pw"S] <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
;p\rgam i8HSYA 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
WlZ[9,:p1 GUat~[lUrj <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
m
U7Ad" >wcsJ{I 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
l`$f@'k by6E
"7% <taglib>
<;9vwSH> +~FH'DsT <taglib-uri>/tutorial-template</taglib-uri>
|k
4+I uc7np]Z <taglib-location>
(2qo9j"j/Y e4CG=K3s /WEB-INF/tutorial-template.tld
j?z(fs-
` S85i* </taglib-location>
)J#@L* I8^z\ef& </taglib>
l@#X]3h! 4\sS f "Iv 实现此tag标签
9MM4 C 6dq U4 e`}|*^- 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
ol`]6"Sc h r6f}2 Za}91z" tag标签类型
yxA0#6so HM[BFF[;/ %8{' XJ! 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
TR)'I QT%&vq <tt:tag>
$ /wr? O Zt 'ovY body
/[EI0~P [BV{=;iD </tt:tag>
R~Xl(O pbm4C0W} mbS
&> 一个不带body的tag标签如下:
T
86}^=-5 f$WO{J <tt:tag />
4a)qn?<z RPp_L>&~< S%%>&^5 简单的tag标签
I|R9@ 8:M~m]Z+| 一个没有body和属性的tag标签如下:
oN _%oc s` S<BX7 <tt:simple />
m&ZdtB| <,cD EN7 Qgf_ 带属性的tag标签
VJ1`& 5Vvy:<.la DDkOg] 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
{ZfTUt)-P e dD(s5 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
o}% /D~
,X48+ <loglic:present parameter = “Clear”>
i,bFe&7J jliKMd<? 而另一个标签logic:iterate是用表达式来给属性赋值:
e@Mm4&f[p 9'4cqR <logci:iterate collection=”<%= bookDB.getBooks() %>”
fk",YtS* ]q?<fEG2< id=”book” type=”database.BookDetails”>
TkQ05'Qc zR`]8E] LTa9'
q0 带body的tag标签
0q62 {p7 beIEy(rA 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
LL,~&5{ ;CU3CLn 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
% l5J 52%.^/ <logic:present parameter=”Clear”>
;#j/F]xG '{Ywb@Bc <% cart.clear(); %>
8"S0E(,mu m*a0V <font color=”#ff0000” size=”+2”><strong>
lR-4"/1|y n
~
=]/ 你选择了清除购物车!
u|w[b9^r ?. ~@ lE </strong></font>
_ :][{W# L:%h]- </logic:present>
OY@/18D<> [(dAv7YbN WS,p}:yPZG 到底是用属性还是用body来传递信息?
"2Ye\#BU6 duwZe+ 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
F!Nx^M1 A).wjd(_, ;,IGO7R 定义脚本变量的tag标签
&d~6MSk $aVcWz% 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
pRYt.}/K 1g|H8CA <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
r?[Zf2& ,NVQ C= <% tx.begin(); %>
E7 7Au;TL YgVZq\AV" ...
(s\Nm_j o{ U=
f6 tF=96u_X 具有协作关系的tag标签
h],_1!0 :@n e29,} 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
|~uCLf> RJSNniYr7 <tt:tag1 attr1=”obj1” value1=”value” />
L]9*^al 9v/1>rziE <tt:tag2 attr1=”obj1” />
$@DXS~UQA 'Z;R!@Dm 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
@mw1(J jgukW7H <tt:outerTag>
i5:fn@& t&-7AjS5 <tt:innerTag />
m}8c.OJ>K` LnM+,cBz </tt:outerTag>
O~igwFe M|e@N zi<C5E` Tag处理类
ga!t:O@w \GBv@ Q?Q!D+~mND Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
Xo$(zGb +AXui|mn 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
6$`8y,TMSt lKwI lp 下表说明不同类型的tag所需要不同的处理过程:
91[(K'=& z,$^|'pP Tag处理类的方法
\iO
,y: _PQQ&e)E Tag标签类型
dTS7l02 所调用的方法
02?y% 'BtvT[KM 基本标签
wR\%tumk doStartTag, doEndTag, release
kOeW,:&65 /2WGo- 带属性的标签
F d *p3a doStartTag, doEndTag, set/getAttribute1...N, release
U%m,:b6V ;5dJ5_ } 带内容的标签
?3"lI,!0 doStartTag, doEndTag, release
+>Y2luR1 T[q2quXgk 带内容的标签,且内容重复循环
kwWDGA?zFB doStartTag, doAfterBody, doEndTag, release
#8rLB( eY;XF.mF 带内容的标签,且内容与JSP交互
Jro) doStartTag, doEndTag, release, doInitBody, doAfterBody, release
8+^q9rLii 2I>X]r.S!1 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
(jtrQob 1Sx2c 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
Jf9a<[CcV xrf z-"n4 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
&r doMc;
/Rf:Z.L V*}ft@GPD Tag库描述(简称TLD)
u{o3 0EKi?vP@y7 MA6(VII Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
\0).
ODA( /R!:l l2 TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
lvY[E9I0 yX0nyhq 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
Vo"Wr>F kZ>_m&g <?xml version="1.0" encoding="ISO-8859-1" ?>
B/0Xqyu `-/-(v+ i <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
3 f@@|vZF TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
kNR -eG i}[cq_wJ x+EkL3{ <taglib>的子元素
L
4V,y> kUGOkSP8[ Element
C3)*Mn3%P Description
[;t-XC?[nk ?I{L^j^#4 tlib-version
3:C)1q Tag库的版本
vJ9I z {bHUZen
jsp-version
t-B5,,` Tag库所需要的jsp的版本
``4e& Swa0TiT( short-name
& %A&&XT9 助记符,tag的一个别名(可选)
oq${}n < cD6S;PSg uri
_t&`T 用于确定一个唯一的tag库
)Fon;/p {ppzg`G\ display-name
,.9k)\/V 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
/9ctmW1!< R!f<6l8#W small-icon
;`Nh@*_ 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
HxSq&j*F ,2YZB*6h{ large-icon
=' uePM") 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
>Q$ph= P9`R~HO'` description
d|?Xo\+ 对tag库的描述(可选)
;3x*pjLG:Q p<1y$=zS listener
wg%g(FO 参见下面listener元素
i/j53towe k/P.[5 tag
TyDh\f!w 参见下面tag 元素
>)F "lR:o XeX\u3<D Listener元素
m/z,MT74*J hw$!LTB2 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
%UAF~2]g 2ah%,o Tag元素
^/_Yk.w #u}%r{T 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
N=AHS pO_IUkt 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
#x;,RPw5 >H^#!eaqw Tag元素的子元素
~)^'5^ ],_+J* 元素名称
K+pVRDRcs 描述
+D@5zq:5 ;$WHTO( name
D|)a7_ 独一无二的元素名
8[;vC$ w
lH\w? tag-class
~:{05W Tag标签对应的tag处理类
Y=p!xr> D"rbQXR7$ tei-class
2]1u0-M5L javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
!!A0K"h |GtvgvO, body-content
_Ao$)Gu) Tag标签body的类型
>!6|yk`GJ O&1qL) display-name
J91[w?, 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
=e4 r=I Keozn*fzI small-icon
?u|@,tQ[ 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
;xZjt4M1 } vmRm*8z large-icon
@^xtxtjzux 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
>~SS^I0 W7^[W. description
4b:|>Z- 此tag标签的描述
;%9]G|*{ CmZayV variable
Pg%9hejf3 提供脚本变量的信息(同tei-class)(可选)
Lm
TFvZ =j62tDS attribute
Gq^vto Tag标签的属性名
L-T,[;bl b,Oh8O;> 以下章节介绍对于不同类型的tag,如何具体地实现它们。
P.}d@qD{) >>
zd LWyr 简单的tag
hW~.F _dJ(h6%3 |;vQ"8J tag处理类
m[^lu1\wn q.c)>=!. 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
W6&vyOc );$99t 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
){*+s RBW z3Q&O$5\ Ax;=Zh<DAv public SimpleTag extends TagSupport
$-iEcxsi T#))_aC {
2;8m0+tl %{@Q7 public int doStartTag() throws JspException
!y= R)k [d: u( {
p49]{2GXb /|IPBU 5 try{
y0%1YY FEaT}/h; pageContext.getOut().print(“Hello.”);
']r8q % !sb r!Qt }catch(Exception e){
mQj=-\p {KG 6#/%; throw new JspTagException(“SimpleTag: “ + e.getMessage());
aQCu3T uM-,}7f7 }
]:P7}Kpb
.Q{RTp return SKIP_BODY;
n0xGIq qqrjI. }
7?$?Yu ^"WVE[" public int doEndTag()
M|WBJ'#x0 @^P^-B {
2cR[~\_9. qt@L&v}~j return EVAL_PAGE;
P {TJ$ tyu@aCK }
(W
~K1] i%hCV o }
!@xO]Jwv l":W@R tt"<1
z@ 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
~r1pO#r- >f(?Mxh2 <body-content>empty</body-content>
M]x>u@JH ?=VvFfv% Xz$4cI#n: 带属性的tag标签