标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
<tTNtBb o
Rk 'I 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
;
]%fFcy $!G|+OuTR 在这篇文章中,我们主要讨论:
1N _"Mm{
[uqr · 什么是自定义tag标签?
}%wP^6G*x\ E7h@c>IK · 怎么使用tag标签?
7V=deYt_p h(q4
B~ o 声明要使用的tag库
lg-`zV3 KD#zsL)3 o 找到与之对应的tag处理类
>;G_o="X L`M{bRl+1 o tag标签的类型
oa+'.b~ ui8$ F
"I* · 自定义tag标签
<8%+-[(
GX19GI@k o tag处理类
~C
3Y/} q#Otp\f o tag库描述
q:up8-LAr MV<)qa T o tag标签示例
VKXi*F9 2pHR $GZ2 o 带属性的tag
LL:N/1ysG ;xTMOuI* o 带body的tag
?}^ y6 ,%m~OB# o 定义了脚本变量的tag
dT1UYG}>j XH0{|#hwN o 具有协作关系的tag
DDIRJd<J "c~``i\G · 自定义tag标签
zhE4:g9v q:vN3#=^qf o 一个迭代tag的例子
n"iaE $igMk'%Nmb o 一个模板tag库
ZK{1z| w2 (}pz: o tag处理类到底是怎样被调用的?
unYPvrd &VjPdu57 U#Kw+slM 什么是自定义的tag?
0* ^f
EoV :;#^gvH 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
n>^9+Rx|i 78T;b7!-C 自定义tag标签有很多特色,诸如:
zGO_S\ ;,/G*`81B · 可以在JSP页面中自定义tag标签的属性
P[`>*C\9c p^{yA"MQ · 访问JSP页面中的所有对象
8oHIXnK E]{0lG`l · 可以动态地修改页面输出
T8LvdzS \8Ewl|"N:u · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
S]ndnxy"b HU
+271A8 · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
zxv y& 9[E/^
WFug-#;e 使用tag标签
V!e`P Q\~#cLJ/
ieEtC,U 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
ENYc.$r w0>5#jq#r 要使用tag标签,JSP程序员必须做2件事:
f:t5`c. @uxg;dyI~ · 声明此tag标签的tag库
^s8JW" H |c]L]PU · 实现此tag标签
BH^cR<<j Dxr4B< 声明tag标签所在的tag库
q<g!bW% }D~m%%, 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
&@&^k$du8q ='/#G0W <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
Y% [H: &6Wim<* uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
jN+2+P%OL mh_GYzd TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
\bSakh71 H/#WpRg 以下taglib指示符直接引用一个TLD:
/{ 8 .Jcx$ )]}68}9 <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
=:RNpi, :d~&Dt<c 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
x6yO2Yo b!;WF
<%@ taglib uri=”/tutorial-template” prefix=”tt” %>
4=ha$3h$ YBk* CW9 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
uvD*]zX '(:R-u!pp <taglib>
j;rxr1+w z\IZ5' <taglib-uri>/tutorial-template</taglib-uri>
,+_gx.H2j >&qaT*_g <taglib-location>
3A b_Z /P{'nI /WEB-INF/tutorial-template.tld
0pe*DbYP5 mc6W" </taglib-location>
s[*I210 F.R0c@&W </taglib>
aOW~! f/M XOY\NMo m`3gNox 实现此tag标签
VS<w:{* QRY7ck:N &4F
iYZ 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
;xE1#ZT TP/bPZY ^6^A/]v tag标签类型
B{_-k u z>V 1w?DSHe 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
Z5>} !:dhK <tt:tag>
zU>bT20x/ 8x6{[Tx
body
ViG-tb gG6BEsGa, </tt:tag>
BG@[m ]FO)U xHwcP2 1 一个不带body的tag标签如下:
cNuBWLG C'0=eel[ <tt:tag />
I*
JSb9r yi1V \8DC ML_[Z_Q<z 简单的tag标签
U[l{cRT
7vsXfIP+ 一个没有body和属性的tag标签如下:
(@u" v%2Jm!i+ <tt:simple />
o7 X5{ m[*y9A1 UXV>#U? 带属性的tag标签
cX-)]D /SYzo4( WO6; K] 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
A&;Pt/#' K"ytE2:3 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
RjQdlr6* r)t-_p37 <loglic:present parameter = “Clear”>
>!2d77I N u9+b"Wr 而另一个标签logic:iterate是用表达式来给属性赋值:
7tz#R:
N]@e7P'9F <logci:iterate collection=”<%= bookDB.getBooks() %>”
'WQ<|(:{ v/DWy(CC id=”book” type=”database.BookDetails”>
5-X(K 'Q |h1Y3 syLpnNx= 带body的tag标签
E?P:!V=_ Ra?0jcSQ$ 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
<</
Le% qc`UDD5 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
H;eOrX{GT VYN1^Tp <logic:present parameter=”Clear”>
ns[Q %_ W_N!f=HW <% cart.clear(); %>
4wQ>HrS)( Gj([S17\0: <font color=”#ff0000” size=”+2”><strong>
CpF&Vy K S~LTLv:> 你选择了清除购物车!
|G]M"3^ s;-%Dfn </strong></font>
\?.Tq24 @#5PPXp </logic:present>
#>\+6W17U v5o@ls VjVL/SO/ 到底是用属性还是用body来传递信息?
%7bZnK`C ]):kMRv 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
<oWoJP`G DN;An0
{MK ?rgk 定义脚本变量的tag标签
^aG=vXK`b gkyv[ 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
&-0eWwMW {$mj9?n=v <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
i.`RQZ$,/ SLG3u;Ab <% tx.begin(); %>
.)eX(2j\ ^d2bl,1 ...
h
.$3jNU C6C7*ks "ewB4F[ 具有协作关系的tag标签
q9&d24| kdrya 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
M%8: h0fbc;l <tt:tag1 attr1=”obj1” value1=”value” />
UF00K1dbz FWbA+{8 <tt:tag2 attr1=”obj1” />
0vRug|}k#% aGz<Yip 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
UE9r1g`z b 64~Y|8 <tt:outerTag>
l1qWl = ,=t Sp <tt:innerTag />
y$e'- v h[O!kwE </tt:outerTag>
<2a7>\74E0 Vi~F
Q Y"&c . Tag处理类
CL$mK5u tCdgtZm jci'q=Vpu Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
&v^LxLt+s E}$K&<J'- 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
-l!;PV S| QDC]g.x 下表说明不同类型的tag所需要不同的处理过程:
kEQ${F{ @: s |X Tag处理类的方法
>aZ$x/U+Iw QxmVImn" Tag标签类型
FFNv'\) 所调用的方法
|h,aV(Q +FoR;v)z=F 基本标签
t3 q0|S doStartTag, doEndTag, release
IRZ?'Im ;?9u#FRtw 带属性的标签
|'2E'?\/x doStartTag, doEndTag, set/getAttribute1...N, release
hfGA7P" <,Zk9 t& 带内容的标签
v?\bvg\E doStartTag, doEndTag, release
@Ooh}V#J &zF1&J58z 带内容的标签,且内容重复循环
DaW_-:@s doStartTag, doAfterBody, doEndTag, release
24Y~x`W 'lU9*e9 带内容的标签,且内容与JSP交互
@,-xaZ[ doStartTag, doEndTag, release, doInitBody, doAfterBody, release
!=.5$/ k.DDfuKN 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
uSs~P%@6| GJA3 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
,OLN%2Sq ^AUmIyf_ 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
[Uezi1I pt;kN&A^ Ve&(izIh Tag库描述(简称TLD)
@^vVou_ X}yEMe{T XY5I5H_U Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
J0}OmNTzD 7 3k3(rZ TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
Aov=qLWJ u8*Uia*vwH 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
t`DoTb4 '(kySf[ <?xml version="1.0" encoding="ISO-8859-1" ?>
h{]l?6` ti'a^( <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
zb}:wUR TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
>sP-)ZeuU[ 33\{S$p @fp(uu <taglib>的子元素
)jp#|#h B_[^<2_ Element
'Z-jj2t} Description
oSt-w{! 6ZVJ2xs[% tlib-version
!9i,V{$c`" Tag库的版本
JQ%`]=n(/ Z^AACKME jsp-version
">kfX1LT Tag库所需要的jsp的版本
/r|^Dc Nx 6tM CpSJ short-name
#5T+P8 助记符,tag的一个别名(可选)
{vAq08 a Kb2:1EQ uri
"j9,3yJT 用于确定一个唯一的tag库
JLRw`V,o7 s} ,p>8 display-name
:?{ **&= 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
Nl7"|()e Fk>/ small-icon
b:>(U. 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
7vV3"uns
8J%^gy>m] large-icon
dKw*L|5 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
r}9qK%C G. 4)iSz> description
:t]YPt 对tag库的描述(可选)
Fy<dk}@ koC2bX listener
)k3zOKZ; 参见下面listener元素
K!k,]90Ko TC3xrE:U<m tag
mz[rB|v"/7 参见下面tag 元素
w/N.#s^ 9xC,i
) Listener元素
ZYrXav< `w]=xe 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
&M~*w~w` 8(D>ws$
Tag元素
w@4q D uA:|#mO 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
?K{CjwE.M ycRy!0l 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
x+"~-KO8q$ !tFs(![ Tag元素的子元素
vKDRjrF- [z`U9J 元素名称
_5.^A&Y* 描述
yuk64o2QE a>Uk<#>2?a name
]~ )FMWQz- 独一无二的元素名
_odP: /_?Ly$>' tag-class
6Ez}A|i Tag标签对应的tag处理类
zMKW@ s*:J=+D]G tei-class
VLN=9 javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
mTW0_!. Ip(
IGR" body-content
S?*v p= Tag标签body的类型
N|T%cdh:/ H
|Z9]+h)7 display-name
t*82^KDU 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
Ezm ~SY .ev'd&l. small-icon
B+wSLi( 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
Io{)@H"f
s<xD$K~rM large-icon
W j/.rG&tE 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
$k V^[ }f<.07 description
ykxjT@[ 此tag标签的描述
2md1GWyP 8k]'P*9ulz variable
fEWS3`Yy 提供脚本变量的信息(同tei-class)(可选)
r~z-l, sbrU;X_S attribute
x;l\#x/< Tag标签的属性名
y|nMCkuX 9PVM06
以下章节介绍对于不同类型的tag,如何具体地实现它们。
M$
`b$il 7Nw7a;h j{IAZs#@> 简单的tag
gpe^G64c` IR?ICXmtx qXkc~{W_ tag处理类
HjbC>* 0~H(GG$VH 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
vL`wn= OO]~\j 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
&p^S6h N't*e Ci kz(%8qi8& public SimpleTag extends TagSupport
S`BLwnU`# +eZR._&0 {
M ZB0vdx +iir]"8 public int doStartTag() throws JspException
vX]\Jqy 5v=%pQbY {
`ux
U
H# .ZFs+8qU> try{
n@mWBUM H*!j\|v0 pageContext.getOut().print(“Hello.”);
=4"D8UaHr Bl2y~fCA }catch(Exception e){
5 .
5 fKf5i@CvB@ throw new JspTagException(“SimpleTag: “ + e.getMessage());
G \?fWqx Y5$5qQ }
j08}5Eo 0"(5\T return SKIP_BODY;
t(-noy) GN /]^{D }
PCH&eTKN RRqHo~*0 public int doEndTag()
)dbi W^ict,t {
nKp='>Th Vz!W(+ return EVAL_PAGE;
!krbGpTVH ce\]o^4 }
p3`'i 6&S;Nrg9 }
(n05MwKu\ D+]#qS1q CDQ}C=4 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
YQvN;W y~w2^VN= <body-content>empty</body-content>
w7$*J:{ Q9H~B`\nQ D'F=v\P 带属性的tag标签