标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
|tolgdj Kr+Bty 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
qNuv?.7 $O8EiC!f6 在这篇文章中,我们主要讨论:
h\: tUEg#J <whPM · 什么是自定义tag标签?
rwV u?W D=pI'5& · 怎么使用tag标签?
w$<fSe7 ?6.KS o 声明要使用的tag库
u0 'pR#
m| ~n]2)>6 o 找到与之对应的tag处理类
KWZNu&)
8t^;O! o tag标签的类型
+lf@O&w wTgx(LtH · 自定义tag标签
tr67ofld| j)lM:vXR o tag处理类
MlcoOi! %(wsGNd o tag库描述
EssUyF-jwU Z:o'
+oh o tag标签示例
v'2OHb# \VhpB
o 带属性的tag
ah&plaVzC MM58w3Mz o 带body的tag
#dn%KMo2r $BO}D o 定义了脚本变量的tag
[7Kj$PB3 gWU(uBS o 具有协作关系的tag
q_m#BE;t WTy8 N · 自定义tag标签
-^nQ^Td=j /v5g;x_T o 一个迭代tag的例子
fU){]YP ;H#R{uR_< o 一个模板tag库
_R!!4Hp<Q .AQ3zpy5B o tag处理类到底是怎样被调用的?
y [7xK}`_ `'k's]Y S r#fyr 什么是自定义的tag?
iJp!ROI Ul~}@^m]4} 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
Ivgwm6M }?ac<> u& 自定义tag标签有很多特色,诸如:
=*)O80oaW P A+e= % · 可以在JSP页面中自定义tag标签的属性
n*8RYm)? gQzJ2LU( · 访问JSP页面中的所有对象
0_xcrM :92a34 · 可以动态地修改页面输出
~4
x Ba:*z `5 v51TpH · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
9QM"JEu@ {CyPcD'$s · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
C?<XtIoB BKlc{= :@4>}k* 使用tag标签
5<GRi"7A@ u C8T!z !v;_@iW3e 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
0dX= 7J_f/st 要使用tag标签,JSP程序员必须做2件事:
Chi<)P$^
|h~/Zz= · 声明此tag标签的tag库
Cot\i\]jv g1!L.
On · 实现此tag标签
ke6cZV5w hy`)]>9z~ 声明tag标签所在的tag库
oX]1>#5UMg |"E9DD]{ 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
YGO 7lar ?kxWj(D <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
2B?i2[a, 50hh0!1 uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
JGNxJ S<] pxnUe1= TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
7;-i_&vws 5nIlG 以下taglib指示符直接引用一个TLD:
ML"P"&~u6 f?I *`~k <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
D\&y(=fzf N'BctKL 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
T-8nUo}i DczF0Ow <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
]mT}
\b A
=#-u&l 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
?{P6AF-xcf scEQDV <taglib>
r{jD,x2 1E_Ui1 [ <taglib-uri>/tutorial-template</taglib-uri>
g~D6.OZU Nn7@+g) <taglib-location>
y8n1IZ*#SZ A|OC?NZY /WEB-INF/tutorial-template.tld
b1^Yxe#L BiCa " </taglib-location>
Sg~A'dG M@@O50~ </taglib>
oi4Wxcj v23Uh2[@Yy *pUV-^uo 实现此tag标签
xVX||rrh ]c=1-Rl 0BD((oNg 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
(SVr>|Db &+iW: 3s$.l} tag标签类型
To?
bp4 A+E@OO w*~ Hu2g (! 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
.TS=[WGMS :Rx"WY <tt:tag>
yzl\{I& n
k3lC/f body
;@s~t:u fR;_6?p*B </tt:tag>
?t P/VL ''07Km@x ]7
mSM 一个不带body的tag标签如下:
~,-O ?^5*[H <tt:tag />
shvcc l<%~w
U <s3( 简单的tag标签
y.<Y]m 3m7V6##+ 一个没有body和属性的tag标签如下:
)Dpt<}}\ ^{bEq\5& <tt:simple />
Q8:ocEhR o_m.MMEU x}j41E} 带属性的tag标签
^i1:PlW] Y &+/[[ *lO+^\HXD 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
Mwk_SCy +Z]%@"S? 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
DQnWLC"u _oVA0@#n <loglic:present parameter = “Clear”>
?{")Wt 5)<jPyC 而另一个标签logic:iterate是用表达式来给属性赋值:
(.+n1)L? B`EgL/Wg[ <logci:iterate collection=”<%= bookDB.getBooks() %>”
uNBhVsM6< :[03upyS id=”book” type=”database.BookDetails”>
|:[vpJFK 7E)7sd a[ l5k 带body的tag标签
1e} 3L2rC dq(L1y870 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
=(\!,S' 4=:eGlU93U 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
@1Lc`;Wd !S{<Xc'wv <logic:present parameter=”Clear”>
!WnI` +[9"M+4- <% cart.clear(); %>
XLxr~Yo <Rt@z|Zv <font color=”#ff0000” size=”+2”><strong>
B(dL`]@Xm 6s2g +[ 你选择了清除购物车!
Ma#-'J pjM|}i<'Q </strong></font>
5C?1`-&65V "PtH
F`mo </logic:present>
*^_!W'T{j |_m;@.44?U Ka{Zoi] 到底是用属性还是用body来传递信息?
D*,H%xA J< M;vB) 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
o-=lH tR B35f5m7r >FNt*tX<0 定义脚本变量的tag标签
]Jqe)o #9Z-Hd< 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
l si8?91 .5xg;Qg\Y <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
*JXJ
2 $0t
%}DE <% tx.begin(); %>
k3XtKPO ~!kbB4`WK ...
!6C d.fpWL N/VIP0Kb zY-m]7Yf 具有协作关系的tag标签
sA.yb,Fw ZeZwzH)BD 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
=T]OYk xd@DN;e <tt:tag1 attr1=”obj1” value1=”value” />
p.|;
k%c7 A[bxxQSP\H <tt:tag2 attr1=”obj1” />
%-CC_R|0$ CG;D (AWR; 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
A>puk2 s ,V?,I9qf <tt:outerTag>
rg~CF< Xv:IbM>
Qc <tt:innerTag />
i$bBN$<b< H_FhHX.2( </tt:outerTag>
sTz*tSwQv Q<pM
tW k~ue^^r} Tag处理类
%?jf.p*kY 3F1Z$d( <~OyV5:6 Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
?Dm&A$r qfU3Cwy 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
}d(6N&;"zN ]u ';zJ. 下表说明不同类型的tag所需要不同的处理过程:
]'q<wPi M&dtXG8<^ Tag处理类的方法
*gn*S3Is[j }0G Ab2 Tag标签类型
-tQ|&fl 所调用的方法
.w~USJ=X )EoG@:[ 基本标签
R7i*f/m doStartTag, doEndTag, release
A-FwNo2"% xjN~Y D: 带属性的标签
Tx(R3B+u7 doStartTag, doEndTag, set/getAttribute1...N, release
wah` "6i9 f$N 带内容的标签
`O/)q^m1L doStartTag, doEndTag, release
L/I-(08!Y: O}Jb,?p 带内容的标签,且内容重复循环
&bRH(yF doStartTag, doAfterBody, doEndTag, release
FcA0 \`0M p* @L1 带内容的标签,且内容与JSP交互
i`~y%y doStartTag, doEndTag, release, doInitBody, doAfterBody, release
5z_) z0sB*5VH 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
FQyiIT6 6D],275`J 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
$m>e!P>%u v|GvN|_| 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
P7b2I=t ,o)MiR9-[A ]Gr'Bt / Tag库描述(简称TLD)
_$0Ix6y, sAN#j
{ [H1NP'Kg] Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
G u=Rf`o !Xm: $KH TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
7}Sw(g)o7 CS/-:>s% 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
=%L^!//c PewLg<?,G4 <?xml version="1.0" encoding="ISO-8859-1" ?>
IjNm/${$ W5p}oN <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
S,H{\c TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
/2:r}O >BX_Bou 1 wG1\9S <taglib>的子元素
dY,'6JzC vl<J-+|0C Element
pqe**`z@y Description
TO.NCO\x D1f=f88/} tlib-version
-n9e-0 Tag库的版本
Hpt)(Nz: jnTl%aQYc jsp-version
H2]I__t/u Tag库所需要的jsp的版本
gJ])A7O (GQy"IuFh short-name
%_
~[+~# 助记符,tag的一个别名(可选)
6voK{C4J Ol? 2Qy.2) uri
^.(]i\V_ 用于确定一个唯一的tag库
[Ue>KG62= P}5aN_v\ display-name
78%2#;;G 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
-4Xr5j%o g@QpqrT small-icon
^T5c^ M8o 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
; H3kb
+ g5E]o) large-icon
%VMazlM15 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
R:e:B7O~0 R9W(MLe58 description
eYa gI 对tag库的描述(可选)
$OT:J >eC^]#c listener
bfJDF(=h 参见下面listener元素
/EC m _ReQQti[ tag
,
?%`Ky/ 参见下面tag 元素
ESO(~X+ IQM!dC Listener元素
VY F4q9 p;@PfhEz) 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
rN}^^9 O^f@ g l Tag元素
TC2aD&cw{ yqK82z5U*R 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
p])km%zB( <W?,n% 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
ZGf=/Ra
a Bq!P.%6p4 Tag元素的子元素
HZ|6&9we K|B1jdzL 元素名称
+b{\v1b 描述
[J^,_iN[. L]p:gI{m name
4 QDW}5xB 独一无二的元素名
f5G17: Q F :u} 7t> tag-class
qg>i8V Tag标签对应的tag处理类
lj[Bd > 53L)+\7w tei-class
+|}~6` javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
#*9*[Xbi K9*K4'#R body-content
SQeQ"k|P% Tag标签body的类型
!{4p+peqJV oreSu;`$ display-name
cZwQ{9> 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
g~cWBr%> %|;^[^7+}t small-icon
#[A/zH|xvV 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
|m=@;B| 6G(k{S large-icon
iw#luHcJ 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
I*#~@:4* sOHh&e description
pZH
bj2~ 此tag标签的描述
6@T_1 Y`M.hYBXk variable
Yux7kD\c 提供脚本变量的信息(同tei-class)(可选)
(s9?#t6 S4|)N,# attribute
-F*j` Tag标签的属性名
iBZ+gsSP &o?pZ(\C 以下章节介绍对于不同类型的tag,如何具体地实现它们。
PKwx)!
Rz Kkd7D_bZ* c`iSe$eS 简单的tag
.D7\Hao p0@iGyd rf9RG! tag处理类
i P/I% D *kDXx&7B$ 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
Db2G)63 =^{^KHzIl3 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
{}>"f]3 sx/g5?zh L\b$1U!i public SimpleTag extends TagSupport
UP,(zKTA '8}\! i& {
=B;)h MHgS5b2 public int doStartTag() throws JspException
>`6^1j(3 1 ft.ZJ {
5Wn6a$^
v+\E%H try{
7$^V_{ej UboOIx5: pageContext.getOut().print(“Hello.”);
:?60pu= >s1HQSe66 }catch(Exception e){
h<6r+*T' p E[$['0 throw new JspTagException(“SimpleTag: “ + e.getMessage());
D$j`+` T*$uc, }
%D&FnTa /]YK:7*98 return SKIP_BODY;
oVLz7Y[JE 0a(*/u }
o XGf#>keg p*>[6{$3)O public int doEndTag()
YGxdYwBwf (+4=A k {
#M_QSD}& <,LeFy\zW return EVAL_PAGE;
4=1lyw u52@{@Ad }
6H3_qx z9VQsC'K }
@m(\f Ron^PvvY& d{YhKf#~ 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
IQH;`+ fA|'}(kH <body-content>empty</body-content>
^P]: etld9 EK#w: " S46[2-v1 带属性的tag标签