标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
Pal=F0-Q\ j_AACq
{. 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
UVP vOtZj UfGkTwoo= 在这篇文章中,我们主要讨论:
29KiuP fex@,I&
· 什么是自定义tag标签?
f8~_E W4S,6( · 怎么使用tag标签?
<YY 14p >Ry01G]_/h o 声明要使用的tag库
*pq\MiD/ !a`&O-ye o 找到与之对应的tag处理类
N)T}P\l ]esC[r]PJ o tag标签的类型
^sw?gH* i@yC-))bY · 自定义tag标签
;+%rw 2Z,B ;TYBx24vD' o tag处理类
Dtk=[;"k2a Cye.gsCT o tag库描述
z_HdISy0 3w=J'(RU o tag标签示例
Vksuu@cch Hka2 o 带属性的tag
L,\Iasv \hXDO_U o 带body的tag
I,tud!p` {FkF o 定义了脚本变量的tag
&Jj<h: * /wp6KXm o 具有协作关系的tag
Y4-t7UlS; 'DR!9De · 自定义tag标签
-f .,tM= c)J%`i$ o 一个迭代tag的例子
;uJMG 7! Nsm o 一个模板tag库
Hs8>anVo[ &yg|t5o o tag处理类到底是怎样被调用的?
V!Uc( TOt dUO By|4m 什么是自定义的tag?
s;e\ pt COlqcq'qAu 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
*@5 @,=d 9;{CIMg& 自定义tag标签有很多特色,诸如:
as|<}:V qX%_uOw:% · 可以在JSP页面中自定义tag标签的属性
1zv'.uu., :;}P*T*PU · 访问JSP页面中的所有对象
$FV NCFN% ]^E?;1$f? · 可以动态地修改页面输出
la!~\wpa :TbgFQ86~ · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
}vuO$j CJY$G}rk · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
FrS]|=LJhX Ui~>SN>s tmq OJ 使用tag标签
?s01@f# [,Gg^*umS `yyG/l 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
o!Zb0/AP) K+eM 要使用tag标签,JSP程序员必须做2件事:
js(pC@<q5 .('SW\u- · 声明此tag标签的tag库
SUiOJ[5, >:-$+I · 实现此tag标签
(`^1Y3&2 oJ^P(] dw 声明tag标签所在的tag库
X?O[r3< K;?+8(H 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
V[LglPt VA%J\T|G2\ <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
I7onX,U+ ="+#W6bZT uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
?<!| oH@78D0A TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
Nn6%9PX_) kiEa<-] 以下taglib指示符直接引用一个TLD:
w)f#V s :#Wd~~d <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
)=+|i3]U 5pX6t 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
,tFg4k[ t@(HF-4~= <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
%{W6PrY{ 1MFbQs^ 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
x}4q {P5$ 9 hl_|r~%* <taglib>
=X}J6|>X .-zom~N-? <taglib-uri>/tutorial-template</taglib-uri>
&oNAv-m^GD Rq -ZL{LR7 <taglib-location>
F9^S"qv$ 203s^K61 /WEB-INF/tutorial-template.tld
mh%VrAq z{q`G wW </taglib-location>
).O)p9 KNl$3nX </taglib>
UMi~14& ; W?&%x(6M tQVVhXQ7 实现此tag标签
@7}W=HB >P(.:_^p Xw1*(ffk 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
*~`(RV h[ ZN+M kJU2C=m@e2 tag标签类型
" bG2: PT
~D",k JF]JOI6.e 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
sOY:e/_F +@UV?"d <tt:tag>
42{~Lhxt (FV >m body
(7Qo hH.G#-JO </tt:tag>
BtZ yn7a GgU/!@ g(g& TO 一个不带body的tag标签如下:
[g,}gyeS( \V:^h[ad <tt:tag />
z:O8Ls^\T pg.%Pdr<$ }H2R3icE 简单的tag标签
qs6aB0ln iZ%yd- 一个没有body和属性的tag标签如下:
9WHddDA HW|IILFB <tt:simple />
[
~,AfY
kAx4fE[c \e_O4
带属性的tag标签
M|-)GvR$J N`i/mP fA-7VdR`R 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
KoY F] pAEx#ck 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
~[: 2I t^HRgY'NjM <loglic:present parameter = “Clear”>
*j=%
# GbyJ: 而另一个标签logic:iterate是用表达式来给属性赋值:
Ac6=(B %y@AA>x! <logci:iterate collection=”<%= bookDB.getBooks() %>”
ysN3 2c}E(8e] id=”book” type=”database.BookDetails”>
Rcv9mj]l <3iMRe 0(Ij%Wi, 带body的tag标签
$'TM0Yu, a.'*G6~Qgw 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
^.tg 7%dJ GILfbNcd 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
}G=M2V<L 9L9sqZUB <logic:present parameter=”Clear”>
^8tEach C~[,z.FvO <% cart.clear(); %>
)"LJ
hLg m|# y
>4 <font color=”#ff0000” size=”+2”><strong>
Cw%{G'O c,22*.V/ 你选择了清除购物车!
zi:BF60]= 0V]s:S </strong></font>
]Dzlp7Y} =sFTxd_"iQ </logic:present>
mmsPLv6 wBzC5T%, 67TwPvh 到底是用属性还是用body来传递信息?
fVwUe _Y f::Dx1VcX 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
'yth'[ B *vM0 H]!"Zq k 定义脚本变量的tag标签
!W0v >p A
>$I
-T+ 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
+"(jjxJm ,[Fb[#Qqb <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
l,:F Q&&@v4L <% tx.begin(); %>
%SI'BJ d3Rw!slIq ...
':W[ A HDKbF/ -8Xf0_ 具有协作关系的tag标签
iLz@5Zj8 23?rEhKe 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
eQ"E h~26WLf. <tt:tag1 attr1=”obj1” value1=”value” />
-&;TA0~; {!`4iiF <tt:tag2 attr1=”obj1” />
M;NX:mX9 6RM/GM 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
_6Ha 9kojLqCT <tt:outerTag>
7KPwQ?SjT 3F0 N^)@ <tt:innerTag />
&{RDM~ G
j1_!.T </tt:outerTag>
ca}2TT&t C7vxw-o|&p !c-*O<Y Tag处理类
fV:83|eQ .o8t+X'G X|[`P<'N< Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
Y~Ifj,\ IAEAhqp 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
4=.so~9odX 2(nlJ7R 下表说明不同类型的tag所需要不同的处理过程:
b2]Kx&! bfO=;S]b! Tag处理类的方法
`kr?j:g ]{ kPrey Tag标签类型
<| &Npd' 所调用的方法
{x7, _rYkis^u 基本标签
|%v^W 3 doStartTag, doEndTag, release
6r_)sHf <ih[TtZ 带属性的标签
-![|}pX doStartTag, doEndTag, set/getAttribute1...N, release
+*^H#|! v3qA":(w+( 带内容的标签
b6 M doStartTag, doEndTag, release
*'X3z@R s<Fl p 带内容的标签,且内容重复循环
Kg$Mx doStartTag, doAfterBody, doEndTag, release
x`?3C"N:< 4fzZ;2sl} 带内容的标签,且内容与JSP交互
d %#b:(, doStartTag, doEndTag, release, doInitBody, doAfterBody, release
c(%|: P^ p:%loDk 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
.~}1+\~5 X jX2] 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
xKC[=E>z VD :/PL 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
qCO/?kW 0;ji65 `XB
9Mi= Tag库描述(简称TLD)
05k0n E ;>YzEo 0^ibNiSP Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
N[yy M'C v}x&?fU ` TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
G9:l'\ V>
bCKtf& 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
j5ve2LiFV% EIQ
p>|5 <?xml version="1.0" encoding="ISO-8859-1" ?>
-(#iIgmP ]7mt[2Cd <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
E!#WnSpnK TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
-gWZwW/lD PT9*)9<L Faf&U%]*` <taglib>的子元素
~nPtlrQa#* 7yba04D) Element
"Pf~iwfw Description
PuO&wI]: hL5|69E tlib-version
nLiY%x`S Tag库的版本
`g})|Gx )Z
VD+X jsp-version
N36_C;K-z Tag库所需要的jsp的版本
&I406Z f7y ;'Nd~:-] short-name
QwJyY{O` 助记符,tag的一个别名(可选)
Ow077v? h-D}'R uri
+U.I( 83F 用于确定一个唯一的tag库
7!$^r$t -tNUMi' display-name
!YJs]_Wr 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
d:{O\ e!r-+.i( small-icon
AvHCO8h| 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
69 o7EA .}`Ix'. large-icon
lA-h`rl/ 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
l0hlM# _7)n(1h[3b description
N&V`K0FU 对tag库的描述(可选)
g>9kXP+ d'I"jZ listener
'Qo*y%{@5 参见下面listener元素
L~>i, Y5d \d\e/ tag
f4Rf?w* 参见下面tag 元素
0C*7K?/
EU/8=JA1 Listener元素
kM@zyDn, 4NIRmDEd 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
S@ f9c {vO9ptR; Tag元素
RAK-UN {
buy"X4 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
+&"zU GTIc }-3mPy(*% 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
Uv~QUL3> T"}vAG( .O Tag元素的子元素
^<-+@v* zNuJj L 元素名称
TvQo? 描述
qcGK2Qx C{XmVc. name
f>Jr|#k 独一无二的元素名
K!]/(V(} *r% c tag-class
6B
?twh) Tag标签对应的tag处理类
ivz5H(b |id
<=Xf tei-class
wg]LVW} javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
@jlw_ob2g bNoW?8bZ body-content
z%LIX^q9 Tag标签body的类型
4I?^ t" 5lT*hF display-name
4X(H; 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
~BkCp pI }Ys>(w small-icon
AZ}Xj>= 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
'!a'ZjYyi d$AWu{y large-icon
5-xX8-ElYz 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
E1U",CMU mS~kJy_- description
/_#q@r4ZQ 此tag标签的描述
f8.gT49I G<^{&E+= variable
MO <3"@/, 提供脚本变量的信息(同tei-class)(可选)
NS6:yX,/ AlW66YAuQ attribute
Sa`Xf\ Tag标签的属性名
v2;`f+ 9v!1V,`j" 以下章节介绍对于不同类型的tag,如何具体地实现它们。
!GEJIefx_ e,XYVWY% ;
p {[1 简单的tag
_W'-+, ?_"ik[w} :'&brp3ii= tag处理类
Zdo'{ $
HuKc9U'7A 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
k/gZ, Q7COQ2~K 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
H =^`! }:*]aL<7_ x*&|0n.D public SimpleTag extends TagSupport
{Wu$YWE*sx 'W,jMju {
1&(V ;x1PS public int doStartTag() throws JspException
; XN{x :7?FF'u {
qXtC^n@x ;K&o-y try{
WPG(@zD M*HnM( pageContext.getOut().print(“Hello.”);
f\>M'{cV "E?2xf|. }catch(Exception e){
Hi`//y*92H <)-Sj, throw new JspTagException(“SimpleTag: “ + e.getMessage());
,47Y9Kz9 PJrtMAcKq }
xDoC( JOLaP@IPT return SKIP_BODY;
cFnDmtI: Ev(>z-{F }
'B0{_RaTb Gvqxi| public int doEndTag()
T+K):ug P{+T<bk| {
8j\cL' r|PB*` return EVAL_PAGE;
|:<f-j7t~ zEy N) }
8j %Tf; o/Q;f@ }
!pdb'*,n M|`U"vO [ )dXI IM 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
JU5C}%Q6 b4ONh% <body-content>empty</body-content>
,lA s 6@0OQb Fv<F}h? 6 带属性的tag标签