标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
R:A'&;S -#aZF2z 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
:#{-RU@PS (/K5! qh 在这篇文章中,我们主要讨论:
D`Gt x=-0 zV · 什么是自定义tag标签?
=EW3&+Lt ?;
[ T · 怎么使用tag标签?
5`~mqqR5 ?E<c[*F05 o 声明要使用的tag库
QH~Jy*\+PX G>%AZr{M o 找到与之对应的tag处理类
j0FW8!!-g 3B{[%#vO o tag标签的类型
7^MX l d+6]u_J · 自定义tag标签
;i\C]* )~V}oKk0t o tag处理类
5Z{_m;I. jWvtv ng o tag库描述
B'}"AC" B3mS] o tag标签示例
\D?:J3H*] LkBZlh_ o 带属性的tag
#~k[ 6YR 0 >)Gd:636+ o 带body的tag
+`.,| |Mq F;u_7OM o 定义了脚本变量的tag
x=]S.XI -U-P}6^ o 具有协作关系的tag
IU#x[P! ?TpUf · 自定义tag标签
/ p)F>WR &[_ZXVva~ o 一个迭代tag的例子
P~RhUKfd & Kmy}q
o 一个模板tag库
yNa;\UF ^Kqf~yS% o tag处理类到底是怎样被调用的?
Au.:OeJm eA=WGy@IcN YEv
Lhh 什么是自定义的tag?
#`ls)-`7 _KN/@(+F 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
m`6VKp{YD [i7YVwG4 自定义tag标签有很多特色,诸如:
qu~X.pW zizk7<?L. · 可以在JSP页面中自定义tag标签的属性
lY'N4x7n oNM?y:O · 访问JSP页面中的所有对象
}`o?/!X p|qyTeg · 可以动态地修改页面输出
;YyXT"6/p KX3KM!* · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
`8:K[gp s-rfS7; · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
=X1?_~} ;..o7I 1 ] #9
使用tag标签
G[Tl%w *1A&'T2 a#0;==# 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
3fr ^ T OgCy4_a[f 要使用tag标签,JSP程序员必须做2件事:
" aq'R(/`c p&N#_dmlH · 声明此tag标签的tag库
".U^ifF riCV&0"n · 实现此tag标签
Br5o7(AE ,^$|R32 声明tag标签所在的tag库
(\,BxvhG= #E$X,[ZFo 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
#0"~G][# +(?>-3_z <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
UBZ9A >#(n"RCHf uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
!HK^AwNY #=,imsW) TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
nJZ6?
V 6bO~/mpWT~ 以下taglib指示符直接引用一个TLD:
a~]bD 'g)n1 { <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
U|@V
74 h7yqk4'Lq 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
e3[:D5 T~xwo
<%@ taglib uri=”/tutorial-template” prefix=”tt” %>
3
hKBc0 oxz{ ejd{ 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
kc$)^E7 r"{<%e <taglib>
pyZ9OA!PD o[\HOe~; <taglib-uri>/tutorial-template</taglib-uri>
p9qKLJ*.C $m| V :/ <taglib-location>
d8o53a] NHQF^2 \\ /WEB-INF/tutorial-template.tld
kkCZNQ~I X~9j$3lUBR </taglib-location>
HU ;#XU1 {~Tg7<\L </taglib>
qu|i;WZE ,h]o> g"_C,XN 实现此tag标签
<skajQQ oG oK, Shr,#wwM`B 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
FnFb[I@eu G"SBYU {zLhiUH
a0 tag标签类型
NjuiD]. R^#@lI~ tt_o$D~kg 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
SA"p\}"
<|B1wa:| <tt:tag>
MCTsi:V>+ \nqkA{;B{ body
kOL'|GgK DKL@wr}8 </tt:tag>
Cby;?F6w B%s7bS s1N?/>lmB 一个不带body的tag标签如下:
t=
#&fSR 0&+k.Vg <tt:tag />
9xI GV! 'tgKe!-@ hqvE!Of 简单的tag标签
H}}$V7]^), J3RB]O_ 一个没有body和属性的tag标签如下:
7[#yu 2 A^ \.Z4=d" <tt:simple />
;,h/
%ysZ5:X CY:d`4 带属性的tag标签
YZf6| &[vw 0N- (2ot5x}`j 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
Sjj>#}U =8Jfgq9E 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
=T?}Nt :M3oUE{ <loglic:present parameter = “Clear”>
-Apc$0ZsN }L=/A7Nk> 而另一个标签logic:iterate是用表达式来给属性赋值:
{7hLsK[]) sic"pn],U <logci:iterate collection=”<%= bookDB.getBooks() %>”
BaI $S>/Q Ws U)Y& id=”book” type=”database.BookDetails”>
4R^mI
uF|3/x= n.MRz WJpZ 带body的tag标签
)- 15 N S0,R_d') 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
CqMhk Cwa^"r3P1 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
(& "su3z ipnV$!z <logic:present parameter=”Clear”>
HAz By\M{ 2jJmE&)7, <% cart.clear(); %>
s9;#!7ms tc;'oMUP <font color=”#ff0000” size=”+2”><strong>
!^#jwRpeN |y;}zQB-dH 你选择了清除购物车!
\*hrW( PX:'/{V </strong></font>
B(a-k? v4,h&JLt </logic:present>
?lGG|9J\ F_iXd/ -&x2&WE' 到底是用属性还是用body来传递信息?
8
;d$54
b {R<Ea
@LV+ 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
>zsid:
/-_=nf}w x5`br.b 定义脚本变量的tag标签
H`bSYjgM! K%<j=c 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
K;?,FlH <~ad:[ <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
6fH@wQ"wN q\Q{sv_ <% tx.begin(); %>
(/!r(#K0,' #4MBoN(3 ...
<9E0iz+j ptatzp]c# 5Wyz=+?m| 具有协作关系的tag标签
qf@q]wtar 8KB>6[H!wE 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
sQ6}\ <~}7Mxn%x@ <tt:tag1 attr1=”obj1” value1=”value” />
M#"524Nz 4a0:2 kIKa <tt:tag2 attr1=”obj1” />
7Dzuii?1 !-2R;yo12 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
'j^xbikr ]V %.I_ <tt:outerTag>
D0k
8^ e0@6Pd <tt:innerTag />
n55Pv3}C v(*C%.M) </tt:outerTag>
h~&gIub UDhG : =9oPowq Tag处理类
I}e3zf> i|w8.}0 ]2# Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
~!s-o|N_\ $vHU$lZ/W 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
Zfk*HV#\ R1nJUOE4w^ 下表说明不同类型的tag所需要不同的处理过程:
]{"Br$ LmlXMia Tag处理类的方法
E$W{8?:{ Y2xL>F Tag标签类型
@L.82p{h 所调用的方法
A(?\>X
9g 1(|D'y# 基本标签
IG(?xf\C doStartTag, doEndTag, release
X37 L\e[c ,yd
MU\so( 带属性的标签
]| N3eu doStartTag, doEndTag, set/getAttribute1...N, release
^~{$wVGa a+hd(JX0~ 带内容的标签
o]nw0q?
doStartTag, doEndTag, release
`cPywn@uGZ -':Y\:W 带内容的标签,且内容重复循环
Hzrtlet doStartTag, doAfterBody, doEndTag, release
[:xiZ ~m|Mg9- 带内容的标签,且内容与JSP交互
KIR'$ 6pn~ doStartTag, doEndTag, release, doInitBody, doAfterBody, release
M?= ;JJ: da1]mb=4 5 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
GN KF&M uB!kM 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
2H.654 jp $Z] 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
763+uFx^ &/Ro lIHF K3\#E/Ox Tag库描述(简称TLD)
gp$Ucfu' 2o>)7^9|#< 83;NIE; Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
}FzqW*4~ WL` 9~S TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
\*,=S52 }g$(+1g 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
G^q3Z#P gM [w1^lj <?xml version="1.0" encoding="ISO-8859-1" ?>
m*$|GW9 ]f]<4HD=i <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
8/0Y vh TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
*3T|M@Y h" H2z1$ k}KC/d9.z <taglib>的子元素
YeF1C/'hy hJzxbr
< Element
<hwy*uBrD Description
a0Ik`8^` E*# ]** tlib-version
jy]JiQB Tag库的版本
6a;v&5 FQ>`{%> jsp-version
N}\[Gr Tag库所需要的jsp的版本
q>w)"Dd ^
wY[3"{ short-name
<>m }}^ 助记符,tag的一个别名(可选)
!QDQ_ K}=|.sE9 uri
#2`D`>7456 用于确定一个唯一的tag库
1SrJ6W @j[ -=.V
' display-name
?<6CFH] 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
l4TpH|k wH~kTU2br small-icon
3Vp#a: 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
V/LQ<Yke xoOJauSX1 large-icon
U%h);!< 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
xQw7 :18wQ V7TVt,-3 description
WD'#5]#Y 对tag库的描述(可选)
N{-]F|XX 8ssJ<LP listener
c\% r38 参见下面listener元素
"zIFxDR# ?BhMjsy. tag
P>9aI/d9 参见下面tag 元素
WcC?8X2 JWA@+u*k Listener元素
p$ bnK] [frq
'c 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
",{ibh)g$` M)sZSH.<O Tag元素
3pmWDG6L MLFKH 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
0(_l|PScF >a3p >2 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
V5 U?F6 >J u]2++lx Tag元素的子元素
:_Eqf8T Jk0r&t7 元素名称
pIbdN/z 描述
wO2_DyMm@ waKT{5k name
"QvmqI> 独一无二的元素名
QMEcQV> (|wz7AY2 tag-class
S~]mWxgZ Tag标签对应的tag处理类
z"*/mP2 7z~_/mAI tei-class
-R{V- javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
h[Gg}N! c*UvYzDZL body-content
qH['09/F6 Tag标签body的类型
`Y?87f:SP <, 3ROo76 display-name
-gQCn>" 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
vky .^ A{B/lX) small-icon
0zY(:;X 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
w>b-} t b~-%c_ large-icon
<9>vO,n 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
g R
nOd t#!yrQ..'G description
sZ?mP;Q 此tag标签的描述
@,XSs 2 1PFR:lP7 variable
Mkq( T[) 提供脚本变量的信息(同tei-class)(可选)
~n}k\s~|4 :$+-3_oLMQ attribute
@|'5n Tag标签的属性名
S(:l+JP t20PP4FWM 以下章节介绍对于不同类型的tag,如何具体地实现它们。
.UoOO'1K ZIdA\_c -[L!3jU 简单的tag
;l$ \6T 1n\ t+F _e9:me5d"$ tag处理类
pStk/te,XK ]\ngX;h8G 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
(LHp%LaZ\; 4`Ic&c/ 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
S>.F_Jl fg#x7v4O ly WwGR public SimpleTag extends TagSupport
~zHg[X*
fh^lO ^ {
MQ)L:R`L sdCvG R e public int doStartTag() throws JspException
P=1I<Pew `mT$s,:h {
s}j1"@ 7OWbAu; try{
~afg)[( q$G,KRy/ pageContext.getOut().print(“Hello.”);
jgS%1/& KN"S?i]X }catch(Exception e){
T;L>P[hNn hm<}p&!J throw new JspTagException(“SimpleTag: “ + e.getMessage());
34!dYr% RI2f`p8k }
'Peni1_ Nm):9YQ/ return SKIP_BODY;
Z/rTVAs@r #yI.nzA* }
"n:{!1VGw )etmE public int doEndTag()
s( <uo{ D#S\!>m {
6!^[];%xN 8P:
Rg%0) return EVAL_PAGE;
jPnM>= }3R13 }
XYoIFv?' RllY-JBO }
;WL1B 6WoAs)ZF 7*DMVok: 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
1}ZKc=Pfu `pd&se'p <body-content>empty</body-content>
Yl;^ k0ZI w;v7_ d*pF> j 带属性的tag标签