标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
b/=>'2f WVL\|y728s 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
u 0 K1n_ ;ZZmX]kz,M 在这篇文章中,我们主要讨论:
S'sI[?\x ZXWm?9uw · 什么是自定义tag标签?
o1Wf#Zq G:MQ_tfr& · 怎么使用tag标签?
'gk^NAG2^E H]Gj$P=k o 声明要使用的tag库
hud'@O"R+ @t8{pb;v o 找到与之对应的tag处理类
o^BX:\} Vb~;"WABo o tag标签的类型
VO*fC yIS&ZtBA · 自定义tag标签
ab<7jfFIa 77G4E ,] o tag处理类
~@iYP/=/Q =Flr05}m o tag库描述
#YLI"/Kn x}N1Wl=8g o tag标签示例
&)EL%o5 U[!wu]HMF o 带属性的tag
Zg >!5{T ]tEH `Kl o 带body的tag
o(xt%'L`t W1UqvaR o 定义了脚本变量的tag
N3Z6o.k (m=F o 具有协作关系的tag
BCr*GtR)W "3NE%1T · 自定义tag标签
$H7T|`WI., a3BlydSlf o 一个迭代tag的例子
vLM-v wpm $?X o 一个模板tag库
4[K6 ZDBU 5VlF\- o tag处理类到底是怎样被调用的?
DQ_ pLXCC ~"vRH p,#**g: 什么是自定义的tag?
2iWxx:e Z`@< O% 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
Pv3 e*I(( -O[9{`i] 自定义tag标签有很多特色,诸如:
W;
?' y1Yrf,E
m= · 可以在JSP页面中自定义tag标签的属性
h/#s\>)T IQ9Rvnna · 访问JSP页面中的所有对象
==~
lc; .BZ3>]F3< · 可以动态地修改页面输出
Uj~
:|?Wz Iy{&T#e" · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
BoPJ;6?>} mRY~)<!4& · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
n)>nfnh 4> (OM|X=9 5> =Ia@I
使用tag标签
n0=[N'Tw3 j;i7.B"[ 0'^zIL#. 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
V?Ye^-29 }9(:W </} 要使用tag标签,JSP程序员必须做2件事:
4031~A8 mybjcsV4
· 声明此tag标签的tag库
Vu1X@@z wqf^n-Ze · 实现此tag标签
Q
1e hW Kj*:G!r0.: 声明tag标签所在的tag库
0p ZX _L' _cXLQ)- 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
`n~bDG> 8w4cqr4m <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
8{J{)gF G+f@m, uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
VtC1TZ3-7 Y,C3E>}Dq TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
!l1ycQM L\H,cimN 以下taglib指示符直接引用一个TLD:
EX^j^#N @K.[;-;g <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
0p'=Vel{} bcZ s+FOPd 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
0=Z_5.T> D<*#. > <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
66l$}+|Zzc xk8P4`;d$ 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
2x&mJ}o#k vFGFFA/K}N <taglib>
'Ijjk`d&c
!&OybjQ <taglib-uri>/tutorial-template</taglib-uri>
dD0:K3@ ~T<o?98 <taglib-location>
y%x2 {(!j6|jK /WEB-INF/tutorial-template.tld
F;^GhiQVS Wo+'j $k </taglib-location>
5//.q;z 2Aq%;=+* </taglib>
X"qC&oZmf 7'9~Kx&+ Iz<}>J B 实现此tag标签
IT_Fs|$ 5%n
W{2(fb 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
Q>}*l|Ci I`e|[k2 J 4E G tag标签类型
+iYy^oXxw %}asw/WiUa {qHf%y&[ 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
&jHnM^nQ F&om^G'U <tt:tag>
Jr4^@]78o< p%v+\T2r body
RvT>{G~ sOBy)vq?\ </tt:tag>
(PmaVwF 3G7Qo OK}+:Y 一个不带body的tag标签如下:
y84=Q )q48cQ <tt:tag />
,U#$Qb 12 w1+xlM,,9 lJloa'%v9 简单的tag标签
iCYo?> .?YLD+\A 一个没有body和属性的tag标签如下:
[9E<z2H s5TPecd <tt:simple />
?Rj)x%fN BtN@P23>k. )wROPA\uA 带属性的tag标签
> ^b6\ gUoTOA, 4M&6q(389 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
wtDy-H n C1@6r%YD 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
<-:gaA`KM |3?q L <loglic:present parameter = “Clear”>
a0oM KGW: 'K=n}}&: 而另一个标签logic:iterate是用表达式来给属性赋值:
(bk~,n_ TrHz(no <logci:iterate collection=”<%= bookDB.getBooks() %>”
=*aun& #lM :BO id=”book” type=”database.BookDetails”>
>d&_e[j jMvWS71 B|-E3v:f4 带body的tag标签
h<50jnH! A7!=`yA$ 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
W`KRaL0^ j`Xe0U< 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
R&BbXSIDX ZS@Cd9* <logic:present parameter=”Clear”>
ptXLWv` 0\*6UH <% cart.clear(); %>
E5P?(5Nv ugtb`d{ Sl <font color=”#ff0000” size=”+2”><strong>
]C =+ i6p0(OS&D 你选择了清除购物车!
-o\r]24 FL+^r6DQ </strong></font>
.FS`Fh; :66xrw </logic:present>
_
FcfNF I|?zSFa X#$mBRK7 到底是用属性还是用body来传递信息?
_N 5$>2 C%8jWc 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
?\C7.of #TLqo(/ C< GS._V& 定义脚本变量的tag标签
821@qr|`e mJaWzR 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
}];8v+M M~Yho". <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
o:<gJzg Jb'M/iG <% tx.begin(); %>
`CP}1W> z}vgp\cuT ...
_h4{Sx ]~:9b[G2 :?VM1!~ga 具有协作关系的tag标签
E4^zW_|xE oe$Y=` 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
$2=-Q/lM Nb2]}; O <tt:tag1 attr1=”obj1” value1=”value” />
lS.*/u*5 <!#6c :(Q <tt:tag2 attr1=”obj1” />
=IH z@CU ho#]i$b}f2 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
MXWCYi -z]v"gF?Px <tt:outerTag>
o7N3:) [:geDk9O#' <tt:innerTag />
Tti]H9g_ Cf'O*RFD </tt:outerTag>
=FkU:q$ je6H}eWTC6 vDgf} Tag处理类
.`z](s &[*F!=%8 z\Vu`Yz Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
tH0=ysf `}/&}Sp 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
VY)!bjW. n22k<@y 下表说明不同类型的tag所需要不同的处理过程:
KS($S(Fi w,(e,8#: Tag处理类的方法
)K2,h5zU J>(I"K% Tag标签类型
<S'5`-& 所调用的方法
EGYYSoBLU LOf0_g/ 基本标签
fS50 doStartTag, doEndTag, release
9ZjSM,+ `<>Emc8Z 带属性的标签
u|l]8T9L doStartTag, doEndTag, set/getAttribute1...N, release
kYw k'\s !ydJ{\; 带内容的标签
HE911 lc: doStartTag, doEndTag, release
}~Z1C0t 5I,5da 带内容的标签,且内容重复循环
Np>[mNmga doStartTag, doAfterBody, doEndTag, release
RkVU^N" dALJlRo" 带内容的标签,且内容与JSP交互
ZOGH.` doStartTag, doEndTag, release, doInitBody, doAfterBody, release
[m7^Euury LJK<Xen 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
ngM>Tzirt W)I)QinOH 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
x/Pi#X m 1df}gG 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
+$Q33@F5l E5.3wOE LyM" Tag库描述(简称TLD)
hC@oyC(4 L
M $Yh7N5XH, Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
OHixOI$O 5bZf$$b TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
#gbJ$1s ` z<k7ig 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
o*7`r ~ Zf~Em'g"3 <?xml version="1.0" encoding="ISO-8859-1" ?>
_idTsd:\ eC:?j`H- <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
FBpf_=(_1 TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
Nq|b$S [4 6T>e~<^ f8u m.Xnp6 <taglib>的子元素
PzThVeJ+ a= *&OW Element
#% PnZ
/ Description
J1kG'cH05 )8Defuxk tlib-version
+~lZ]a7k Tag库的版本
Y>*{(QD ?5d7J,"<h jsp-version
<`8l8cL Tag库所需要的jsp的版本
%;+Q0
e9 o@6:|X)7 short-name
i;!#:JX 助记符,tag的一个别名(可选)
7Pu.<b}
r=YprVX uri
q~9Y&>D 用于确定一个唯一的tag库
y'ULhDgq^B DDh$n?2fd display-name
QEIu}e6b 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
;C,D1_20Z g+Z~"O]$M small-icon
&Pu}"M$[MH 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
QGE)Xn#_bN :=u Ku'~ large-icon
5!Y51R^c 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
A<esMDX FV|/o%XqK description
|V#h
"s 对tag库的描述(可选)
Yhu
6QyRV 9l9h*Pgt listener
,Q~C
F;qe 参见下面listener元素
^i}*$ZC72 5(kRFb'31F tag
ajFSbi)l 参见下面tag 元素
:|i jCg+ umV5Y` Listener元素
S EdNH.|I bM`7>3
d7E 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
|,k,X}gP z.itVQs$I Tag元素
qE73M5L& 86(8p_&zC 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
-z%|
Jk wmu#@Hf/[h 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
o'S&YD 03aa>IO Tag元素的子元素
9
z_9yT Dg]( ?^ 元素名称
(~t/8!7N 描述
^|KX)g Y'6GY*dL name
z?V'1L1gM 独一无二的元素名
\yeo-uN8 h?H:r <
tag-class
G
@ib Tag标签对应的tag处理类
:G?6Hl)~) m}Z=m8 tei-class
>P*wK9|( javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
tm27J8wPzV 67zCil body-content
}$-;P=k Tag标签body的类型
T@c{5a @?,iy?BSG display-name
`8$gaA* 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
~x`BV+R afEhC0j small-icon
e-vwve 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
tjw4.L<r 9L+dN%C large-icon
&_cMbFLBP 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
\
UCOe (dl7+ description
Y>}[c
此tag标签的描述
(h;4irfX /$v0Rq9 variable
`4V_I%lJ& 提供脚本变量的信息(同tei-class)(可选)
$ K>.|\ Ph(bgQg attribute
% j4 Tag标签的属性名
v6B}ov[Y2 Qp9)Rc5 以下章节介绍对于不同类型的tag,如何具体地实现它们。
\OMWE/qMy +c@s
E:,V{&tLK 简单的tag
^^MVd@,i FSnF>3kj- WZkAlg7Z tag处理类
lFMQT
; 9/N=7<$ 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
Hk)IV"[R w#EP`aM2$= 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
|y+<|fb,a 'urn5[i =?Y%w%2 public SimpleTag extends TagSupport
CT1)tRN fhCMbq4T {
\bJ,8J1C 4,D$% . public int doStartTag() throws JspException
ZuV/!9qU e RiP C {
,A`.u \f(: 1+\ZLy!5: try{
04eE\%? saMv.;s
1^ pageContext.getOut().print(“Hello.”);
`Oxo@G*@}W ":t'}Eg=6 }catch(Exception e){
Sl@$ 1&_93 throw new JspTagException(“SimpleTag: “ + e.getMessage());
E3bS Q 35/)S@ }
x[]}Jf{t (+Ia:D return SKIP_BODY;
D@5Ud)_ ,dhSc<:LT }
i}C9 hq}kAv4B= public int doEndTag()
D,FX&{TYU p-d2HXo {
CF|c4oY 82 4{!7T return EVAL_PAGE;
-8;@NAUa r q2]u }
rdK=f<I] g8<Ja (J }
.QRa{l_) 7s#,.(s 5&}~W)"9 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
iwJeV J ^{L/) Xy5 <body-content>empty</body-content>
:xdl I`S [kfLT::mT >s3H_X3F 带属性的tag标签