标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
~(`iR xK ~dK)U*Q 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
)y:~T\g VscEdtkd 在这篇文章中,我们主要讨论:
uIvE~< U{o0Posg · 什么是自定义tag标签?
Hd)4_
uBt dLm~]V3 · 怎么使用tag标签?
=6TD3k6(2 L%JmdY; o 声明要使用的tag库
&a
p{|>3 j>Htaa o 找到与之对应的tag处理类
^1S(6'a# P-QZ=dm o tag标签的类型
]W%<<S ?c^0%Op · 自定义tag标签
2@aVoqrq# K/jC>4/c/ o tag处理类
{@oYMO~ LQs2!]?HT o tag库描述
6nRD:CH)X i9oi}$;J o tag标签示例
pVt8z|p_;{ &la;Vu"dp o 带属性的tag
fG5 U' Vw m$:o+IH/ o 带body的tag
b{t'Doe Uok?FEN o 定义了脚本变量的tag
lM5Xw =?3D:k7z o 具有协作关系的tag
t3b%f`D =x~HcsJ8!R · 自定义tag标签
_{6QvD3kg. ;X !sTs o 一个迭代tag的例子
]-&
ehW @twClk.s o 一个模板tag库
(yCFpb D`LcL|nmH o tag处理类到底是怎样被调用的?
5/Q^p"
wEo/H %uyRpG3, 什么是自定义的tag?
n9Z|69W6> ^e>`ob 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
&gZ5dTj> jYRwtP\ 自定义tag标签有很多特色,诸如:
Os@ d&wm XU .FLNe · 可以在JSP页面中自定义tag标签的属性
WLEjRx uHUicZf. · 访问JSP页面中的所有对象
V7!x-E/ C9U~lcIS · 可以动态地修改页面输出
*S_eYKSl Dg4?,{c9W · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
rm NqS+t pUWj,&t · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
2`Xy}9N/Y z)r)w?A bH&Cbme90- 使用tag标签
w3c[t~R8 DJ;G0* d$/BF&n 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
U&|=dH]- GM{m(Y 要使用tag标签,JSP程序员必须做2件事:
$cFanra jAmAT/ 1 · 声明此tag标签的tag库
VC\43A,9 O/>$kG%ge · 实现此tag标签
6';'pHqe T+m`a# 声明tag标签所在的tag库
pIk&NI Ujw A06 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
}|
_uqvin o-B9r+N <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
P7(+{d{ JGp~A#H& uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
&+=A;Y) EUU9JnQhBJ TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
C+$dm)M/q iK1<4) 以下taglib指示符直接引用一个TLD:
1K&z64Q5J [J0L7p*6 <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
Y!v `0z G:$wdT(u 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
Iu^#+n k`6T% [D] <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
Zg%U4m: iVzv/Lqm1 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
~oh=QakW -@-cG\{ <taglib>
.xuLvNyQr )Fk%,H-1 <taglib-uri>/tutorial-template</taglib-uri>
&C<B=T"I b40zYH`'{ <taglib-location>
a1B_w#?8 &96I4su /WEB-INF/tutorial-template.tld
T+zZOI |f&)@fUI </taglib-location>
.R;HH_ UHF.R>Ry </taglib>
&aldnJ /pZLt)=P Xz&Hfs"/J 实现此tag标签
kehv85 <7/ _Vs)F0 xWD=",0+ 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
1 e1$x@\\
qm&}^S gYfN?A*`_ tag标签类型
v_"p)4&' 8MGtJ'. ~cVFCM 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
deHhl(U; DTk)Y-eQ <tt:tag>
\T'uFy9&a 11}X2j~Ww body
W~k"`g7uu _9wX8fh3D </tt:tag>
\@vR*E i)g=Lew mK5<;$ 一个不带body的tag标签如下:
|\%[e@u kMAQHpDD <tt:tag />
rY_)N^B|nF KlDW'R$ r4k=i4 简单的tag标签
uOc:^ `Lb^!6`) 一个没有body和属性的tag标签如下:
DcE)6z# #"fBF/Q <tt:simple />
%+YLe-\? lcHwKd rlmzbIuI9 带属性的tag标签
+',[q E8zga ) /UTeaM!?" 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
;3OQgKI YwyP+Sr\ 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
~UX@%0%)N (wU<Kpt?J <loglic:present parameter = “Clear”>
<61T)7 AHc:6v^ 而另一个标签logic:iterate是用表达式来给属性赋值:
eTemRNz n~l9`4wJY <logci:iterate collection=”<%= bookDB.getBooks() %>”
q%%8oaEI W\:!v%C id=”book” type=”database.BookDetails”>
@&t';"AE hJ\IE?+ 1r;]== 带body的tag标签
k'E3{8<! =<R")D]4z 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
R)MWO5 %^f!= * 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
xDv$z.=Y i"Hec9Ri <logic:present parameter=”Clear”>
[74HUw> c""*Ng*T <% cart.clear(); %>
N7:=%F y( t+7h(?8L <font color=”#ff0000” size=”+2”><strong>
@^]wT_r 9J h"1i>x2 你选择了清除购物车!
j h0``{ l{ja2brX </strong></font>
JpqZVu"7 8\HL8^6c5 </logic:present>
:so2 {.t- Jn3cU ;[TC`DuNj0 到底是用属性还是用body来传递信息?
'QW/TJ=7r 6x|"1
G{ 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
'RK.w^ V/5.37FSb CZ"~N` 定义脚本变量的tag标签
?,uTH
4 _L
5< 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
yW5/Y02 f.8Jp<S2K <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
e^2e[rp0 ya7PF~:E- <% tx.begin(); %>
F5la:0fb !=%0 ...
q)vdDdRe_ zmd,uhNc: )a"rj5~- 具有协作关系的tag标签
.XDY1~w0 U$jw8I'. 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
D#Qfa!=g ^*JpdmVhu <tt:tag1 attr1=”obj1” value1=”value” />
,p2BB"^_i zY_xJ"/9 <tt:tag2 attr1=”obj1” />
QcQQQM -}avH
在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
7{F(NJUO1 ${I$@qq83 <tt:outerTag>
@!k\Ivd xuBXOr4"P <tt:innerTag />
5@l[!Jl0k XRoMD6qf; </tt:outerTag>
GVS-_KP\ ZccQ{$0H ?^y%UIzf Tag处理类
N6K%Wkz >d#oJ?goX YDh6XD<Z Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
R-odc,P= L(Ww6oj 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
O`Ht|@[6 CUJP"u>8M 下表说明不同类型的tag所需要不同的处理过程:
:eIPPh|\ j{}-zQ]n Tag处理类的方法
1K(a=o[Ce WZ}je!82 Tag标签类型
}{FKs!(4 所调用的方法
P$l-p'U- yLv jfP1 基本标签
"mT95x\NA\ doStartTag, doEndTag, release
"s[Y$!# ;/tZsE{ 带属性的标签
Qdepzo>E doStartTag, doEndTag, set/getAttribute1...N, release
m
,B,dqT iV+'p->/ 带内容的标签
IX/FKSuq doStartTag, doEndTag, release
$BIQ#T>qK -^A=U7 带内容的标签,且内容重复循环
_`RzPIS^ doStartTag, doAfterBody, doEndTag, release
%Xm3m0nsv{ VrG4wLpLs 带内容的标签,且内容与JSP交互
8R!3}kx doStartTag, doEndTag, release, doInitBody, doAfterBody, release
!r=^aa(\ X`xI~&t_ 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
MYVUOd, bpe8
`b(# 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
b1X.#pz7F PT2b^PP 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
"= H.$
+ >&uG1q0p. [y^)&L$= Tag库描述(简称TLD)
Zmx[u_NG !: e0cV dU!`aPL? Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
3,`.$
,.#
SEv5 TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
JGmW>mH M :m-i X 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
[,GXA)j p)
x.Y <?xml version="1.0" encoding="ISO-8859-1" ?>
b0\'JZ B@ab[dm280 <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
iEDZ\\, TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
{?a9>g-BW d<*4)MRN qF9rY)ifm <taglib>的子元素
7Pt*V@DHS $D,m o2I Element
doR'E=Z4h Description
+{%@kX<V_ +n1jP<[<N tlib-version
^iaeY
jI Tag库的版本
vBUl6EmWu OtopA) jsp-version
?nm:e.S+? Tag库所需要的jsp的版本
)p.+39]{2 >M` swEj short-name
Kd_WN;l 助记符,tag的一个别名(可选)
)G(6=l* ^V^In-[!y: uri
=hV-E
D 用于确定一个唯一的tag库
V/j]UK0$ a
S-
rng display-name
0Sz&Oguv 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
+uPN+CgQ@ Z_%}pe39B small-icon
DSwF
} 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
//--r5Q {$iJYS\ large-icon
(xU+Y1*g"% 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
{Y5h*BD> my#qmI description
Isq3YY 对tag库的描述(可选)
9Ao0$|@b ujcS>XN,1 listener
c$f|a$$b 参见下面listener元素
[7Nn%eZC
W7NHr5RC tag
7YRDQjg 参见下面tag 元素
=q|fe%# uTJi }4cw Listener元素
D#%J|| QN(f8t( 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
(4V1%0 m[^;HwJ Tag元素
=J8)Z'Jr dE5DH~ldV 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
MCma3^/1 H+zn:j@~L 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
\Rn.ug 6RZ[X[R[} Tag元素的子元素
v)JQb-< \h^bOxh 元素名称
hMJ \a 描述
)!dELS\ix <.3@-z>w2, name
tC+9W1o 独一无二的元素名
b*Ipg8n+ .<Z7K @ tag-class
a73b/_zZ= Tag标签对应的tag处理类
ej,MmLu~^ NrvS/cI!t tei-class
'4sT+q javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
BO\l>\)Ir :Puv8[1i body-content
"sFdrXJ Tag标签body的类型
Fc}wuW $2BRi@ display-name
~4}m'#! 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
e:[Kp6J P's <M small-icon
T
GMHo{] 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
89l_%To }jU{RR%6B large-icon
9[N'HpQ3 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
nVG\*#*]| NQfIY`lt' description
Vm8;{S q 此tag标签的描述
]_BG"IR!.. "EpE!jh variable
17D167\X 提供脚本变量的信息(同tei-class)(可选)
}sy3Mrb sSG]I%oB3 attribute
:yT~.AK}>1 Tag标签的属性名
gb(\c:yg1R v03~=( 以下章节介绍对于不同类型的tag,如何具体地实现它们。
tBBN62^X
(I.uQP~H Cu;X{F'H 简单的tag
q1dYiG.-Z 5, Yk5?l<' v,>F0ofJ tag处理类
aic6,>\!' {>FA ~}cX. 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
&P3B B_5q}Bp< 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
Wr)%C >mF`XbS
8KWTd public SimpleTag extends TagSupport
`?JrC3 #<'/sqL {
N83RsL "}_ :o}7C%Q8 public int doStartTag() throws JspException
x6DH0*[.
=hl-c {
$Z28nPd/ }Tc)M_ try{
`"ie57- A94VSUDA: pageContext.getOut().print(“Hello.”);
.h+<m7 YSrFHVq }catch(Exception e){
ObM5v rEk| }Pb!u9_ throw new JspTagException(“SimpleTag: “ + e.getMessage());
cjN4U [
7/7A }
Wq{' ZN 0[3b, return SKIP_BODY;
==FzkRA) X_!mZ\H7 }
/@#)j(
eY/ ]}v`#-Px( public int doEndTag()
rW\~s TH !Rb7q{@>
{
iBUf1v T[Gz return EVAL_PAGE;
609=o+ oub4/0tN,~ }
jilO% " Y6N+,FAk+J }
;?:,L >a4Bfnf"eI zV80r+y 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
U'lmQrF! |x5w;= <body-content>empty</body-content>
k6Tpaf^ !m(6/*PAl q6G([h7 带属性的tag标签