标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
I16FVdUun4 I8H3*DE 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
^z,3#gK uU
d"l,V 在这篇文章中,我们主要讨论:
dwj?; rYUIFPN · 什么是自定义tag标签?
$H:!3-/ :;?$5h*|` · 怎么使用tag标签?
2a d|v] 2D\pt o 声明要使用的tag库
F>;Wbk&[| U)}]Z@I- o 找到与之对应的tag处理类
)&Ii!tm3 SX4*804a_ o tag标签的类型
A#U! KX E^8|xT'h6 · 自定义tag标签
xd Z$|{, lu=a e<M o tag处理类
wMa8HeBE\ %ms%0% o tag库描述
U-|]A\`)I lyn%r o tag标签示例
TrI+F+; hgU;7R,?ir o 带属性的tag
]jT}]9Q$ 6<&~R3dQ o 带body的tag
KsDS!O U}92%W? o 定义了脚本变量的tag
"t|)Kl dX(JV' 18A o 具有协作关系的tag
Z|$# HoI6(t · 自定义tag标签
O&!R7T &raqrY|V o 一个迭代tag的例子
3%vXB=>T! |Xt G9A> o 一个模板tag库
xAmtm" Q14zc0N o tag处理类到底是怎样被调用的?
ay"jWL- {C |R@S v,4{:y]p 什么是自定义的tag?
g`fG84 *s6x 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
zs$r>rlO G
e;67 自定义tag标签有很多特色,诸如:
}'[>~&/" bY_'B5$.^2 · 可以在JSP页面中自定义tag标签的属性
C'R9Nn' qqDg2,Yb · 访问JSP页面中的所有对象
Z\
hcK: )O'LE&kQ| · 可以动态地修改页面输出
{f06Ki Gxr\a2Z&r% · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
Xv1vq
-cM m*^)# · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
x $uhkP 7# AIX], =D<0&M9C 使用tag标签
]545:)Q1 Ft5A(P > Emlj,c<?j 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
*)m:u : 5c- P lm% 要使用tag标签,JSP程序员必须做2件事:
\ `Hp/D1 ?N kKDvv · 声明此tag标签的tag库
Ny^ 1#R !73y(Y%TE · 实现此tag标签
*g5bdQ:Av~ ~${~To8$CW 声明tag标签所在的tag库
OG$n C Q2
q~m8( 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
e5_Hmuk| 4`O[U#? <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
w>W #cTt 20Zxv! uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
Zue3Z{31T OP/DWf TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
JFv70rBe $dfc@Fn^x 以下taglib指示符直接引用一个TLD:
T//xxH]w- s|C[{n<_ <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
s8-RXEPb M0
z%<_<} 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
0/HFLz' M9)4ihK <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
Wf
c/?{ P2n8H Fi 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
cSL6V2F *\ii+f- <taglib>
!}Xoqamm Snr(<u <taglib-uri>/tutorial-template</taglib-uri>
l";Yw]:^ |5u~L#P <taglib-location>
KL \>-
rLTBBvV /WEB-INF/tutorial-template.tld
\$ 9C1@B@ 2 "&GH1 </taglib-location>
7@@g|l] gvP-doA7W </taglib>
N~/'EaO =3-=p&* 3IYFvq~ 实现此tag标签
^E}?YgNp h,/Aq ?:r?K|Ku 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
=lAjQt IfmQPs+f =g+}4P tag标签类型
O Z
./suR) jNj;#C) Pmv@ 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
BX/3{5Y>{ nDnJ}`k <tt:tag>
luP;P& uV:R3#^ body
IiE6i43 T)P)B6q </tt:tag>
HOx4FXPs I>?oVY6M@u |]-Zz7N) 一个不带body的tag标签如下:
q>_<\|?%x mZ71_4X# <tt:tag />
*RkUF!)( k`5I"-e Avw=*ZW 简单的tag标签
///Lg{ie 96w2qgc2 一个没有body和属性的tag标签如下:
bK:U:vpYm 0?54 8yH <tt:simple />
?^VPO% ZR1U&<0c@ FKO2UY#&7 带属性的tag标签
`D ;*.zrA oU|G74e6 V'9.l6l 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
4Y(@
KUb iC3z5_g*@ 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
&tH?m;V TuQGF$n@ <loglic:present parameter = “Clear”>
xM%4/QE+ tp`1S+'~j 而另一个标签logic:iterate是用表达式来给属性赋值:
d,GOP_N8I "3^tVX%$\[ <logci:iterate collection=”<%= bookDB.getBooks() %>”
9FDu{4: 6f +aGz id=”book” type=”database.BookDetails”>
f<8Hvumw lpG%rN! ~N!HxQ 带body的tag标签
k6C XuU 'xH^ksb " 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
`X<B+:>v- >Y>R1b% 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
JP8}+ Et3I(X3 <logic:present parameter=”Clear”>
}JFTe
g t5{P'v9J <% cart.clear(); %>
6x^$W ]R =TD`P et <font color=”#ff0000” size=”+2”><strong>
Z:9 Q~}x8 sZrVANyqb 你选择了清除购物车!
gGMfy]]R 1Ms]\<^j </strong></font>
g-qXS]y7 >NUbk9}J4 </logic:present>
u%C oo f\_RW;y|m c|/HX%Y
到底是用属性还是用body来传递信息?
<UGaIb
N|DfE{, 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
nL
5tHz:e -PV1x1| x*Z'i<;B 定义脚本变量的tag标签
)9H5'Wh# irQ'Rm[ 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
L('1NN2 $e+sqgU <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
7I;kh`H$(f aDdxR: <% tx.begin(); %>
*$=i1w 4<Vi`X7[F ...
M
FIb-*wT cK'g2S vK!`#W`X 具有协作关系的tag标签
necY/&Ld- [Vs\r&qL 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
iaL@- dg ~YH?wdT <tt:tag1 attr1=”obj1” value1=”value” />
i >3`V6 ?W'z5'| <tt:tag2 attr1=”obj1” />
nkHl;;WJ F;Q,cg M 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
s!(R L3{(Bu <tt:outerTag>
G|,&V0* -K/+}4i3N <tt:innerTag />
^xHKoOTj[ Xc-["y64 </tt:outerTag>
mI8EeMa{ `Na()r$T ( eKgc Tag处理类
aMI;;iL^ LhO\a 0%bCP/ Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
NQqw|3 )M0`dy{1 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
^BF}wQb:j &ZD@-"@ 下表说明不同类型的tag所需要不同的处理过程:
8xB-cE wlNL;W@w Tag处理类的方法
dWn6-es WX4sTxJK Tag标签类型
TOHz3= 所调用的方法
>SXSrXyYX k>ErDv8 基本标签
b/_Zw^DPC doStartTag, doEndTag, release
Hf('BagBL SRfh{u 带属性的标签
[~N;d9H+*1 doStartTag, doEndTag, set/getAttribute1...N, release
=RWTjTZ h@`Rk 带内容的标签
VgbNZ{qk@ doStartTag, doEndTag, release
g}%ODa !H ;7\Fx8"s[ 带内容的标签,且内容重复循环
h8(#\E doStartTag, doAfterBody, doEndTag, release
eKr>>4,-P KZ2[.[(Ph 带内容的标签,且内容与JSP交互
3A,N1OXG doStartTag, doEndTag, release, doInitBody, doAfterBody, release
Q# hRnM N|i>|2EB 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
eV"%(<{ K e4oLF2 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
7RT{RE wm@j(h4 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
Onx6Fy]L 3#t9pI4 $$ND]qM$M Tag库描述(简称TLD)
#ksDU $^Xxn.B9 qlcd[Y*B Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
~DD
_n "]"0d[d TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
C@Wzg I7vP*YE 7F 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
5.^pD9 [mT JA4Zg*7I <?xml version="1.0" encoding="ISO-8859-1" ?>
k^oSG1F bkJ bnW= <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
.6gx|V+ TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
,t 2CQ uUfw"*D P'VHga <taglib>的子元素
)>ML7y &m--} Element
l-w4E"n3 Description
3}}/,pGSc JM;bNW8 tlib-version
eP~3m Tag库的版本
|va@&;#wf )#AYb jsp-version
; Pk"mC Tag库所需要的jsp的版本
OD'~t,St :kHk'.V1( short-name
lH3.q4D
5 助记符,tag的一个别名(可选)
#)S }z+I b]]k\b uri
4>(K~v5;N 用于确定一个唯一的tag库
Mg\588cI Hs)] display-name
r)S:=Is5 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
F,_cci`p ),{3LIr small-icon
2M+RA}dX 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
lSR\wz*Fk L~ax`i1:" large-icon
XF: wsC 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
&3/`cl[+ Sp[9vlo8 description
q5g_5^csM{ 对tag库的描述(可选)
HZ<#H3_ix il>+jVr listener
}F1Asn 参见下面listener元素
.U(6])%;@ iY>xx~V tag
8GxT! 参见下面tag 元素
ybJa: wSjy31 Listener元素
7eq.UyUxs PE7V1U#$o, 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
hak#Iz0[C jEKa9rt Tag元素
=pe O% 9I 6^-m@: 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
"^t7]=q 4oF,;o+v\4 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
36'J9h\ rKPsv*w Tag元素的子元素
}c/#WA|b QPVr:+\B{ 元素名称
8;=?F>]xn 描述
W=2.0QmW IF>v
-Z name
?Zv5iI 独一无二的元素名
&/EZn xl akw:3+` tag-class
\yymp70w Tag标签对应的tag处理类
%|@?)[; R(Vd[EGY tei-class
_6FDuCVD- javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
*RkvM?o@jC y3*IF2G body-content
N
cHCcc Tag标签body的类型
J'cE@(US .WOF:Nu4
display-name
IwFf8?
3 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
M-Nn \h$, >VjtKSN small-icon
f].z. 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
PmId #2f ZbH6$2r large-icon
D622:Y886 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
Zo-Au zh !/24p9 description
JmF`5 此tag标签的描述
J!rZskd -'W:P'BG variable
UL7%6v{'* 提供脚本变量的信息(同tei-class)(可选)
]H:K$nmX Zf u" 8fX attribute
YVY(uq)d Tag标签的属性名
r~;.8qs h\-jqaq 以下章节介绍对于不同类型的tag,如何具体地实现它们。
a(o[ bH.|; Y!E|X 3 zJ0'KHF}o 简单的tag
d@|j>Z gvZLW!={ XeBSHvO_ tag处理类
OQX ek@~2 L3Q1az!Ct 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
6a`_i
qf]OSd 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
6ud<B NOmSLIgt7 PzTTL=G + public SimpleTag extends TagSupport
]*;+ U6/? RZE:WE;5 {
K[TMTn ;v+CQx public int doStartTag() throws JspException
7e#|=e
*I! a( {`<F {
Zr2QeLQC( 1J*wW# e try{
N<Q}4%^c uJp}9B60_ pageContext.getOut().print(“Hello.”);
l1_X5DI dl$l5z\ }catch(Exception e){
<ct {D|mm f&cG;Y
throw new JspTagException(“SimpleTag: “ + e.getMessage());
"AVj]jR .r*b+rc;] }
s*#|EdD6@ a
m zw return SKIP_BODY;
;09J;sf |]\bgh }
+[}]a3) /~tfP public int doEndTag()
6k3l/ ~R fAUsJ[ {
s*YFN#Wuc 17Gdu[E return EVAL_PAGE;
?h3Ow`1G m<f{7]fi5 }
?HcA&
246lFxG. }
/+1Fa): 22r01qH Pd;ClMa% 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
mVL,J=2 < 5_Ys <body-content>empty</body-content>
|uZ=S]V@ tr/dd&(Y1 y?@Y\ b 带属性的tag标签