标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
cT5BBR KV)if' 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
Wl7S<>hg4 T65"?=<EB 在这篇文章中,我们主要讨论:
X[!S7[d-y sd9b9?qiu · 什么是自定义tag标签?
Jcy+(7lE) p9 G{Q · 怎么使用tag标签?
#-i#mbZ e a/</P
|UG o 声明要使用的tag库
||L^yI~_d &5[B\yv o 找到与之对应的tag处理类
Wo(m:q(Om Eunmc o tag标签的类型
lc 3N i<3v a!EW[|[Q · 自定义tag标签
;t M U[? f@.& o tag处理类
$>7T s>8 )5NWUuH 5 o tag库描述
ik](k"1{ f/QwXO-U o tag标签示例
^T#jBqe + 9I|Fm o 带属性的tag
Qz89=#W S,EL=3},= o 带body的tag
*07?U") ^/VnRpU o 定义了脚本变量的tag
{+]tx46$ "@^Q"RF o 具有协作关系的tag
&>!-67 f@gvDo]Y · 自定义tag标签
b0/YX@ AB{zkEuK o 一个迭代tag的例子
+cbF$,M4 .C.b5x! o 一个模板tag库
_K&Hiz/' XG!6[o; o tag处理类到底是怎样被调用的?
]j!pK4 mMvAA; %LM6=nt 什么是自定义的tag?
L?Ys(a"k ~MP |L?my 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
;%Px~g NG`Y{QT6N 自定义tag标签有很多特色,诸如:
P,xIDj4d ^?wR{q"8 · 可以在JSP页面中自定义tag标签的属性
M.xZU\'ty D2GF4%| · 访问JSP页面中的所有对象
} '?qUy3x 8A5/jqnqt · 可以动态地修改页面输出
x4/{XRQ 6{{<+
o · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
{kBsiSvsA; ]28j$)6
· tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
QT5pn5+ z C_'EO<w$ E[7E%^:Mg 使用tag标签
q(X7e WNZYs V= - 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
*o38f>aJl R(*t1R\ 要使用tag标签,JSP程序员必须做2件事:
RO|8NC<oj <W>A }}q · 声明此tag标签的tag库
~ g-( m"-kkH{I · 实现此tag标签
LuHRB}W ;aj;(Z.p) 声明tag标签所在的tag库
AloL+eN@ ^_i)XdPU 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
b;{"@b,Y Zk/ejhy0 <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
Hq+QsplG LR{bNV[i uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
4lWqQVx '6})L TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
AorY#oq Z#B}#*<C 以下taglib指示符直接引用一个TLD:
_5H~1G%q MPDRMGR@i <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
d:w/{m%# <i4]qO(0u 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
.drY 4H(8BNgzV <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
;Ce?f=4 #g0_8>t 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
Ws7fWK; :o~'\:/ <taglib>
LSA6*Q51 Q(cLi:)X2 <taglib-uri>/tutorial-template</taglib-uri>
RRPPojKZ <tBT?#C9+ <taglib-location>
2J{vfF Z$g'h1,zW /WEB-INF/tutorial-template.tld
/&Cq-W Xz^k.4 Y{4 </taglib-location>
br
Iz8] tM;cvc`/ </taglib>
;4ybkOD R6BbkYWrX m~*qS4 实现此tag标签
0 K#|11r K}cA%Y 87[ ,.W 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
Za1mI^ L1 [ i,[^ E"_{S.Wc tag标签类型
1HKA`]D"p Jw@X5-(Cp R[v0T/ 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
9#9bm ?g{[U0) <tt:tag>
T)sIV5bk yNXYS body
O5vfcX4> krFp q; </tt:tag>
|f @A-d X u9|Eos i ']eN4H&=?} 一个不带body的tag标签如下:
2F`#df yQUrHxm <tt:tag />
d@g2 9rs +B " aUF L=qhb;[L 简单的tag标签
3))CD,| m jP 一个没有body和属性的tag标签如下:
|Vqm1.1/Zv zHz>Gc <tt:simple />
"hI"4xSg K"XwSZ/ T@.+bD 带属性的tag标签
&Pm@+ML*x P$Vh{]4i{ WN{8gL&y 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
^8~TsK~ 8 <;.[l 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
DvQV_D J.: <loglic:present parameter = “Clear”>
lqv}~MC Q2Ey RFT 而另一个标签logic:iterate是用表达式来给属性赋值:
?OF$J|h QxLrpM"O <logci:iterate collection=”<%= bookDB.getBooks() %>”
Yb5@W/' )cRHt: id=”book” type=”database.BookDetails”>
:FC)+OmJ hNZ_=
<D! 53:u6bb; 带body的tag标签
q6$6:L,< d+v|&yN 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
TM{m:I:Z*n JS8pN5 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
5]]QW3 4y+hr <logic:present parameter=”Clear”>
SaF0JPm4z _ps4-<ugC <% cart.clear(); %>
Zy3F%]V0 `Zo5!"' <font color=”#ff0000” size=”+2”><strong>
~FYC'd *!y04'p`< 你选择了清除购物车!
c^1JSGv OfBWf6b </strong></font>
aC1 xt( .Qn#wub </logic:present>
M5+R8ttc =/|GWQj =Xr{ Dg 到底是用属性还是用body来传递信息?
,e1c,} p+b9D 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
,/Gp>Yqx {@7UfJh> ^Ff fc@= 定义脚本变量的tag标签
|>U<EtA" 2 N &B 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
}])j>E [7`S`\_NK <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
UV;I6]$}A7 l2Py2ZI-b <% tx.begin(); %>
b_{+O qI {)r[?%FMgV ...
4%nK0FAj g=4P-i3 `O3#/1+ 具有协作关系的tag标签
Om:Gun\% 1iR\M4?Frf 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
#Qz9{1\G K
~\b+ <tt:tag1 attr1=”obj1” value1=”value” />
qfFa" a LL3| U <tt:tag2 attr1=”obj1” />
fy>3#`T- !$iwU3~< 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
Z%.Ld2Q{ x?{l<mc <tt:outerTag>
lxXF8c>U L67yL( d6a <tt:innerTag />
H/x9w[\+[ QrmGrRH </tt:outerTag>
lp$,`Uz` 6tVp%@ e
jk?If 07 Tag处理类
:LX!T& o%]b\Vl6
j
yp.2c Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
DP*V|) Sb?v5 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
K~UT@,CS60 iuEe#B;! 下表说明不同类型的tag所需要不同的处理过程:
PB8U+ E(S$Q^ Tag处理类的方法
:Oj!J&A Us&~d"n Tag标签类型
vy5{Vm".4 所调用的方法
@d3yqA
25xt*30M 基本标签
#CeWk$)m doStartTag, doEndTag, release
Pvkr$ou m7>)p]] 带属性的标签
78Zb IL doStartTag, doEndTag, set/getAttribute1...N, release
V^G+_#@,, %7TG>tc 带内容的标签
b7M ) doStartTag, doEndTag, release
[F *hjGLc} %tkL<e 带内容的标签,且内容重复循环
gY-}!9kW] doStartTag, doAfterBody, doEndTag, release
JKYl R^I4_ZA 带内容的标签,且内容与JSP交互
]Ah<kq2sk doStartTag, doEndTag, release, doInitBody, doAfterBody, release
&s.-p_4w^D r)qow.+& 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
$I4JKh g fv?#mp 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
:NwFJc P]4u`& 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
14-uy.0[ @DR?^
q p )lx;u.$4 Tag库描述(简称TLD)
Q?m= a0g y7R{6W_U> ?y* yl Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
Z
+}#
Ic FO|Eg9l TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
hdH-VR4 .a]av 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
'! ;Xxe5 5Obv/C <?xml version="1.0" encoding="ISO-8859-1" ?>
\xZ6+xZd1 t_X=x`f <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
F,GG>(6c TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
QbAEWm UD]RWN h5H#xoCXp <taglib>的子元素
98l- 2;ogkPv ' Element
W2,Uw1\:1 Description
wAF#N1-k r$d'[ZcX tlib-version
6CWm;%B#G Tag库的版本
{1wjIo"ptg g>f_'7F& jsp-version
H]f8W]"c[ Tag库所需要的jsp的版本
v.H@Ey2 \" =@uqar2 short-name
`Yu4h+T 助记符,tag的一个别名(可选)
8bEii1EM Ria*+.k@"B uri
]:]w+N%7 用于确定一个唯一的tag库
<m?/yREK2 dy0xz5N- display-name
y"0!7^ 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
uchz<z1 .sPa${ small-icon
Ba|76OBRJ 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
RZKczZGZg G?{uR6s># large-icon
I9r> 3? 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
p8u-3 cf1GA description
jJY!;f 对tag库的描述(可选)
a
s?)6 yy3-Xu4 listener
>9]i#So^ 参见下面listener元素
4ze4{a^ L {i|OK^e tag
Rlf#)4 参见下面tag 元素
*[['X%f }#f~"-O Listener元素
baM@HpMhM /3v`2=b 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
L[:b\O/p, 3/((7O[ Tag元素
< G:G/ ob.=QQQs
每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
w!^{Q'/,Q
PP)-g0^@ 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
W[tX%B ::rKW*? Tag元素的子元素
-}*YfwK MXU8QVSY" 元素名称
lAPvphO 描述
L9)nRV8 vb Mv8Nk name
];o[Yn'>o 独一无二的元素名
~~'UQnUN4 zc#aQ. tag-class
5S?+03h~ Tag标签对应的tag处理类
;O7<lF\7o )o8]MWT\; tei-class
w[wrZ:[ javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
</8F J'>i3eLq body-content
tO^KCnL Tag标签body的类型
~<#!yRy>r U#!f^@&AB display-name
!G3d5d2)C 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
07L1 " /"<o""<] small-icon
zcNv T 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
ta 66AEc9 PxHHh{y%c large-icon
Os-sYaW 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
H|0GRjC AlRng&o~ description
IvyBK]{| 此tag标签的描述
_7"G&nZ0 Pb^Mc <j variable
("L&iu\`@ 提供脚本变量的信息(同tei-class)(可选)
Bzw!,(u/
" 4U;6 2 jq attribute
k/ 9S
Tag标签的属性名
^B|Q&1 B@W`AD1^{ 以下章节介绍对于不同类型的tag,如何具体地实现它们。
@ukIt !h0#es\ le-Q&* 简单的tag
2=6}! Y >)3[CU, ,1+)qv#|i tag处理类
$fwv' 2%Y]M%P 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
KGsH3{r
5 5_#?vw 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
}t[?g)"M#- Y&Sk/8 Z'vGX,: public SimpleTag extends TagSupport
Je#vl4<L X^U)j
N2 {
j[fVF3v lklMdsIdj public int doStartTag() throws JspException
g=
ql 3N $i+
1a0%n {
ni@N/Z?!pA }0P5~]S<5A try{
<QyJJQM *c+Kqz- pageContext.getOut().print(“Hello.”);
F`$V H^%V $=iV)- }catch(Exception e){
.}>DEpc:n 9o]h}Xc throw new JspTagException(“SimpleTag: “ + e.getMessage());
N{u4 H)),~<s }
%/o8-N|_[ 4_E{ return SKIP_BODY;
^hhJ6E_W MW^,l=kqW) }
ZV`D} CQ =!b<@41 public int doEndTag()
G02(dj |[tlR`A $ {
(CRY$+d S(c ,Sinc return EVAL_PAGE;
y^#jM 8#9di }
L)5YX-? Jbud_.h9 }
J3oj}M* DL5`A?/ <wt#m`Za 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
<(YmkOS+ xbFoXYqgP <body-content>empty</body-content>
][|)qQ%V 06 kjJ4 `[<j5(T 带属性的tag标签