标准的JSP 标记可以调用JavaBeans组件或者执行客户的请求,这大大降低了JSP开发的复杂度和维护量。JSP技术也允许你自定义taglib,其实换句话说,taglib可以看成是对JSP标记的一种扩展,正如xml是对html的一种扩展一样。taglib通常定义在tag标签库中,这种标签库存放着你自己定义的tag标签。简而言之,如果使用taglib,那么你可以设计自己的JSP标记!
yp@cn(:~ NwQ$gDgu t 一般来说,自定义tag标签主要用于操作隐藏对象、处理html提交表单、访问数据库或其它企业级的服务,诸如邮件和目录操作等等。自定义tag标签的使用者一般都是那些对java编程语言非常精通,而且对数据访问和企业级服务访问都非常熟悉的程序员,对于HTML设计者来说,使得他可以不去关注那些较复杂的商业逻辑,而将精力放在网页设计上。同时,它也将库开发者和库使用者进行合理分工,自定义tag标签将那些重复工作进行封装,从而大大提高了生产力,而且可以使得tag库可用于不同的项目中,完美地体现了软件复用的思想。
S;2UcSsQl 4`cf FowK~ 在这篇文章中,我们主要讨论:
{ehYE ^%N x^Qij!mB% · 什么是自定义tag标签?
t\!5$P RZSEcRlN · 怎么使用tag标签?
iEy2z+/"^ cIkA ~F o 声明要使用的tag库
UYQ@ub /X#OX8gb] o 找到与之对应的tag处理类
I\rjw$V# N"Y%*BkH o tag标签的类型
6& hiW]Adm ?duw0SZ · 自定义tag标签
glKPjL * Vhb~kI!x o tag处理类
b}u#MU 66+]D4(k o tag库描述
9)j"|5H J4iu8_eH!D o tag标签示例
<Nc9F[' *laFG<; o 带属性的tag
wLt0Fq6QG 99]s/KD2yb o 带body的tag
KVViTpZ y^kC2DS o 定义了脚本变量的tag
a{%EHL,F Bxj4rC[ o 具有协作关系的tag
?V_v=X%w 6(1
&6|o3 · 自定义tag标签
S_VzmCi 5"q{b1 o 一个迭代tag的例子
KpS=oFX{} YxA nh o 一个模板tag库
"/UPq6 M$f_I + o tag处理类到底是怎样被调用的?
T:CWxusL (>Pz3 7 gq~`!tW' 什么是自定义的tag?
`$3P@SO" mt e3k=17 一个自定义的tag标签是用户定义的一种JSP标记。当一个含有自定义的tag标签的JSP页面被jsp引擎编译成servlet时,tag标签被转化成了对一个称为tag处理类的对象进行的操作。于是当JSP页面被jsp引擎转化为servlet后,实际上tag标签被转化成为了对tag处理类的操作。
,c;#~y *|0W3uy\Y 自定义tag标签有很多特色,诸如:
&qa16bz ZC^?ng · 可以在JSP页面中自定义tag标签的属性
pH@yE Vf _nw\ac#* · 访问JSP页面中的所有对象
Y!|}; (.{. " · 可以动态地修改页面输出
JKCV>k HDu|KW$o1 · 彼此这间可以相互通信。你可以先创建一个JavaBeans组件,然后在一个tag中调用此JavaBeans组件,同时可以在另一个tag中调用它。
)coA30YR TFhYu · tag允许相互嵌套,可以在一个JSP页面中完成一些复杂的交互。
<!|=_W6 8@T0]vH& f\~w!- 使用tag标签
W^3'9nYU l?;ReK.r 'XSHl?+q 本节主要描述怎样在JSP页面中使用tag标签,以及tag标签的不同类型。
)oS~ish otP2qAI 要使用tag标签,JSP程序员必须做2件事:
[~Z#yEiW^ )MX%DQw · 声明此tag标签的tag库
%U1HvmyK 0nlh0u8# · 实现此tag标签
C|QJQ@bj0
:+ "JPF4X 声明tag标签所在的tag库
kYd=DY rj5)b:c} 如果要使用tag标签,则应用JSP的taglib指示符来指定其tag库(注意:taglib要在在使用此tag标签之前声明)
#KtV 4)( P|aSbsk:I< <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
FOcDBCrOe Ew9MWlk uri属性定义了唯一的标签库描述(以下简称TLD),它可以是直接是tld文件名或一个独一无二的名字。prefix是用来区别其它TLD中和本TLD中有重名的tag的一种手段。
>v%UV:7ap Yt4v}{+ TLD必须以.tld作为扩展名,并且存放在当前应用的WEB-INF目录或其子目录下。你可以通过它的文件名直接引用它,也可以通过别的方式间接地引用它。
)IE)a[wo M49Hm[0( 以下taglib指示符直接引用一个TLD:
VC!g,LU|- z]O>`50Q <%@ taglib uri=”/WEB-INF/tutorial-template.tld” prefix=”tt” %>
2Ju,P_<dt 2TaHWw<A 以下的taglib指示符通过一个逻辑名称间接地引用一个TLD:
hrOp9|!m 2L 1Azx <%@ taglib uri=”/tutorial-template” prefix=”tt” %>
%';DBozZ hDEZq>& 如果是间接引用TLD的话,那你必须还要在web.xml中定义此逻辑名称与tld文件之间的映射,具体做法是在web.xml中加入一个名为taglib的元素:
ZPY84)A_} e9B$"_ &2 <taglib>
$,Y?qn/ :/NP8$~@j <taglib-uri>/tutorial-template</taglib-uri>
Aq/wa6^% WS$~o*Z8 <taglib-location>
G&7 } m =E8Kacu% /WEB-INF/tutorial-template.tld
`"bp-/ [{_K[5i </taglib-location>
1+Y;
"tT .fY$$aD$4 </taglib>
Gv\fF;,R
lx~mn~;x lt}U,p,S 实现此tag标签
@gJPMgF$F aII:Pzh]B _LZ 442 为了实现tag标签,你有2种方法来存放tag处理类。一、让tag处理类以.class的方式存放于当前应用的WEB-INF/class子目录下,二、如果tag处理类是以JAR包的形式存在的话,那可以放在当前应用的WEB-INF/lib目录下,如果tag处理类要在多个应用中共享,那么它就应放在jsp服务器上的common/lib目录下,对于tomcat来说,就是tomcat/common/lib目录下。
Je`
w/Hl/U Q9t.*+ 0+S'i82=M tag标签类型
z7lbb*Xe nSU7,K`PM JhB$s 自定义的tag标签遵循XML语法。它有一个开始标记和一个结束标记,有的还有body(即文本节点):
?T_hK .O.fD <tt:tag>
WJ]g7!Ks E__A1j*gd body
N{zou?+ E`uK7 2j </tt:tag>
2l4`h)_q *K w/ilI k:zGv 一个不带body的tag标签如下:
+;;pM[U XpOQBXbt <tt:tag />
HM\gOz \V.U8asfI _]=, U.a=/ 简单的tag标签
VnMiZAHR 8m)E~6 一个没有body和属性的tag标签如下:
~3m}
EL 'MIM_m)H <tt:simple />
z[_Gg8e O<w7PS ,[Z;"wE 带属性的tag标签
`#N7ym;s@ 1uhSP!b i'vjvc~ 自定义标签可以有自己的属性。属性一般在开始标记中定义,语法为 attr=”value”。属性的作用相当于自定义标签的一个参数,它影响着tag处理类的行为。你可以在TLD中详细定义它。
Q|cA8Fn Ad`jV_z 你可以用一个String常量给一个属性赋值,也可以通过表达式给它赋值,如<%= ...%>。以struts为例,它的logic:present标签就是用的String常量来给属性赋值:
\R<OT%8 8f|+045E@ <loglic:present parameter = “Clear”>
.DHRPel SkA"MhX 而另一个标签logic:iterate是用表达式来给属性赋值:
&Lgi ZsYT&P2 <logci:iterate collection=”<%= bookDB.getBooks() %>”
x68s$H [p_C?hHO id=”book” type=”database.BookDetails”>
(*Y ENT} y<5xlN(+v zL3'',Ha 带body的tag标签
b; 4;WtBO @;z}Hk0A 一个自定义标签可以包含其它自定义标签、脚本变量、HTML标记或其它内容。
'GcZxF0 aG\B?pn- 在下述例子中,此JSP页面使用了struts的logic:present标签,如果些标签定义了parameter=”Clear”的属性,则将清除购物车的内容,然后打印出一条信息:
U
z6XQskX mCx6$jz <logic:present parameter=”Clear”>
m,]M_y\u ub]
w"N <% cart.clear(); %>
V]9?9-r 3bPvL/\Lb <font color=”#ff0000” size=”+2”><strong>
~UJ_Rr54 KcjP39@I 你选择了清除购物车!
I*K~GXWs# {%b-~& F9 </strong></font>
hYN b9^ ysiBru[u
</logic:present>
Gwkp(9d 4%k_c79> "2bCq]I0 到底是用属性还是用body来传递信息?
,*Yu~4 }KHdlhD 如上所述,我们既可以通过属性,也可以通过body来传递信息。但一般来说,比较简单的类型,如字符串或简单表达式最好采用属性来传递信息。
<kmn3w,vi w~g)Dz2G `4 A%BKYB 定义脚本变量的tag标签
6y9#am? ToVm]zPOUt 所谓脚本变量,是指JSP中可以调用的变量或对象。它可由tag标签产生。以下示例阐述了一个tag标签定义了一个名为tx的由JNDI所定义的事务处理对象。脚本变量可以是ejb对象、事务、数据库连接等等:
@YTZnGG* Io&F0~Z;;( <tt:lookup id=”tx” type=”UserTransaction” name=”java:comp/UserTransaction” />
j7 D\O zW^@\kB0D <% tx.begin(); %>
AHhck?M^ 9_GR\\ ...
cv["Ps#;`W YX_p3
Ol24A^ 具有协作关系的tag标签
,#r>#fi0 R@r"a&{/ 自定义tag标签之间可以通过共享对象来实现协作。在下述例子中,标签tag1创建了一个名为obj1的对象,在标签tag2仍可以重复使用obj。
r#pC0Yj!3 8+1tys <tt:tag1 attr1=”obj1” value1=”value” />
7>J8\= #\$R^u]! <tt:tag2 attr1=”obj1” />
Ui7S8c#tH u1&pJLK0[ 在以下这个例子当中,如果外层的tag标签创建了一个对象,那么其内层的所有tag标签都可以使用这个对象。由于这样产生的对象没有一个指定的名字,那么就可以将少重名的冲突。这个例子阐述了一系列协作的嵌套对象。
Ij }RlYQz P-QZ=dm <tt:outerTag>
]W%<<S v}ZQC8wL <tt:innerTag />
eg-,;X# jC<!Ny-$ </tt:outerTag>
``}EbOMG 8:,l+[\ X] &Q^ Tag处理类
m>'sM1s (;' ?56 <gKT 7ONtg Tag处理类必须实现Tag接口或BodyTag接口,不过现在一般都流行从TagSupport或BodyTagSupport类中继承,这些类或接口都可以在javax.servlet.jsp.tagext包中找到。
b^\u
P Ed)t87E 当JSP引擎看到自己的JSP页面中包含有tag标签时,它会调用doStartTag方法来处理tag标签的开头,调用doEndTag方法来处理tag标签的结束。
><[($Gq`g ,P<n\(DQ 下表说明不同类型的tag所需要不同的处理过程:
Kuy,qZv!" ^60BQ{ne Tag处理类的方法
iFW)}_. VZ;ASA?; Tag标签类型
-[4Xg!apO 所调用的方法
R1FBH:Iu (&FSoe/![' 基本标签
Cv|ya$}a doStartTag, doEndTag, release
[(Pm\o .3&zP 带属性的标签
(yCFpb doStartTag, doEndTag, set/getAttribute1...N, release
#|34(ML iP;X8'< BC 带内容的标签
0zaE?dA] doStartTag, doEndTag, release
(<pc4#B@* /4]M*ls 带内容的标签,且内容重复循环
QOkPliX doStartTag, doAfterBody, doEndTag, release
m-UI^M,@< Dm[4`p@IY\ 带内容的标签,且内容与JSP交互
]w(i,iJ doStartTag, doEndTag, release, doInitBody, doAfterBody, release
A -G?@U .Kr?vD^nG 一个tag处理类可以通过javax.servlet.jsp.PageContext来与JSP交互,通过javax.servlet.jsp.PageContext类,tag处理类可以访问JSP中的request、session和application对像。
v*1UNXU\ >9(lFh0P 如果tag标签是互相嵌套的,那内层的tag处理类可以通过它的parent属性来访问上层的tag处理类。
B`}?rp QdL
;|3K9 一般情况都将所有的tag处理类打成了JAR的包,以便于发布。
n97A'"'wz wz5xJ:T j keEyE;O}u Tag库描述(简称TLD)
2`Xy}9N/Y bH&Cbme90- w3c[t~R8 Tag库是用xml语言描述的,TLD包括了tag库中所有tag标签的描述,它一般用来被jsp服务器用来校验tag的语法正确性,或者被jsp开发者用来开发新的标签。
_U)DL=a' INsc!xOQ TLD的文件扩展名必须为.tld,而且必须放在当前WEB应用的WEB-INF目录或其子目录中。
e;56}w E/9 U0 一个TLD的内容的开头必须遵守标准的XML开头,用于描述DTD和xml的版本,例如:
_pM&Ya C$xU!9K[+ <?xml version="1.0" encoding="ISO-8859-1" ?>
M&
GA:` cTFyF) <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "
http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
rE-Xv.
| TLD必须以<taglib>来作为它的根元素,<taglib>的子元素如下表:
CEE`nn utC]GiR ;-47d ^ <taglib>的子元素
h&||Ql1 impzqQlZ, Element
c.Pyt Description
it!8+hvq9* 16[>af0<g tlib-version
_H|x6X1- Tag库的版本
|<P]yn `AeId/A4n jsp-version
0x'>}5`5 Tag库所需要的jsp的版本
?ZDXT2b~~ q-3%.<LL short-name
LZV 助记符,tag的一个别名(可选)
X~GnK>R [>Kkj;* uri
W~
XJ ']e 用于确定一个唯一的tag库
[nxjPx9-
SEF/D0 display-name
W\o(f W 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
eP$0TDZ eXWiTi@ small-icon
_) 2fXG! 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
_=XzQZT!L h*{{_3, large-icon
0m6Vf
x 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
Ps(3X@ I|,^a|\ description
2GA6@-u\ 对tag库的描述(可选)
8'_>A5L/C MOY.$M,1 listener
sXkWs2! 参见下面listener元素
9 W><m[O 7\'vSHIL tag
@;M( oFS9 参见下面tag 元素
9~bje^M g= k}6"F~ Listener元素
[s"3g\L'; .{LFc|Z[ 一个tag库可能定义一些类做为它的事件侦听类,这些类在TLD中被称为listener 元素,jsp服务器将会实例化这些侦听类,并且注册它们。Listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
yv^j~ @dV'v{:, Tag元素
G eN('0 qi_[@da f? 每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略,它的值是否可以通过<%= …%>这样的JSP语法来获得,以及属性的类型。
{BKu'A f@T/^|`mh 每一个tag在TLD中对应一个tag元素,下表是tag元素的子元素:
ZFNM>C^ 2j`x^ Tag元素的子元素
DTk)Y-eQ \T'uFy9&a 元素名称
n;)!N 描述
2cr~/,YY hS}?"ST| name
N&U=5c`Q' 独一无二的元素名
Wo2TU! -mOSB(#bo tag-class
b"t95qlL Tag标签对应的tag处理类
KlDW'R$ r4k=i4 tei-class
uOc:^ javax.servlet.jsp.tagext.TagExtraInfo的子类,用于表达脚本变量(可选)
)uiYu3 I Lnbbv
* body-content
fDhV
*LqW Tag标签body的类型
VG^*?62 q3adhY9|)0 display-name
?Ko)AP 被可视化工具(诸如Jbuilder)用来显示的名称(可选)
j<>E
Fd #ok1qT9_ small-icon
A&rk5y; 被可视化工具(诸如Jbuilder)用来显示的小图标(可选)
jt?4raNW Z;=G5O
uvQ large-icon
>
$DMVtE0 被可视化工具(诸如Jbuilder)用来显示的大图标(可选)
w d2GKq! @|v4B[/ description
AHc:6v^ 此tag标签的描述
|}
;&xI M?Tb9c?` variable
T_|%nF-+ 提供脚本变量的信息(同tei-class)(可选)
>Lx,<sE 1r;]== attribute
lxx)l(& Tag标签的属性名
z %{Z e`zx#v 以下章节介绍对于不同类型的tag,如何具体地实现它们。
oa$-o/DhB {m~.'DU \7rFfN3 简单的tag
L|.q19b* 5wYYYo= =/Pmi_ tag处理类
v=e`e68U~ `&2~\o/ 简单的tag处理类必须实现Tag接口的doStartTag和doEndTag方法。当jsp引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回 SKIP_BODY。当jsp引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
bD*V$w*P e\%+~GUTC= 以下是例子:对于标签 <tt:simple /> ,它的tag处理类实现如下:
8+K=3=05#U :so2 {.t- Jn3cU public SimpleTag extends TagSupport
;[TC`DuNj0 "<uaG?: {
iq2)oC_ '8\7(0$c public int doStartTag() throws JspException
$51M'Qu 6t/nM {
L[o;@+32 m}&cX Y try{
vaN}M)W/ GSo&$T;B6 pageContext.getOut().print(“Hello.”);
l]t9*a]a jN
9|q }catch(Exception e){
BK`NPC$a (?R;u> throw new JspTagException(“SimpleTag: “ + e.getMessage());
)@+lfIE(l ^Z1t'-xZ }
j06?Mm_c2 e59P6/z return SKIP_BODY;
"zFv?ay ]Hr:|2|. }
gq9IJ n${,r public int doEndTag()
-5;Kyio ;^+# {
8>^(-ca_ C><]o return EVAL_PAGE;
.,Qj3 ${I$@qq83 }
@!k\Ivd r*?rwtFtg }
Mx?]7tI XRoMD6qf; GVS-_KP\ 注意:如果tag标签没有内容的话,那必须定义body-content元素为空,例如
ZccQ{$0H ?^y%UIzf <body-content>empty</body-content>
N6K%Wkz .G-F5`2I PL vz1}ts 带属性的tag标签