标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
!D!Q]M5oU MZv In ZS 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
M1-n Y7{IF X 在这篇文章中,我们主要讨论:
@/g%l1$` aTxss:7] · 什么是自定义tag标签?
P?\ IlziCB B~G?&"] · 怎么使用tag标签?
nZ0-
Kb W c{<DE?J o 声明要使用的tag库
)k&<D*5s \GO^2&g( o 找到与之对应的tag处理类
S=*rWh8)%< g:7S/L0] o tag标签的类型
<-D>^p9 OTY9Q · 自定义tag标签
z1{kZk xrs?"]M[ o tag处理类
YKlYo~fGN9 9LI#&\lba o tag库描述
|7LhE+E s3Pr$h o tag标签示例
?Id3#+-O HZX(kYV o 带属性的tag
9nN$%(EO5; qcSlqWDk o 带body的tag
R?Vs8? G~5EAeG o 定义了脚本变量的tag
{N42z0c Z]V^s8> o 具有协作关系的tag
B4Ko,=pg ["TUSf] · 自定义tag标签
W<_9*{|E; W$>srdG0$ o 一个迭代tag的例子
5|z>_f.^pS &@p _g8r# o 一个模板tag库
[H<![Z1*r OGpy\0% o tag处理类到底是怎样被调用的?
">_<L.,I bFD
vCF @ qy
n[C 什么是自定义的tag?
q~ ]S5 ux`)jOQ`Y] 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
aDceOhfx 6O"?wN%$ 自定义tag标签有很多特色,诸如:
|Ii[WfFA|J R9@Dd · 可以在JSP页面中自定义tag标签的属性
E%8Op{zv_ /
VypN, · 访问JSP页面中的所有对象
k<(G)7'gm HI&N&a9C · 可以动态地修改页面输出
-5B>2K F (cAWT, · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
50kjX} tUU`R{=( · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
8S/SXyS *'[8FZ|dQ {BPNb{dBKr 使用tag标签
?&A)%6` ~ 69/aP= HEh,Cf7`' 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
Se~<Vpo }% 2hBl/ 要使用tag标签,JSP程序员必须做2件事:
WRrCrXP s2F<H# · 声明此tag标签的tag库
%:Mi6sR| T-,T)R`R · 实现此tag标签
^F\RM4|, l Oxz&m 声明tag标签所在的tag库
{;mT.[ t7#lRp& 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
r'*x><m' $.HZz <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
,'!x9 ` Rn?Yz^
1q uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
3lr9nBR \"k[y+O],4 TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
I
"Qf};n 8k~$_AT>u 以下taglib指示符直接引用一个TLD:
@>:V? ["O/%6b9+ <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
(B+CI%=
D Q+bZZMK5,U 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
"-
2HKs |z.x M> <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
b-!+Q) p}}pq~EH/ 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
x;N@_FZ7KY Bk)E]Fk| <taglib>
}SD*@w =f~8"j <taglib-uri>/tutorial-template</taglib-uri>
-nK\+bTL} omdoH? <taglib-location>
\G4L+Q/13 +;#z"m] /WEB-INF/tutorial-template.tld
B|I9Ex~L
Z2P DT </taglib-location>
XS#Jy
n ??5y0I6+ </taglib>
'0b!lVe n <,:;0{ 0+3_CS++r 实现此tag标签
|NMf'$ 9!XXuMWU< ce56$L8[ 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
<b.O^_zQF yj$a0Rgkv 2eC`^ tag标签类型
t@(:S6d xxy
(#j$ b?^CnMO 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
CU`yi.)T{ ]9A@iA <tt:tag>
DjLSl,Z xVnk]:c body
;15j\{r ]#NJ[IZb </tt:tag>
%>io$ o L.ML0H- ^WF/gup\hS 一个不带body的tag标签如下:
4
*n4P I@/s&$H`l <tt:tag />
JX)%iJq# wjzR 8g0bQ fvE:'( #? 简单的tag标签
n=F|bW <Jc
:a?ICe 一个没有body和属性的tag标签如下:
%VH{bpS|i: 9B)<7JJX!J <tt:simple />
6lAHB*` uD=FTx ztEM>xsk 带属性的tag标签
eo [eN. -prc+G,qyp #@UzOQ> 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
< C1Jim alp}p 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
P->.eo#VG OF1fS\P<> <loglic:present parameter = “Clear”>
af- -dyN
Ah?= 而另一个标签logic:iterate是用表达式来给属性赋值:
x=I|O;">< F1A7l"X] <logci:iterate collection=”<%= bookDB.getBooks() %>”
CT0 ~ a%YohfsY?U id=”book” type=”database.BookDetails”>
+tCNJ<S@l$ }lQ`ka ix+sT|> 带body的tag标签
.,*68S0k7 UFl+|wf 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
Jfs_9g5 I xk+y? 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
*Dhy a g o+0x1Ct3P <logic:present parameter=”Clear”>
Hx?OCGj=S* !;, Dlq-} <% cart.clear(); %>
M5Q7izM pNNvg,hS8 <font color=”#ff0000” size=”+2”><strong>
PRi1 `%d vuoD~ =z 你选择了清除购物车!
[/Vi*Z oYmLJzCf </strong></font>
7#[8td "CTK%be{q/ </logic:present>
MJ_]N+ cii!
WCu 5fvY#6; 到底是用属性还是用body来传递信息?
X3zpU7`Av+ [XbNZ6 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
2tqj]i CzfGb4 a,ZmDkzuv 定义脚本变量的tag标签
;)XB' G$oi>zt3 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
mx=2lL` Yc3Rq4I'G <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
~YQH] ZcE:r+ <% tx.begin(); %>
P*:9u> /v-:ca)7mI ...
&|YJ?}, |kc#=b@l _^MkC}8 具有协作关系的tag标签
*LOUf7` xcM*D3 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
OzA'd\| (iJ9ekB <tt:tag1 attr1=”obj1” value1=”value” />
xe@11/F M" vd/FV <tt:tag2 attr1=”obj1” />
4S1\5C9 v[XTH 2 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
|PxTm fq<JX5DER <tt:outerTag>
!m:rtPD' ,)35Vi;. <tt:innerTag />
?Rd{`5.D "pMx( </tt:outerTag>
hF^y4v|5 tl"?AQcBR yOswqhz Tag处理类
yFY:D2 ,GUOq!z /Bs42uJ3 Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
%DhM }f |))O3]- 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
.C\## jxqKPMf>@% 下表说明不同类型的tag所需要不同的处理过程:
11YpC;[o "I,=L;p Tag处理类的方法
-*[:3% ]x5+v0 Tag标签类型
SIZZFihcYh 所调用的方法
h,zM*z A_ l4$Iv: 基本标签
/i)>|U
4 doStartTag, doEndTag, release
N~|Z@pU" X" Upml 带属性的标签
ybU_x doStartTag, doEndTag, set/getAttribute1...N, release
c^1tXu|& Xe2Zf 带内容的标签
)skz_a}]8 doStartTag, doEndTag, release
BcxALRWE "cz'|z` 带内容的标签,且内容重复循环
I7XJPc4} doStartTag, doAfterBody, doEndTag, release
?egZkg=U
Q N]y.(S)y 带内容的标签,且内容与JSP交互
"'74GY8, doStartTag, doEndTag, release, doInitBody, doAfterBody, release
'!<gPAVTzV jSMxb a] 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
8(>2+#exw @!Rklhb 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
)F_nK f"a u';9zk/$ 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
./35_Vy/O 5tl($j =K<`nF0w Tag库描述(简称TLD)
F%IvgXt5 F R(k==pZ 2EiE5@ Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
$X,dQ]M TW6F9}'f& TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
+~$pkxD" G^Va$ike 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
Mp?L9 GK=b <?xml version="1.0" encoding="ISO-8859-1" ?>
Xp[x O 0 Z;y(D_;_ <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
HCw,bRxm TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
h+ <Jv ckYT69U N6HeZB": <taglib>的子元素
~P BJ~j+G rXR!jZ.hi Element
g OK Description
$`[TIyA9! DY\~O tlib-version
GH \
Sy Tag库的版本
=O3)tm; yoH,4,! G jsp-version
MML=J~1 Tag库所需要的jsp的版本
%-woaj /2'l=R5# short-name
A(*c|Aj9 助记符,tag的一个别名(可选)
E>iN > *x:*Q \| uri
?I$- im 用于确定一个唯一的tag库
c2gi3 %j@@J\G! display-name
t:"3MiM=c 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
hp`ZmLq/[ jyB
Ys& v small-icon
DTlId~Dyq 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
d ehK#8 Xe&p.v large-icon
qKrxln/T 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
EbG&[v @H8DGeM description
On|b- 对tag库的描述(可选)
5z&>NI 6Ad C listener
1obajN 参见下面listener元素
~=Q^]y, Sc]G7_ tag
/0o#V-E) 参见下面tag 元素
~+C)0Yn XZ@|(_Z Listener元素
*M/:W =,t &?$mS'P 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
aS``fE;O |`xM45 Tag元素
RO@=&3s hd]ts. 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
R?IRE91 : Y?3f
Fg 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
[+_>g4M~% a`R_}nus* Tag元素的子元素
]tzF
Ob 7pou(U 元素名称
*`8JJs0g 描述
FA+"t^q \!xCmQ name
hI9q);g 独一无二的元素名
|Sm/s;&c6 &isKU8n
tag-class
-
AU{Y`j Tag标签对应的tag处理类
H~^)^6)^T '/)qI. tei-class
}m'n1tm;
javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
a|jZg oKCv$>Y body-content
K:^0*5Y-k Tag标签body的类型
skBD2V4 oEX^U4/= display-name
b;%t*?t 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
NWP!V@WG a{@}vZx>3 small-icon
|B^Mj57DO 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
tHAe L^r & .N\ large-icon
}8POm# 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
NJ]3qH Y%eq2% description
C$0g2X 此tag标签的描述
~d].<Be i(_A;TT6 variable
l&}}Io$?@
提供脚本变量的信息(同tei-class)(可选)
{VKFw=$8 4"_`Mu_% attribute
=~k
c7f{ Tag标签的属性名
zgH(/@P U`lK'.. 以下章节介绍对于不同类型的tag,如何具体地实现它们。
tU5uL.( O dt^h9I2O fvcS=nRQv 简单的tag
?^M,Mt |Fi5/$S. 1`YU9? tag处理类
g`%in cP D_=.& 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
&w#! j:xC\b47" 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
?C#E_ ~MBPN4r #c5jCy}n public SimpleTag extends TagSupport
N+h05` Pc_aEBq {
D}q"^"#T "4;nnq public int doStartTag() throws JspException
_'LZf=V0 -(t7>s {
/("7*W 2 ;8eKAh try{
d&[RfZ` ]%)<9]} pageContext.getOut().print(“Hello.”);
Qr9;CVW kQ lU.J>^ }catch(Exception e){
fT|A^ UXs)$ throw new JspTagException(“SimpleTag: “ + e.getMessage());
xC,x_:R` bh<;px- }
Vv45w#w; +.Ij%S[Px5 return SKIP_BODY;
e=WjFnK[x7 PO`p.("h }
C+llA }Nsdk',} public int doEndTag()
D%abBE1 USEb} M` {
lQ-<T<g Jsysk $R return EVAL_PAGE;
!R"W2 Z4h \gk.[={^P }
-}9^$}PR TK
fN`6 }
*y!O\-\S#> })H d]a !:^q_q4 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
O=A2QykV( <;6{R#Tuh <body-content>empty</body-content>
@ M]_], "FWx;65CR p 1'l D 带属性的tag标签