标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
c_RAtM<n o;^k"bo6 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
UbDRE[^P XW2{I.:in> 在这篇文章中,我们主要讨论:
%aHQIoxg [\|p~Qb)s · 什么是自定义tag标签?
-h|YS/$f V9SkB3-' · 怎么使用tag标签?
TM?RH{(r >ow5aOlQ& o 声明要使用的tag库
>oOZDuj c
c^I9g~ o 找到与之对应的tag处理类
.~L^h/)Gjy s${|A= o tag标签的类型
Q9C;_Up fdCN?p[_ · 自定义tag标签
/P}Wp[)u 7L"Pe'Hw o tag处理类
z~ R: !O- oDvE0"Sz o tag库描述
0DIXd*oj & So^;5tG o tag标签示例
A@HCd&h y G{;kJ P o 带属性的tag
fg8"fbG`: O&(@Ka o 带body的tag
B+w< 0No ^XbN&'^,HL o 定义了脚本变量的tag
__Tg1A 99]&Xj o 具有协作关系的tag
a{deN9Qn m-h+UKt · 自定义tag标签
g,,'Pdd7Pn <6(&w9WY o 一个迭代tag的例子
J<'7z%2w nTd[-3o o 一个模板tag库
N7WQ{/PSG F\"`^`(O o tag处理类到底是怎样被调用的?
tI-u@
g %=t8 fkjo 什么是自定义的tag?
(='e9H!3D /GQN34RD 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
b+rn:R LE1#pB3TG 自定义tag标签有很多特色,诸如:
`r$c53|<u u+
?Wm40E · 可以在JSP页面中自定义tag标签的属性
FWJhi$\:D] ;xKPa6`E · 访问JSP页面中的所有对象
y))) {X =Co[pt · 可以动态地修改页面输出
/ ~\ I "-U`E)]w*[ · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
D+u#!t[q d2!A32m · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
^zs]cFN#% 3{j&J- <8[y2|UBt 使用tag标签
{"x>ewAf ~s[St0 + yF._Ie= 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
sPod)w?e zx7g5;J 要使用tag标签,JSP程序员必须做2件事:
!9/1_Bjv )8rN · 声明此tag标签的tag库
2VgDM6h e~+VN4D&b> · 实现此tag标签
jwe^(U F^mMyK 声明tag标签所在的tag库
{f9jK@%Gy NPFrn[M$ 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
9AGf4tuy j18qY4Gw) <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
0<{zW%w qyx
' uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
JTw3uM, e 9t1aR*b&@ TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
mK>c+ u) Gop;!aV1* 以下taglib指示符直接引用一个TLD:
l?AWG& 7P!Hryy <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
n.a55uy wy1xZQ<5 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
QS*!3?% -ST[!W V <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
#:5vN-9? {);S6F$[3 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
\U0p?wdr: z
TM1 e <taglib>
;Rz+4< QQB\$[M!Z <taglib-uri>/tutorial-template</taglib-uri>
'|9fDzW"] @
z{E <taglib-location>
Jp0*Y-*Y ')8c /WEB-INF/tutorial-template.tld
S"/M+m+ ] (eOzntp8 </taglib-location>
yd-r7iq !5/jDvh
</taglib>
SR4cR)Iz p7\}X. L D(m2^\O[ 实现此tag标签
U1Z.#ETnM ?0{8fGM4 R43yr+p 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
L~,x~sLd *gJ:irah |fJpX5W-l tag标签类型
aMxg6\8 IC1oW) e)Be*J]4 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
@-7h}2P Q 2itJD1; <tt:tag>
xUiSAKrcM 7B|ddi7Q> body
U^ecg{ !c;Z<@ </tt:tag>
DvBL#iC (zVT{!z H\zV/1~Y 一个不带body的tag标签如下:
&L88e\
c+ l;N?*2zm[ <tt:tag />
KfSI6
Y_ 0""t`y& .d^XM 简单的tag标签
U]aH4N *gq~~(jH 一个没有body和属性的tag标签如下:
+/bT4TkML d3$*z)12` <tt:simple />
W+F^(SC\ rv75R}.6R^ MDHTZ94\Q 带属性的tag标签
!rK,_wH
O?6ph4' Au-_6dT 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
oi@hZniP? J6WyFtlyLc 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
:sf(=Y.qA (}]ae* <loglic:present parameter = “Clear”>
Gu3# y"a> |f:1Br 而另一个标签logic:iterate是用表达式来给属性赋值:
*8ZaG]L !\)9fOLs <logci:iterate collection=”<%= bookDB.getBooks() %>”
i]>)'i @v#]+9F id=”book” type=”database.BookDetails”>
F%Xj'= o=&tT,z 7$z]oVbO' 带body的tag标签
kp{q5J6/ $CgJ+ua\8 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
B
66-l!xa $KmhG1*s 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
]TE,N$X D2060ze <logic:present parameter=”Clear”>
'@{'T LMCi L.cGt"{ <% cart.clear(); %>
(jV_L1D 5._=m"Pl <font color=”#ff0000” size=”+2”><strong>
c{qoASc? T6P9Icv?@7 你选择了清除购物车!
I6jDRC0< _o'3v=5T </strong></font>
'Q^P#<< uT#MVv~ . </logic:present>
b?=>)':f j06Xz\c Zx1 I&K\Cd 到底是用属性还是用body来传递信息?
x]6wiV /5PV|onO 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
*c0\<BI $bGe1\ T%opkyP>= 定义脚本变量的tag标签
bG'"l qn y[pU8QSt 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
SWrt 4G |%i|P)] <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
2I!L+j_ >z,SN <% tx.begin(); %>
wG,"ZN m^9[k,;K ...
"1-|ahW ThvVLK Q9\6Pn ]T 具有协作关系的tag标签
`;:zZ8* RfZZqeU 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
-kv'C6gB p5`d@y\hj <tt:tag1 attr1=”obj1” value1=”value” />
;)SWUXa;{ qMA K"%x <tt:tag2 attr1=”obj1” />
r
N.<S[ ]Zj6W9]m 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
W{{{c2 . GOzV# <tt:outerTag>
_F"o0K!u Py3Y*YP <tt:innerTag />
9uRs@]i +pq/:h </tt:outerTag>
V*|#j0}b s-z*Lq* ?11\@d Tag处理类
?9?eA^X% .2si[:_(p M[Kk43;QY! Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
dWCU Z,6} l$:.bwXXO 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
l5}b.B^w mp\`9j+{ 下表说明不同类型的tag所需要不同的处理过程:
8:iu 8c$ xD(RjL+ Tag处理类的方法
syseYt] ~I+}u]J Tag标签类型
v+3-o/G7 所调用的方法
H/eyc` 8" x+^ 基本标签
)R QX1("O doStartTag, doEndTag, release
TC2gl[ oQkY@)3.w 带属性的标签
\w]c<gM K doStartTag, doEndTag, set/getAttribute1...N, release
vE9M2[TJA "DW; 6<m 带内容的标签
pxF<L\L?: doStartTag, doEndTag, release
vfh0aW-O !Gphs`YI 带内容的标签,且内容重复循环
`wyX)6A|bt doStartTag, doAfterBody, doEndTag, release
zeXMi:X ^aW?0qsH 带内容的标签,且内容与JSP交互
xSQ0] vE doStartTag, doEndTag, release, doInitBody, doAfterBody, release
4/Vy@h"A3 WdA6Y 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
&.\|w Vs)%*1>< 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
'm;M+:l
6 'k9?n)<DW 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
a-`OE" pY3N7&m\: #&@qmps(T Tag库描述(简称TLD)
bi fi02 `VT0wAe2; 2Qoj>Wy{ Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
yrDWIU(8;6 '.@'^80iQ TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
u#+p6%?k >PsP y. 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
~dIb>[7wy 8tc9H}> <?xml version="1.0" encoding="ISO-8859-1" ?>
Kb_R "b3v CIM9~:\ <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
3X+uJb2 TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
bb6
~H _{EO9s2FG u5f+%!p <taglib>的子元素
(1bz.N8z dYg}qad5: Element
I5"ew=x# Description
728}K^7: -DO*,Eecv tlib-version
u_aln[oIv Tag库的版本
kRs24= 3:$hC8 jsp-version
Jmb [d\ /D Tag库所需要的jsp的版本
\WM*2& lu^c^p; short-name
lN,8(n?g 助记符,tag的一个别名(可选)
2a;vLc4 {cF7h)j uri
i<g|+}I 用于确定一个唯一的tag库
9Z0(e!b4S )x.}B4z display-name
bQ-5uFe~$B 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
8#%p[TLj +#5nk,1c> small-icon
29"eu#-Qj 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
XA~Rn>7&H Kp*nOZ large-icon
"C$z) 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
NF1e>O:a< dbkccO}WB description
a1p:~;f}[ 对tag库的描述(可选)
XD`QU m ^4Ra$< listener
6Q,-ZM=Z_p 参见下面listener元素
'Y+AU#1~H n4%|F'ma tag
9?r|Y@xh ] 参见下面tag 元素
f>JuxX\G e{/(NtKf Listener元素
/)SwQgK# .~V0>r~my 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
XG"&\FL{T @v9PI/c Tag元素
8NJ(l @oC8: 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
4-[L^1%S[ Wy%q9x]} 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
|KF X0*70 irCS}Dbw Tag元素的子元素
CG IcuHp (yE?)s 元素名称
S\GC^
FK 描述
_`WbR&d2Id ^_JD
7-g name
80cBLGG 独一无二的元素名
)J8dm'wH92 @L^2VVWk^ tag-class
~#iRh6^98 Tag标签对应的tag处理类
%'j)~ C>Qgd9 tei-class
c&2ZjM javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
*52*IRH @(PYeXdV6& body-content
.MuS"R{y Tag标签body的类型
[P2$[|IM `CW8Wj display-name
[AQ6ads) 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
;rpjXP aQwc Py|1R small-icon
sM({u/ 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
>/1N#S#9 ~fB: >ceD large-icon
xh[Mmq/R 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
blph&[`}I *. l,_68 description
6GG&mqr+ 此tag标签的描述
A D=@ c|u{(E58 variable
T5NO}bz 提供脚本变量的信息(同tei-class)(可选)
< i*v =C8 t5BZ" attribute
@jO3+ Tag标签的属性名
q5?g/-_0[ 0Psp/H% 以下章节介绍对于不同类型的tag,如何具体地实现它们。
`w6\II)aB QIF|pZ+^ +ZtqR 简单的tag
y.2_5&e/ :y%%Vx~ EsXCi2]1 tag处理类
6#fl1GdH- n;Tpf<*U 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
[Rw0']i`4 CL|t!+wU/ 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
_ 0%sYkUc z$oA6qB) br+{23&1R# public SimpleTag extends TagSupport
2]5dSXD d*Dq=.F( {
Zalgg/. 2Ch!LS:+ public int doStartTag() throws JspException
ge:UliHJ /E$"\md {
q.FgX [c]X)
@#S try{
NqvL,~1G 9+U%k(9 pageContext.getOut().print(“Hello.”);
vC[)/w [>::@[ }catch(Exception e){
L.>tJ.ID _H>ABo throw new JspTagException(“SimpleTag: “ + e.getMessage());
B;Ab`UX#t AJ` b-$Q }
:XEr{X R<lj$_72Q return SKIP_BODY;
?Q;8D@
*5 ]fjh{ }
(p26TN;*$5 -MOPm]iA public int doEndTag()
l;}D| 6+_W ]H0BUg {
B5*{85p(u [tym~ZZ]_m return EVAL_PAGE;
J!O5`k*.C 55MsF}p }
PF*<_p" j Y v }G"-= }
y _M<\b g*F? } *|_P 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
1VL!0H ;X-~C.7k <body-content>empty</body-content>
D oX!P|* ;0O3b trnjOm 带属性的tag标签