标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
\e=_
2^v!_ i>L+gLW 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
3gWvmep1 g3n'aD@'x 在这篇文章中,我们主要讨论:
|LG4=j.l -Lu)'+ · 什么是自定义tag标签?
/StTb, uf<@ruN · 怎么使用tag标签?
0Q,g7K<d DDT_kK; o 声明要使用的tag库
zIC;7 5# zQ?!f#f o 找到与之对应的tag处理类
+i ?S M$4k; o tag标签的类型
S0h'50WteJ d4:`@* · 自定义tag标签
0<"k8
k@J J2q,7wI# o tag处理类
:Eh\NOc_O yw[ # o tag库描述
JTqDr L$'[5"ma
; o tag标签示例
pA.J@,>`}
3P~o"a> o 带属性的tag
682Z}"I0 I4;A8I o 带body的tag
Mwb/jTp @WH@^u o 定义了脚本变量的tag
'K@|3R /[:dp< o 具有协作关系的tag
5Dp#u nMDxH$O · 自定义tag标签
r`&-9"+ YzosZ! L!< o 一个迭代tag的例子
rqv))Zo` ^Jb
H? o 一个模板tag库
=/<LSeLxH 5tJ,7Y' o tag处理类到底是怎样被调用的?
mOo`ZcTU }nt*
[:% f~E*Zz`; 什么是自定义的tag?
_0+0#! J! ,Vd\m"K{ 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
&aM7T_h8 8eA+d5k\. 自定义tag标签有很多特色,诸如:
Vz14j_ %1pYEHn · 可以在JSP页面中自定义tag标签的属性
"~UUx"Y -(#I3h;I · 访问JSP页面中的所有对象
EM>}0V %h1N3\y9i( · 可以动态地修改页面输出
I%|>2}-_U Li*eGlId · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
bo.(zAz Y`+=p@2O2o · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
e \O/H< '=][J_ ~['Kgh_; 使用tag标签
Pxn,Qw* V"cKJ;s Kn+S, 1r 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
"CiTa>x ]weoTn: 要使用tag标签,JSP程序员必须做2件事:
4|A>b})H -}K<ni6 · 声明此tag标签的tag库
9&<x17' B|o2K}%f · 实现此tag标签
iy""(c keRE==(D 声明tag标签所在的tag库
$ d?.2Kg j*xV!DqC 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
d1[ZHio2c? z;@*r}H <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
q7u'_R,; O-)-YVU uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
Y^<bl2"y8 0'nikLaKy TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
Ov<NsNX] V|\7')Qq 以下taglib指示符直接引用一个TLD:
$XoQ]}"O 4Qn$9D+? <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
$1SUU F\. B=|cS;bM$3 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
J90v!p- >:lnt /N3 <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
nB .G vTn}*d.K= 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
qe5feky \6\<~UX^ <taglib>
y(
y8+ZT 4*$G & TX <taglib-uri>/tutorial-template</taglib-uri>
4[N^>qt = j&k6O1_ <taglib-location>
jlxpt)0i K(aJi,e> /WEB-INF/tutorial-template.tld
yr,=.?C- NIw\}[-Z0E </taglib-location>
B5$kHM%p Kv~U6_=1O </taglib>
!F?XLekTi
ge8/``= iQ"XLrpl 实现此tag标签
)vxUT{;sH Dwzg/F( c%qv9 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
Tgl} 7x<i :x3 }1r m tag标签类型
[<KM?\"1< A%^ILyU6c nl9P,
d 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
yxc=Z0~1 M>/Zbnq <tt:tag>
Lco&Fp YX#-nyK body
."Y
e\>k D$x_o!JT </tt:tag>
(IPY^>h PsZ
>P|e1 |n] d34E 一个不带body的tag标签如下:
FJd]D[h qcT'nZ:
<tt:tag />
,#8e_3Z$ n..g~$k ^urDoB: 简单的tag标签
Q1z;/A$Al C$5[X7' 一个没有body和属性的tag标签如下:
%!1Q P[}K QeK*j/ <tt:simple />
@62Mk},9 c l(Q?rwI8Y KSrx[q 带属性的tag标签
?y!E-& $r3i2N-I F_4n^@M 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
^k\e8F/ p
l&Muv 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
]EpWSs!"g x|5k<CiA <loglic:present parameter = “Clear”>
b4pm_Um =ha{Ziryo 而另一个标签logic:iterate是用表达式来给属性赋值:
&:7ZQ1 k%G1i-]4 <logci:iterate collection=”<%= bookDB.getBooks() %>”
'R:"5d .AU)*7Gh id=”book” type=”database.BookDetails”>
Z@$8I{}G B9J&=6`) PV=5UyjW 带body的tag标签
qQH]`#P ,#kIr 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
tmtT( jNC4_q& 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
2TA*m{\Hr )[|3ZP` <logic:present parameter=”Clear”>
"%x<ttLl j ku}QM^ <% cart.clear(); %>
9,"L^W8"k j+
LawW- <font color=”#ff0000” size=”+2”><strong>
Dv/WE>?Aw aT$9; 你选择了清除购物车!
'uxX5k/D@t J":,Vd!*- </strong></font>
~7Tc$
"I qhz]Wm P </logic:present>
dB5b@9* d:U9pC$ [ra_ 2R 到底是用属性还是用body来传递信息?
#*(td<Cp L~NbdaO 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
n= u&uqA* 6Avw-}.7> ;{"+g)u 定义脚本变量的tag标签
!!? Mw Z7?~S2{c 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
6 jn3`D 5)MS~ii <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
KSNPkd6 9*1,!%] <% tx.begin(); %>
Ch3jxgQY 7!JQB ...
D'Y-6W3 &E=>Hj(dTG $
.
9V& 具有协作关系的tag标签
vsl]92xI H,u<|UMM_ 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
t?'!$6 ssN6M./6 <tt:tag1 attr1=”obj1” value1=”value” />
tyqT %Va!\# <tt:tag2 attr1=”obj1” />
7w6cwHrL@ Evjj"h&0J 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
J:zU,IIJ Q{5kxw1ZF <tt:outerTag>
3skC$mpJHw ,~]tg77 <tt:innerTag />
%s(k_|G+4 "pRtczxOgR </tt:outerTag>
S-|)QGxV6 ,^ . 88< k+ty>bP= Tag处理类
D,k"PaLP Y/ .Z.FD` Us0EG\Y Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
Z
Z:}AQ ^8AXxE 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
OD6\Mr2= sv&;Y\2c 下表说明不同类型的tag所需要不同的处理过程:
B2'i7Ps h*u Tag处理类的方法
tE`u(B, #T=LR@y Tag标签类型
+w{*Xk)4 所调用的方法
\S!e![L/ Nbi.\ 基本标签
k@3Q|na doStartTag, doEndTag, release
283F)T\Rv 2vWx)Drb6 带属性的标签
.Lsavpo doStartTag, doEndTag, set/getAttribute1...N, release
}%_ b$ \}"$ ?d'f 带内容的标签
~U@;gLoD doStartTag, doEndTag, release
n4R(.N00 O#S;q5L@ 带内容的标签,且内容重复循环
Pn>Xbe doStartTag, doAfterBody, doEndTag, release
)]H-BIuGm r'HtZo$^R 带内容的标签,且内容与JSP交互
G#u6Am)T doStartTag, doEndTag, release, doInitBody, doAfterBody, release
HV{wI1 m0;CH/D0 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
P;ci9vk +
|#O@k 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
*&^:T~|=! \Ani}qQ%| 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
|m^k_d!d G2Qlt@.T xgKdMW'%g: Tag库描述(简称TLD)
rzm:Yx noml8o x"gd8j]s Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
@W[f1 zGAq-< TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
KmA;HiH%J PE3vQH=t~ 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
]dGw2y pxCK;] <?xml version="1.0" encoding="ISO-8859-1" ?>
uF9C-H@: pu
7{a <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+RYls|f TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
0 Tx{3# o4K ~ Of[XKFn_ <taglib>的子元素
O$&mFL[` |yQZt/*SOZ Element
i*Sqd a
$ Description
T>2[=J8U :7!0OVQla\ tlib-version
DVB{2~7 4 Tag库的版本
$m].8? Py@wJEo jsp-version
}%'?p<^M Tag库所需要的jsp的版本
2\jPv`Ia g1W.mAA3B short-name
-bT)]gA2 助记符,tag的一个别名(可选)
]+XYEv ifUGY[ L uri
Z{ X|6. 用于确定一个唯一的tag库
jB$IyQ;@ tG9BfGF display-name
<UV1!2nv* 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
E[@ u
3i8 $RIecv<e_ small-icon
t\{'F7 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
t>urc :U3kW8;UMP large-icon
qln3 k` 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
p?);eJtV/ %_RQx2 description
D#il* 对tag库的描述(可选)
/H(?
2IHC cDFO; Dr listener
si`A:14R 参见下面listener元素
52 fA/sx Crho=RJPR tag
%|g>%D3Z? 参见下面tag 元素
-QM:
q #h8Sq~0 Listener元素
zF8dKFE~ )z73-M V" 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
q Gw -tPD<
gX]-\ Tag元素
njScz"L~ Q<^Tl(`/N? 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
nrxo&9[@n 0=* 8
每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
Ma.`A [E!oQVY Tag元素的子元素
aE&,]'6 \?0&0;5 元素名称
Tx|Ir+f6L 描述
E.7 e;Ti&o} name
!`g~F\l 独一无二的元素名
-@yh>8v [ sN EHf tag-class
(@<lRA
^ Tag标签对应的tag处理类
4)h]MOZ )Dw,q~xgg0 tei-class
!}v=N";c javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
p^%YBY#,H
FT#8L body-content
u37'~&o{U Tag标签body的类型
4C<jdv_J JJ}0gZ display-name
M=FxB;v 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
&x[E;P*Fg }!"A! ~& small-icon
P&9Gga^I 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
v 1z M)'HCnvs' large-icon
)6,de2Pb 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
yj;sSRT kzn5M&f> description
Vr6@>@SC 此tag标签的描述
S1p;nK Xu<k3oD7 variable
xy5lE+E_U 提供脚本变量的信息(同tei-class)(可选)
,&jhlZ i a`&f attribute
{ /K.3 Tag标签的属性名
WN{ 9 cik!GA 以下章节介绍对于不同类型的tag,如何具体地实现它们。
"!Uqcay- @wpN6 / q qpgy7 简单的tag
;>
_$` BSYzC9h` [Sr,h0h6 tag处理类
TH; R ??PC
k1X 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
T&%ux=Jt QrB@cK] 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
YP.5fq: r"``QmM %X4xv_o`f public SimpleTag extends TagSupport
WF1px % .z)%)PVV {
0Sle
q*\x0"mS/ public int doStartTag() throws JspException
mQCeo}7N5 CN#+U,NZV {
QW$G oFy=-p+C try{
`tHvD=`m.
i`QKH pageContext.getOut().print(“Hello.”);
|zQ4u P;P%n }catch(Exception e){
g .onTFwN 0'V5/W throw new JspTagException(“SimpleTag: “ + e.getMessage());
)2V: eoai(&o0$ }
W=#:.Xj[ !n*
+(lZ return SKIP_BODY;
9Wnn'T@Tl \R|4( +]x }
HG+%HUO$ ]bj&bk# public int doEndTag()
.q
`Hjmg< Xe<sJ.&Wf {
]$Yvj!K*Q Fs{x(_LOr return EVAL_PAGE;
q;<h[b? ~i~7na| }
E=e*VEjy l^|UCgRn }
Sz^
veh? @\|_ >#hO).`C 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
V n* 7NDr1Z#B6V <body-content>empty</body-content>
` D= S{
S/D^ R]OpQ[k 带属性的tag标签