标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
{7o3wxsS [Fl_R[o 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
|J-X3`^\H .9bi%=hP 在这篇文章中,我们主要讨论:
V&*IZt& ,8e'<y · 什么是自定义tag标签?
.PB!1C.}@ iXDG-_K · 怎么使用tag标签?
9{u= F7DA~G! o 声明要使用的tag库
=I# pXL YnEyL2SuU o 找到与之对应的tag处理类
(/A.,8Ad I0m7;M7 P o tag标签的类型
Gyq 6? K!6T8^JH · 自定义tag标签
hY`<J]-'` ]3LLlXtK[ o tag处理类
5T x4u%g q`9.@u@ a o tag库描述
^&qK\m_A ,b*?7R o tag标签示例
ciblj?"Wi |p:4s"NT o 带属性的tag
Db|f"3rq? $e\s8$EO o 带body的tag
sY;h~a0n riIubX# o 定义了脚本变量的tag
0~U#DTx0 Ui'v'
$ o 具有协作关系的tag
t]h_w7!U #Zdh<. · 自定义tag标签
o%_-u
+ mkSu
$c o 一个迭代tag的例子
A(2 0+ 90vWqL! o 一个模板tag库
ZFtx&vrP T8S&9BM7 o tag处理类到底是怎样被调用的?
1aAOT6h Qc7*p]E& [+\He/M6 什么是自定义的tag?
2j-l<!s 2u]G]:ml 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
Wd'}YbC vFUp$[ 自定义tag标签有很多特色,诸如:
jj{:=lZB p/{%%30ke · 可以在JSP页面中自定义tag标签的属性
{8m&Z36E Qw0k-t0=4 · 访问JSP页面中的所有对象
1S?~c25=h *y4DK6OFe · 可以动态地修改页面输出
`y>m
>j u`XRgtI{g? · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
[j6]!p]S$ V D#q\ · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
n*\o. :f A|"T8KSMB F@<cp ?dR 使用tag标签
zZMKgFR@ (dg,w*t' <WUgH6" 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
b$@I(.X: "09v6Tx 要使用tag标签,JSP程序员必须做2件事:
(-S^L'v62v <-1:o*8:} · 声明此tag标签的tag库
rZgu`5<a mZiKA-t · 实现此tag标签
ThV>gn5 fM.#FT?? 声明tag标签所在的tag库
XpANaqH\ oXZWg~&l^ 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
hJSvx .i;.5)shsu <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
Z66Xj-o 3HyOQD"{ uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
QvbH " 7 "}X+vd`` TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
vd%AV(]<LJ "nz\YQdg 以下taglib指示符直接引用一个TLD:
r5gqRh}+ F > rr. <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
~7b#BXzP .5\@G b.8 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
X+Sqw5rH (VO'Kd <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
Ar)EbGId |Ua);B ~F 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
@;O"-7Kk ?GX@&_ <taglib>
b}(c'W*z% ;gL{*gR]S <taglib-uri>/tutorial-template</taglib-uri>
f}yRTR GJv @G;9eh0$ <taglib-location>
ZY<RNwu jTS8
qu /WEB-INF/tutorial-template.tld
L]l/w |dxWO </taglib-location>
?n#$y@U #e.x]v: </taglib>
E,d<F{=8,o 29=ob(" Fug4u?-n 实现此tag标签
X0L\Ewm uG -+&MU? '9QEG/v 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
%e[E@H 7 B9,39rG/7+ jwjLxt tag标签类型
fTpG>*{p 1Xi>&;], sSh." H 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
=oVC*b a(~X <tt:tag>
$%$zZJ@/ ;39b.v\^ body
0xZ^ f}@L ^P{y^@XI </tt:tag>
ZklO9Ox( |*48J1:1y *04}84?: 一个不带body的tag标签如下:
;o'>`=Y K bQXH!J <tt:tag />
"'t f]s ,|z@Dy 7(D)U)9h 简单的tag标签
@_t=0Rc n;Mk\*Cg 一个没有body和属性的tag标签如下:
4"|3pMr X>
98` <tt:simple />
oAifM1*0 onmpMU7w aoz+T h3 带属性的tag标签
_<]0hC G(?1 Urxi `StuUa 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
bp/l~h.7W <r <{4\%} 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
p5qfv>E8) &_]G0~e <loglic:present parameter = “Clear”>
^>%.l'1/( #9s)f R 而另一个标签logic:iterate是用表达式来给属性赋值:
{Y/0BS2D i+5Qs-dHA <logci:iterate collection=”<%= bookDB.getBooks() %>”
`oe=K{aX //N="9)@ id=”book” type=”database.BookDetails”>
NA$)qX_ u`wD6&y* KC&XOI % 带body的tag标签
p*<I_QM! f6J]=9jU 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
/pkN=OBR tBkgn3w 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
FO>!T@0G =}tomN(F~[ <logic:present parameter=”Clear”>
(`slC~" =RXeN+
&R <% cart.clear(); %>
6|'7Mr~\ ;o)'dK <font color=”#ff0000” size=”+2”><strong>
x0)=jp '
OYxYlUq 你选择了清除购物车!
Jw=7eay$F &x B^ </strong></font>
g?|Z/eVJ R|}4H*N </logic:present>
SVZ@'X\[M F#yn'j8 Pc&dU1 到底是用属性还是用body来传递信息?
X]9<1[f lH?jqp 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
q {}5wM 3]'ab-,Vp t$,G%micj 定义脚本变量的tag标签
LmyaC2 Uc_}=" 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
g$2#TWW5 o"0~ <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
/Z]nV2$n)V I9L3Y@(f6m <% tx.begin(); %>
QKEtV T^MY w ...
wbOYtN Y@ !wUznyYwt IhK
SwT 具有协作关系的tag标签
h}'Hst Q=%W- 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
Lp"OXJ*es IO&U=-pn& <tt:tag1 attr1=”obj1” value1=”value” />
$?!]?{K ?7)v:$(G} <tt:tag2 attr1=”obj1” />
%Iflf]l "oiN8#Hf 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
_vb'3~'S ?fP3R':s <tt:outerTag>
qT$ IV\;_ yogL8V-^4 <tt:innerTag />
*w.":\P] 8a@k6OZ </tt:outerTag>
OY(CB(2N <K&A/Ue ^HR8.9^[1u Tag处理类
6/3E!8 &+(D< U %{IgY{X Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
#"c'eG0 rZ+4kf6S 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
e(0cz6 9[X'9*, 下表说明不同类型的tag所需要不同的处理过程:
KwMt@1Z Fhllqh) Tag处理类的方法
y@$E5sz l="X|t Tag标签类型
P5B,= K>r 所调用的方法
YC St X)r GPGPteC 基本标签
H-&27?s^ doStartTag, doEndTag, release
^Os }sJ*5S Qp[
Jw?a 带属性的标签
p),*4@2< doStartTag, doEndTag, set/getAttribute1...N, release
E0 VAhN3G\ u59l)8= 带内容的标签
{R63n doStartTag, doEndTag, release
8<0P Ssx P 0+@,kM 带内容的标签,且内容重复循环
<]%6x[ doStartTag, doAfterBody, doEndTag, release
%U}6(~
jK/FzD0- 带内容的标签,且内容与JSP交互
x
~)~v?>T doStartTag, doEndTag, release, doInitBody, doAfterBody, release
/>8A?+g9u "3]}V=L<5 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
\ ;]{` toDi70o 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
MC,Qv9m u/|@iWK: 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
b'SP,}s5" Kv1~,j6 f{L;, Tag库描述(简称TLD)
2`;XcY4A 1}c/l<d ~.G$0IJY Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
^{IZpT3 ;u(*&vRqr^ TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
T?[;ej: vOCaru?~h 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
mX.mX70|J Xl2g Hh <?xml version="1.0" encoding="ISO-8859-1" ?>
@}Ry7H0O |6?s?tC"u <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
xc@$z*w TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
d>I)_05t NTZ3Np` kq(><T <taglib>的子元素
F~E)w5?\O 1Zp/EYWa{ Element
E <j=5|0t Description
,0AS&xs$ [S]q'c) tlib-version
44~ReN}` Tag库的版本
EI?8/c ,)d`_AD+5 jsp-version
,KM%/;1Dm Tag库所需要的jsp的版本
` W);+s OMmfTlM% short-name
; \co{_&D 助记符,tag的一个别名(可选)
?-Of\fNu 6rmx{Bt uri
z<!A;.iD 用于确定一个唯一的tag库
r6Vw!^]8u8 ;aD~1;q display-name
\VIY[6sn\M 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
>{~xO 6H WdS1v% small-icon
wTR?8$ 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
h"8[1
; ND?"1/s large-icon
`%#_y67v 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
KLG .?`h: 2P'Vp7f6 Y description
:+QNN< 对tag库的描述(可选)
.j,xh )v" fk?!0M6d listener
X1}M_h% 参见下面listener元素
<W3p! 7z, $ tag
OA9P"* 参见下面tag 元素
$U7/w?gc' sVP\EF8PY Listener元素
gzVZPvTPE (O09HY: 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
N
GnE Oz_CEMcy Tag元素
3;}YW^oXq "#0P*3-c 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
RWM~7^JA yVn%Bz'
[ 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
=z9,=rR4
7|dm"%@ Tag元素的子元素
U,yZ.1V^: DH_~,tK9 元素名称
mM/#(Ghl 描述
_'V o3b # Dgkl name
yRyRH%p) 独一无二的元素名
7u^wO< bL0]Yuh tag-class
Citumc)E Tag标签对应的tag处理类
$X.F=Kv ?XyrG1(' tei-class
}lPWA/ javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
#<&@-D8 xZ2 1iQeN body-content
$?:IRgAr Tag标签body的类型
d@*dbECG +N,Fq/x display-name
RDQ]_wsyKG 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
zn= pm#L t W small-icon
s2N'Ip 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
q2*)e/}H ]!P6Z? large-icon
Qz{Vl>" 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
BSSehe* a8[%-eW, description
n 78!]O 此tag标签的描述
(kK8
Ox fF *Z.{1 variable
Mx93D
提供脚本变量的信息(同tei-class)(可选)
dXY}B=C P*?2+. attribute
r
SoT]6/ Tag标签的属性名
x?0(K=h, {nA+-=T 以下章节介绍对于不同类型的tag,如何具体地实现它们。
~KGE(o4p "k [$euV Wx;%W"a 简单的tag
fIx|0,D&7L O7Jp; =r`E%P: tag处理类
Eqny'44 %(?;` 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
vft7-|8T &];W#9"Z 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
n.5M6i/~a *}(B"FSO r_']; public SimpleTag extends TagSupport
!.@:t`w 4^Ks!S>K{8 {
BUh(pS: G6Wa0Z public int doStartTag() throws JspException
g;o5m}
TK>~)hc} {
cqZlpm$c 7I(QTc)* try{
c(3idO*R) 2"Unk\Y pageContext.getOut().print(“Hello.”);
jgpF+V-n$ .bh7 }catch(Exception e){
UY.o,I>s Gh{9nM_\" throw new JspTagException(“SimpleTag: “ + e.getMessage());
?5pZp~ I7f:T N }
#f=41d% 0!:%Ge_ return SKIP_BODY;
~^ ' + . 5V0#_!QAN }
` -f\6r|:) @WKJ7pt`'N public int doEndTag()
!,7)ZW?*8 r:U<cLT[9 {
l0',B*og \Y:zg3q* return EVAL_PAGE;
] TZ/=Id (h@~0S }
*a(GG G-o6~"J\ }
G&6`?1k /W}"/W9 K7q R 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
6k37RpgH *'n=LB8R <body-content>empty</body-content>
{ueDwnZ rXGaav9 FB~IO#E8W 带属性的tag标签