标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
p<b//^ sywSvnPuYZ 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
YyOPgF] M h`O"]2 在这篇文章中,我们主要讨论:
Z05kn{<a8 <9zzjgzG{c · 什么是自定义tag标签?
*&$J.KM DONXq]f:," · 怎么使用tag标签?
~)!yl. H ;pk4Voo$ o 声明要使用的tag库
p,_,o3@~ 2tz%A~}4 o 找到与之对应的tag处理类
T:
zO9C/ WXJEAje o tag标签的类型
>*DR>U &PY~m<F · 自定义tag标签
0$RZ~ 4n55{?Z o tag处理类
j\W"P_ dpd kKbq?}W[ o tag库描述
Z>=IP-,> Z)
nB o tag标签示例
sVdn>$KXk 50,`=Z o 带属性的tag
5^kLNNum 5%H(AaG*q o 带body的tag
!,D7L6N HEqTlnxUu o 定义了脚本变量的tag
R8[l\Y>Ec ?HD(EGdx o 具有协作关系的tag
Q;9-aZ.H G- _h 2 · 自定义tag标签
#G</RYM~m xBba&A]= o 一个迭代tag的例子
zNAID-5K; h"~i&T
h o 一个模板tag库
)OjTn" i.QS(gM o tag处理类到底是怎样被调用的?
|tK_Bn 9W^sq<tR @9,=|kxK 什么是自定义的tag?
R]dN-'U R/!lDv!
一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
g]kM7,/M e6?iQ0 自定义tag标签有很多特色,诸如:
9;W2zcN *\#/4_yB} · 可以在JSP页面中自定义tag标签的属性
-cDS+*[ z{wW6sgPr · 访问JSP页面中的所有对象
.h({ P#QT Uc>kiWW · 可以动态地修改页面输出
Ej_ >*^b G6W_)YL · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
irjOGn Z;=h= · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
;v#BguM |nOqy&B ;Dh\2! sr 使用tag标签
0.pZlv SB1j$6]OR7 o!6~tO=% 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
j-~x==c-; @=
E~` 要使用tag标签,JSP程序员必须做2件事:
E[$"~|7|$ e>F i · 声明此tag标签的tag库
g`7C1&U*T QoLp$1O(y · 实现此tag标签
?L K
n =*0KH##%$ 声明tag标签所在的tag库
I{bDa'rX w\V1pu^6@ 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
h#hx(5"6 0B}O&DC%| <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
0H$6_YX4A ON(OYXj uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
Bb[WtT}= @euH[< TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
%fbV\@jDCX s=S9y7i(R 以下taglib指示符直接引用一个TLD:
q?R^~r (M0"I1g|w <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
`i!BXOOV{ z6IOVQ*r 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
[Sr^CYP( <QuIX A <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
V8w7U:K D=+md 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
nrBpq }Z/[ " <taglib>
]!c59%f= r5RUgt <taglib-uri>/tutorial-template</taglib-uri>
N>TmaUk YYE{zU <taglib-location>
o*k.je1 /M :7 /WEB-INF/tutorial-template.tld
qw?Wi%t(x8 -/V,<@@T </taglib-location>
N!PPL"5z ,59G6o </taglib>
Ir\P[A X!b+Dk Y9/`w@"v 实现此tag标签
40e(p/Qka bmOK8 \DiAfx<Ub 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
_2-fH *5QN: bcR";cE tag标签类型
adcH3rV x/pX?k B_uhNLd 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
Aaw]=8 OI ~hZr1hT6L <tt:tag>
m
>Rdsn~l A_!N,<- body
%jE0Z4\ pqCp>BO?O </tt:tag>
SeV`RUO 8aqH;|fG} K/YXLR + 一个不带body的tag标签如下:
+C}s"qrb@
UVd
^tg <tt:tag />
HJi
FlL3 b FMBIA| {X\%7Zef+ 简单的tag标签
4<j7F4 *V`E)maU 一个没有body和属性的tag标签如下:
;b5^)S M=M~M$K <tt:simple />
s||c#+j"8 R?3N><oh* c
W1`[b 带属性的tag标签
j].=,M<dxE yMz dM&a!* LE|DMz|J 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
Q\nIU7:bZ */APe# 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
p)qM{`]G\ Lp7h'|]u <loglic:present parameter = “Clear”>
0iAQ;<*xi Ez/>3:; 而另一个标签logic:iterate是用表达式来给属性赋值:
d4m@u$^1B xrZzfg <logci:iterate collection=”<%= bookDB.getBooks() %>”
M?d (-en =o)B1(v@. id=”book” type=”database.BookDetails”>
Gc=uKQ+\V o?g9Grk y&W3CW\: 带body的tag标签
xV0:K= O@>ZYA% 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
&R))c|>OT& ?{;7\1[4 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
IkuE | v@d]*TG <logic:present parameter=”Clear”>
?orLc,pU^ b&*)C#7/T <% cart.clear(); %>
qoP/`Y6 ]i/Bq!d l <font color=”#ff0000” size=”+2”><strong>
/,yRn31[ Zet80|q 你选择了清除购物车!
|\U 5m6 q >|pN4FS </strong></font>
a0jzt!ci 8
KRo< </logic:present>
Zg4kO;r08 $!vK#8-&{ z?Cez*.h> 到底是用属性还是用body来传递信息?
;LC?3. (@Kc(>(: Y 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
p=[SDk` m@W>ku 4 'DEdx,&f 定义脚本变量的tag标签
gle<{
` 48,uO! 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
3ESrd"W= :rU,7`sE/ <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
$=5kn>[_Z% GvBmh . <% tx.begin(); %>
`|<? sjY d5"rCd[ ...
Ki>XLX,er= 25;(`Td5 **.g^Pyc 具有协作关系的tag标签
AHU=`z .JBTU>1]_n 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
*LEI@ t[ZGY,8 <tt:tag1 attr1=”obj1” value1=”value” />
y" |gC!V} } J`cRDO <tt:tag2 attr1=”obj1” />
O Cnra UZ1Au;(| 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
`PT'Lakf;3 >uxAti\ <tt:outerTag>
3i#'osq !ou;yE&<, <tt:innerTag />
tC5>K9Ed m7u" awM^ </tt:outerTag>
yUN>mD- *#1J s`|KT&r Tag处理类
G1Vn[[%k p~v0pi MvTp%d. Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
x@@bC=iY$ 6 $K@s 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
m:c0S8#: qJJ},4} 下表说明不同类型的tag所需要不同的处理过程:
'A9Z (( >IipWTVo< Tag处理类的方法
lHFk~Qp[ T@Z-;^aV Tag标签类型
RWFvf 所调用的方法
PU4-}!K LKA/s ~G 基本标签
pjma<^|F doStartTag, doEndTag, release
('2Z&5 TUARYJ6= 带属性的标签
m%b#B>J,n doStartTag, doEndTag, set/getAttribute1...N, release
$WO{!R 4Ik'beZqK 带内容的标签
.vie#,la doStartTag, doEndTag, release
A6
Rw LX )SJ"IY\P 带内容的标签,且内容重复循环
z0UtKE^b doStartTag, doAfterBody, doEndTag, release
+~sqv?8 F_0@Sh" 带内容的标签,且内容与JSP交互
fRHzY?n9; doStartTag, doEndTag, release, doInitBody, doAfterBody, release
Ph)>;jU 7~SnY\B| 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
o+Mc%O Z et/v/Hvw1 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
03.\!rZZ $}fY
B/ 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
mNsd&Rk' aMGyV"6(-6 F\jawoO9 Tag库描述(简称TLD)
,20l` : viJP6fh i.^:xZ Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
S%e)br} 1B@7#ozWA? TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
?I u=os>* Pj_*,L`mZ 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
{q^UWv?1 4(,M&NC
<?xml version="1.0" encoding="ISO-8859-1" ?>
&A=c[pc P&yB(M-z <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
F:~@e( TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
ay#f\P!1 /!N=@z) cgO<%_l3` <taglib>的子元素
c& K`t x<7? Element
;#^ o5ht Description
r`pf%9k bn7g!2 tlib-version
nb ?(zDJ8 Tag库的版本
cI&XsnY 5vLA)Al3 jsp-version
Mcq!QaO}& Tag库所需要的jsp的版本
< FY%QB)h 4K 8 (H9( short-name
*U$%mZS]1 助记符,tag的一个别名(可选)
V9D q<y-y Vt,P.CfdC uri
!N!AO(Z 用于确定一个唯一的tag库
)Cat$)I#, 13*S<\ display-name
D]5j?X' 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
aj/+#G2 d%RH]j4 small-icon
5tk7H2K^< 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
<8YvsJ ah,"c9YX large-icon
:^-\KE`3 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
<\eRa{ef { `xC~B h description
,LC(Ax'.F 对tag库的描述(可选)
@2On`~C` `Y^l.%AZZ listener
SbQ:vAE*ho 参见下面listener元素
dn:\V?9 K=r~+4F tag
9m\Yi 参见下面tag 元素
uKj(=Rqq KzJJ@D*4M] Listener元素
Q- w_@~ /`0>U 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
>UV}^OO ddbQFAQQQ Tag元素
T%;NW|mH& z.+%{_pe 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
1f'msy/ 6 !N2B[9 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
&C)97E gGN6Yqj0 Tag元素的子元素
!Rgj'{ mD|Q+~=|e 元素名称
4j'`,a= 描述
fwlicbs ' VDxF%!h( name
BR_fOIDc 独一无二的元素名
TQPrOs? fn.;C tag-class
~N7;.
3 7 Tag标签对应的tag处理类
gVy`||z 4#:C t* f tei-class
EXwU{Hl javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
owI:Qs_/4 7j29wvSp5 body-content
@1' Y/dCyD Tag标签body的类型
6'.)z,ts E25w^x2 display-name
J1Az+m 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
)o-mM
tPj rO YD[+ small-icon
Pjxj$>&;*j 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
$RunGaX!=N KD\sU6 large-icon
\ H#" 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
IYHNN 2+b}FVOe\ description
wQ~]VVRN 此tag标签的描述
ggm'9| lL
50PU variable
8TK*VOf` 提供脚本变量的信息(同tei-class)(可选)
gv D*^ /k(wb4Hv attribute
nLC5FA7< Tag标签的属性名
c=QN!n:
Oi]B%Uxy= 以下章节介绍对于不同类型的tag,如何具体地实现它们。
Jr= fc*f P,xJVo\ =BJe}AV 简单的tag
mahNQ5 W*) =+I-9= <M}O&?N
8x tag处理类
@ &Od1X 2@@evQ 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
P2|+7D: uu"hu||0_ 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
k@h0 }% P=L@!F+s 5uOz #hN public SimpleTag extends TagSupport
mdo$d-d& shP}T[< {
F2ISg' z#rp8-HUDS public int doStartTag() throws JspException
;>;it5 l= "Nz@jv? {
}' sW[?ik `e?~c'a@ try{
LGVy4D wZW\r!Us pageContext.getOut().print(“Hello.”);
F?0Q AA y$_]}<b }catch(Exception e){
WK@<# }TAG7U* throw new JspTagException(“SimpleTag: “ + e.getMessage());
ez)Ks` RCxwiZaf33 }
E H%hL5( 5hDy62PRr return SKIP_BODY;
[N}QCy <"xqt7f }
lC,~_Yb !IB}&m public int doEndTag()
+Z86Qz_ u8`S*i/)m {
,'9R/7%s 4HX;9HPHE< return EVAL_PAGE;
UI%4d3 K{V.N<