标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
u%3i0BajY 1!1!PA9u 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
!^w
E/ x5h~G 在这篇文章中,我们主要讨论:
DkDoA;m k?*KnfVh! · 什么是自定义tag标签?
_ \D"E>oM `!vUsM .d · 怎么使用tag标签?
|4;UyHh ST1'\Eo o 声明要使用的tag库
.5w azvA LlHa5]E@6 o 找到与之对应的tag处理类
edipA
P~! kJ{+M] pW o tag标签的类型
^{F_a aI3CNeav · 自定义tag标签
8|@9{ 0|c}p([~ o tag处理类
f>2MI4nMG wM~H(=s`D o tag库描述
+1rkq\{l 7b[wu~'(
n o tag标签示例
5'KA'>@ ),(V6@Z? o 带属性的tag
/( hUfYm0 Kcy@$uF{2 o 带body的tag
[;A[.&6 IgIYguQ o 定义了脚本变量的tag
/mA,F;
X6\ sF"E o 具有协作关系的tag
=-"c*^$] NX[4PKJ0C · 自定义tag标签
v+G=E2Lhv -F@L}| o 一个迭代tag的例子
j$Ab>}g] E{E0Z9t7& o 一个模板tag库
t)f-mQz) W3H+.E o tag处理类到底是怎样被调用的?
Jrxz'9qRG &@% $2O.3 [ sF(#Y:I 什么是自定义的tag?
G2Vv i[c M|,mr~rRG 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
58 bCUh#uw 3djC;*,9, 自定义tag标签有很多特色,诸如:
xtfBfA mN|r)4{` · 可以在JSP页面中自定义tag标签的属性
x/!5K|c gNYqAUG5 · 访问JSP页面中的所有对象
zFz10pH oGa^/:6L · 可以动态地修改页面输出
Hc^W%t~ q1?&Ev^ · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
s{0aBeq 8NBT|N~N · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
X5LBEOG n_?tN\M _P?s' HH 使用tag标签
vi.w8>CE (o5j'2:. En{`@JsM 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
1rKy@9 F+m }#p 要使用tag标签,JSP程序员必须做2件事:
Ep9W- n?} nKa$1RMO · 声明此tag标签的tag库
2*w0t:Yxe Dre2J<QL · 实现此tag标签
z2_6??tS/c a2IgC25 声明tag标签所在的tag库
ryB}b1`D f| _u7"OX 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
5"XC$?I<} PHOP%hI$ <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
0k)rc$eDF+ El\%E"Tk% uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
yAL[[ GZI`jS"lU TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
'k;rH!R wX >*H 以下taglib指示符直接引用一个TLD:
#$1Z k:jSbbQ <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
4}+/F}TbJ5 Od f[* 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
7xRl9
HY)-/ <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
v~QHMg HK`I\,K 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
ZKHG !`X0 pRkP~ZISU <taglib>
)nL`H^ fU=B4V4@ <taglib-uri>/tutorial-template</taglib-uri>
Mmpfto%i _XCOSomL` <taglib-location>
I:K"'R^ PB;eHy /WEB-INF/tutorial-template.tld
3k#~yaoI y;_% W </taglib-location>
Pj}66. UMAgA!s </taglib>
Zm6{n' zR2B-
&]H `tP7ncky 实现此tag标签
_S>JKz I(S`j[U o2<#s)GpY 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
:oJ=iB'Zc 'Ut7{rZ5 hjZKUMG(k tag标签类型
6DH~dL_",% "g$IP9?U /p8dZ+X 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
DI+fwXeg qkiI/nH3 <tt:tag>
ep)>X@t bv&;R body
t+9][Adf ty8v
6J# </tt:tag>
")d`dj\o X5j1`t, Djg,Lvhm 一个不带body的tag标签如下:
Na:w]r:y Q~Hy%M%R3 <tt:tag />
tQS5hwm* @Y1s$,=xB EK4d_L]I 简单的tag标签
sBcPq SMby O)[1x4U 一个没有body和属性的tag标签如下:
B)0i:"q Hv2De0W <tt:simple />
j KoG7HH yU9DSY\m{ Z<vKQ4G 带属性的tag标签
tCdqh- ZpnxecJUJ Za1QC;7 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
K*~0"F>"0 cXKjrL[b 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
3f,hw5R /pT=0= <loglic:present parameter = “Clear”>
B]Thn Q\ 0cvmU 而另一个标签logic:iterate是用表达式来给属性赋值:
#3gp6*R 1,% R;7J=g <logci:iterate collection=”<%= bookDB.getBooks() %>”
XCBL}pNkR g"}%2~Urf id=”book” type=”database.BookDetails”>
0$ S8fF@
~^1 {B\I CLUW!F 带body的tag标签
c-(UhN3WG Ru>MFG 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
oM>Z;QVRC:
sG
F aL 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
]x(!&y:h ?vbvBu{a <logic:present parameter=”Clear”>
Z'.AA OG ;IZwTXu !S <% cart.clear(); %>
*2,VyY T( U_ <font color=”#ff0000” size=”+2”><strong>
-w"VK|SGm 5fd]v< 你选择了清除购物车!
~5}*
d 5:KQg
</strong></font>
Zg{KFM% gcl5jB5)> </logic:present>
@X#F3; }f6HYU <nT
+$ 到底是用属性还是用body来传递信息?
R8a3
1& .nx2";oi 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
` 2V19s] %5"9</a&G G$F<$ 定义脚本变量的tag标签
Wa{` VS [q8 P~l 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
) QU P&*2pX: <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
@emK1iwm Ezd_`_@R <% tx.begin(); %>
D$I5z.a wNpTM8rfU# ...
j}.\]$J
CDK5 >JFO@O5 具有协作关系的tag标签
/} b03 CTq&-l:f 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
Nh_Mz;ITuu B#Vz#y <tt:tag1 attr1=”obj1” value1=”value” />
c7x~{V8 4R1<nZ"e~ <tt:tag2 attr1=”obj1” />
j i7[nY Lr~=^{ 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
(ROY?5
@c $QN"wL|| <tt:outerTag>
wsI`fO^A8 K;?m';z0 <tt:innerTag />
Qp_isU Bg x'9p/ </tt:outerTag>
3z{?_;bR 1W^taJH] KBx6NU?;PO Tag处理类
^:^9l1] eg;~zv FQ<Ju. Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
[+n*~ 4.[^\N 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
,St#Vla &8Cu#^3
下表说明不同类型的tag所需要不同的处理过程:
mwHB(7YS, $P^q!H4D Tag处理类的方法
< $lCkSx<Q YNKHN2E8 Tag标签类型
K*LlW@ 所调用的方法
yerg=,$_i ,Z&xNBX 基本标签
'"0'Oua doStartTag, doEndTag, release
%)zodf r!_-"~`7E 带属性的标签
Ug>~Rq] doStartTag, doEndTag, set/getAttribute1...N, release
`ZYoA
t]C~ s>7}zU] 带内容的标签
S9]'?| doStartTag, doEndTag, release
m
Bu ` Mjj@[ 带内容的标签,且内容重复循环
*\+\5pu0 doStartTag, doAfterBody, doEndTag, release
PUp6Q;AdQ CkOz 带内容的标签,且内容与JSP交互
c|e~BQdRw doStartTag, doEndTag, release, doInitBody, doAfterBody, release
[%y';`( x $p#Bi-& 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
AG`L64B A5c%SCq; 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
KX ,S +Vb.lH[av 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
LDgrR[ Rr&h!YMb JjtNP)We Tag库描述(简称TLD)
yVU^M?`# :}'=`wa #A1%gIw<v2 Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
6m*QX+ ]b2p G' TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
^a0um/+M} @vC4[:"pD} 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
w'Y7IlC Ns>-
o <?xml version="1.0" encoding="ISO-8859-1" ?>
+~m46eI XixL R <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
?uzRhC_)! TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
Elcj tYu4 )WNzWUfn=z }7|1 <taglib>的子元素
HSjlD{R 3`t#UY).F Element
KrgFKRgGj Description
eenH0Ovv 7Wf/$vRab tlib-version
##,a0s^ Tag库的版本
{Z(h.de 44ek
IV+? jsp-version
W9 GxXPA Tag库所需要的jsp的版本
!Q2d(H>
>?2M
}TV3 short-name
h5*JkRm 助记符,tag的一个别名(可选)
1gL2ia b|l:fT?& uri
j/323Za+ 用于确定一个唯一的tag库
`uv2H$ W#9BNKL display-name
tU }h~&M 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
@K &GJ B3pCy~*5 small-icon
Si2k"<5U 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
{j.bC@hWw EU2$f large-icon
D=q:*x 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
*v;2PP[^ -u6bAQ description
$O&b`` 对tag库的描述(可选)
9&-dTayIz Sq>dt[7 listener
cvn@/qBq*t 参见下面listener元素
"%`1]Fr 1{)5<!9! l tag
K[I=6 参见下面tag 元素
d~9A+m3b_ zGb|) A~, Listener元素
F+YZE[h% e(]!GA 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
\j@OZ 1!xQ=DU" Tag元素
,Xu-@br{ ne>pOK<vZ 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
NW~N}5T so,t 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
NO*u9YH? ((YMVe Tag元素的子元素
v [wb~uw\ :}He\V 元素名称
9P1OP Xv*p 描述
+SP{hHa^ nHM~ name
]J1dt N= 独一无二的元素名
VQc_|z_s b.2aHu( 3 tag-class
&PR5q7 Tag标签对应的tag处理类
rN<0
R`4sE R3
-n>V5o tei-class
kKaE=H-x javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
Vh'P&W?[ F%@A6'c body-content
%|s; C Tag标签body的类型
C8J[Up {c6=<Kv display-name
F|'>NL-= 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
&p'Y^zL- hr#M-K small-icon
4`4kfiS$ 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
Tm~" IB* \o z#l'z large-icon
Eq% } 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
\{Y 7FC~ ;"a=gr description
E(*0jAvO[z 此tag标签的描述
J?*1*h DwM)r7<Ex variable
9&$y}Y 提供脚本变量的信息(同tei-class)(可选)
-WY<zJ 7o7)0l9! attribute
0eT(J7[ < Tag标签的属性名
LoURC$lS !O\82d1P 以下章节介绍对于不同类型的tag,如何具体地实现它们。
vDp8__^ G"r1+# W,K;6TZhh 简单的tag
Ansk,$
\Z?9{J R|6Cv3: tag处理类
M92dZ1+6 @3>u@ 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
f/ U` W\>fh&!) 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
Cz9xZA{[M T`9lV2x*P .iYJr;9`d public SimpleTag extends TagSupport
@KXV%a' BGvre'67 {
FI)17i$
[@&m4 7 public int doStartTag() throws JspException
%vn|k[nD pd:WEI
, {
ts,ZvY] aHV;N#Lx3 try{
G0CW}e@) xipU8'ac/ pageContext.getOut().print(“Hello.”);
0CWvYC%e 6gL#C& }catch(Exception e){
C(eTR1 5Y.)("1f}f throw new JspTagException(“SimpleTag: “ + e.getMessage());
4R#chQ ?fQ'^agq }
D@,6M#SK BnX0G1|# return SKIP_BODY;
S4Pxc
]! TYy?KG>:' }
eVEV}`X 4n#M public int doEndTag()
.8 2P(}h XD!W: uvb {
l3{-z4mw ?U%qPv: return EVAL_PAGE;
>1.X*gi?- dph{74Dc }
'3R`lv $By<$ }
8^kGS-+^ /}((l%U E. u0}vWkn\4 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
L 8c0lx}Nn sG(~^hJ_ <body-content>empty</body-content>
9Uh"iMB s%vis{2 /Y/UM3/ 带属性的tag标签