标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
7l-MVn_8 aJv+BX_, 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
g4q{
] |in>`:qk 在这篇文章中,我们主要讨论:
e}5x6t ~*3Si(4l/ · 什么是自定义tag标签?
~Qif-|[V qPz_PRje · 怎么使用tag标签?
qGN>a[D *>?N>f" o 声明要使用的tag库
4P?`<K' 8>j&) @q o 找到与之对应的tag处理类
1E!.E=Y?M ylos6]zS8 o tag标签的类型
GKEOjaE z l`m1k-X · 自定义tag标签
;yqHt!N cg^~P-i@* o tag处理类
"4xo,JUf *6<4ECa7C o tag库描述
).GM0-y
TR*vZzoy o tag标签示例
0J[B3JO@M oMYFfnoAa o 带属性的tag
&Oz 0?t;3z$n o 带body的tag
ye(av&Hn ~pH!.|k-& o 定义了脚本变量的tag
sa<\nH$_X ;~r- P$kCY o 具有协作关系的tag
4sSw7` _l]
0V
g` · 自定义tag标签
D]fgBW- .nEMd/pX o 一个迭代tag的例子
Ar~<l2,{r d]K8*a%[- o 一个模板tag库
,Gbc4x 2A|mXWG}~ o tag处理类到底是怎样被调用的?
x(Uv>k~i} #k/T\PQ0s }LS.bQKqi, 什么是自定义的tag?
+68age;dM 6qmV/DL 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
^GYVRD POc<XLZB 自定义tag标签有很多特色,诸如:
Q;l%@)m+~ N!<l~[rc · 可以在JSP页面中自定义tag标签的属性
pk'd&. uj\&-9gEi · 访问JSP页面中的所有对象
4VvE(f Y5ei:r|^ · 可以动态地修改页面输出
cGo_qR/B(> hFtjw6 · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
n|T$3j) yYe>a^r4R · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
y+$vHnS/jC wPYeKOh' "fv+}' 使用tag标签
mHW%^R= x]hG2on! v; ewMiK@E 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
qmPu D/c )gU:Up24|" 要使用tag标签,JSP程序员必须做2件事:
)bYOy+2g _qOynW · 声明此tag标签的tag库
H/ e jO_{ =Gj~:|;$ · 实现此tag标签
!Q_Kil.9 \I6F;G6 声明tag标签所在的tag库
I4ZbMnO 6^jrv [d 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
s!D?% xh<{lZ)KJ <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
3HR)H-@6@7 +3AX1o%p,# uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
QTF1~A\ -f:PgBj TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
GHLFn~z@XJ sAA;d 以下taglib指示符直接引用一个TLD:
$z)egh(z
!jEV75 <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
"p+oi@ iM9k!u FE 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
xrY >Or @o}J ) <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
<o|k'Y(- "5$p=| 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
L`O7-'` #/9Y}2G|] <taglib>
? YIe< bx6=LK <taglib-uri>/tutorial-template</taglib-uri>
6W]C` v^t oe <taglib-location>
RxV
" , w .M /WEB-INF/tutorial-template.tld
dci,[TEGu hWn-[w/l_ </taglib-location>
\%]lsml *\iXU//^) </taglib>
tNqSCjQ~_c T8*;?j*@ o9Mr7 实现此tag标签
i(e= 4u0?[v[Hu 6_rgRo& 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
JX>`N5s $%&OaAg [*C~BM tag标签类型
|z@AvS[ Y)(w&E>1 -!T24/l 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
nnu#rtvZp} ]<%NX
$9\ <tt:tag>
gd%Ho8,T +g1+,?cU body
>#T?]5Z'MF (bNoe(<qU </tt:tag>
\Q|,0` 9 ,tk ,N_V(Cx5pt 一个不带body的tag标签如下:
5[*8CY 6>&(OV <tt:tag />
bq5we*"V +>Y]1IlI By*YBZ 简单的tag标签
e !w{ap8u tk 5p@l 一个没有body和属性的tag标签如下:
.k
up[d( Y)GU{ <tt:simple />
.
Wd0}?} L"T :#> &(o&Y 带属性的tag标签
#'i,'h+F ofYZ!-V h y\iot 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
]gA2.,)}D #c/K.? 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
BOdlz#&s WkpHe <loglic:present parameter = “Clear”>
)#? K2E /
U~yYh 而另一个标签logic:iterate是用表达式来给属性赋值:
Crla~h?= i_!$bk<yo <logci:iterate collection=”<%= bookDB.getBooks() %>”
^H&`e"|R9 #?>pl. id=”book” type=”database.BookDetails”>
cnY}^_ CqX*.j{ m("KLp8 带body的tag标签
x>J(3I5_b Cnu])R 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
,HNk<W "r@G V5ED 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
$RC)e7 elD|b=(-
<logic:present parameter=”Clear”>
c4Q%MRR -Vmp6XY3q <% cart.clear(); %>
,x3<a}J VYH
$em6 <font color=”#ff0000” size=”+2”><strong>
:yw(Co]f -0k{O@l" 你选择了清除购物车!
^`$-c9M?' C(xsMO'k,, </strong></font>
#>z !ns ;c@B +RquR </logic:present>
;<F^&/a|yQ uaLjHR0 8|!"CQJ|H 到底是用属性还是用body来传递信息?
(Dba!zSs XZTH[#MqeI 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
NUuIhB+ YQ1rS X3 %r(qQM.Pl 定义脚本变量的tag标签
G]Im.x3O- vZqW,GDfXo 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
cwHbm% (@*%moo <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
?cK67|%W x.I?)x!C' <% tx.begin(); %>
@RdNAP_6 DoN]v ...
#,"[sag u0Z MrIJ 6OtNWbB 具有协作关系的tag标签
*m'&<pg]X ?|Wxqo 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
95/;II A=D
G+z'' <tt:tag1 attr1=”obj1” value1=”value” />
SK@lr }n,LvA@[0 <tt:tag2 attr1=”obj1” />
1:{+{Yl7 ZlQ&m 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
jS#YqVuN bc& 5*? <tt:outerTag>
W:8{}Iu< (r1"!~d@ <tt:innerTag />
SEM-t Pn?gB}l </tt:outerTag>
}JUc!cH8z ,OkI0[ GN+,9 Tag处理类
n(Um/ sr<\fW lI9|"^n7F Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
++|e
z{ ,L\KS^> 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
9S5C{~P4 O4^' H}* 下表说明不同类型的tag所需要不同的处理过程:
b:
I0Zv6 tCj\U+; Tag处理类的方法
@,]$FBT"5
<yw=+hz[u Tag标签类型
*M$$%G(4 所调用的方法
T I yHM1+ 1b2xWzpG 基本标签
=<P$mFP2* doStartTag, doEndTag, release
8xoC9!xt K8v@) 带属性的标签
a,xy38T< doStartTag, doEndTag, set/getAttribute1...N, release
aMxM3" ABq#I'H#@2 带内容的标签
:{-/b doStartTag, doEndTag, release
HoZsDs.XZ DeQZDY // 带内容的标签,且内容重复循环
J[\8:qE doStartTag, doAfterBody, doEndTag, release
E8aD[j[w ~x+&cA-0A2 带内容的标签,且内容与JSP交互
Saks~m7, doStartTag, doEndTag, release, doInitBody, doAfterBody, release
@|d`n\%x IL%P\Zs 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
7v`~;}5 4y,pzQ8a 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
U@}P]'`'f `mS0]/AV/ 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
7aHP;X~0 )s
?Hkn ztC,[ Tag库描述(简称TLD)
1E$^ul-v V'l9fj*E "Q[?W(SA Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
;F/w&u.n }l5Q0' TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
87R$Y> V =o[H2o
y 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
i~{ 0>"9 85:mh\@-G <?xml version="1.0" encoding="ISO-8859-1" ?>
suN}6CI uLt31G() <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
VE^IA\J x TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
X/D%
cQ6 NLev(B:OQH t2FA|UF <taglib>的子元素
*3y_FTh8ra H<l0]-S{ Element
<07~EP Description
fTi5Ej*/?) }x"8v&3CM_ tlib-version
ZP<OyX? Tag库的版本
sGGi7% cu4 |!s`# jsp-version
3nx*M= Tag库所需要的jsp的版本
58PL@H~@0 yDi'@Z9R? short-name
~AcjB( 助记符,tag的一个别名(可选)
Ro#O{ wHs4~"EY9 uri
oK2j PP 用于确定一个唯一的tag库
=^w:G =ymS 2&2t8.< display-name
#D%l;Ae 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
is{H >#+" YF)c.Q0 small-icon
oox;8d4}y 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
xp]_>WGq B~u`bn,iQ large-icon
o^x,JT 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
^:ehG9 zCj#Nfm description
5&}p'6*K 对tag库的描述(可选)
s<8|_Dt X7)B)r}AG listener
['aiNhlbt 参见下面listener元素
@.h;k4TD PLK;y tag
GO6uQ}; 参见下面tag 元素
s 5F?m ^7Z.~A y Listener元素
9@YhAj xepp."O 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
SB^xq +QEiY~i Tag元素
YvFt*t
69zMWuY 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
w[/m:R?eX ^dKtUH/78G 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
lR5k1J1n 'CvV Ktk Tag元素的子元素
2Gn26L5 @5cY5e*i{ 元素名称
1j!{?t? 描述
;sY n=r 4R9y~~+ name
+<sv/gEt 独一无二的元素名
Vd A!tL CD)JCv tag-class
{br6* Tag标签对应的tag处理类
y2>AbrJ le~p2l#e tei-class
17!<8vIV$C javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
")3$. '5Dg l
!JTM body-content
)8V=!73 Tag标签body的类型
G4J)o?:m@ n fMU4(: display-name
mfr7w+DK 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
,xy$h }g eJ60@N\A small-icon
?PU7xO;_ 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
.-cx9& D8)6yPwE large-icon
R-1C#R[ 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
+y|Q7+ B5!|L)7>{p description
'E4}++\ 此tag标签的描述
Eu$hC]w q4Y7 HE|ym variable
;r95i1a' 提供脚本变量的信息(同tei-class)(可选)
Z4D[nPm$ X=%e'P*X attribute
t+A9nvj) Tag标签的属性名
4&G
#Bi *m[[>wE 以下章节介绍对于不同类型的tag,如何具体地实现它们。
[(Ihu e H~lvUHN ZO]P9b 简单的tag
a}'dIDj d,0Klew _''9-t;n, tag处理类
k6(0:/C l6pvQ| 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
v`r*Yok;` |L(h+/>aWX 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
T<o8lL *JiI>[ qR9!DQc' public SimpleTag extends TagSupport
uevhW
X>U _v {
0G(|`xG1q *fQn!2}=( public int doStartTag() throws JspException
+RyV"&v qzii[Mf {
P$&l1Mp KDLrt try{
1i@a? 27| #F'8vf'r pageContext.getOut().print(“Hello.”);
Wn Ng3'6 =!DpW VsQ }catch(Exception e){
}[SYWJIc yhd]s0(! throw new JspTagException(“SimpleTag: “ + e.getMessage());
W@Rb"5Gy+ @81N{tg- }
* 5(%'3 TPNKvv!s return SKIP_BODY;
ev1:0P rYrvd[/*&( }
%g~zEa-g lec3rv0) public int doEndTag()
| *N;R+b N@V:nCl {
T
(?
CDc+ (9v%66y return EVAL_PAGE;
G$;cA:p-j KxQMPtHstz }
o~26<Lk &o'$uLF~Y }
=kBN&v_(! W:O p\ cue aOtD 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
8+8L'Yv; z+<ofZ(. <body-content>empty</body-content>
{pC$jd>T O6Y1*XTmH6 TEi1,yc 带属性的tag标签