2.7 自定义JSP标签
前面介绍了JSP的动作标签,使用标签可以处理定向请求以简化JSP页面开发与维护。JSP技术提供了一种封装其他动态类型的机制—自定义标签,它扩展了JSP语言。自定义标签通常发布在标签库中,该库定义了一个自定义标签集并包含实现标签的对象。一些功能可以通过自定义标签来实现,包括对隐含对象的操作,处理表单,访问数据库及其他企业级服务,如e-mail、目录服务、处理流控制。很多JSP开发框架如Struts都提供了丰富的标签库,本节将以一个“Hello Reader”的例子来介绍如何自定义JSP标签。
2.7.1 标签库简介
标签库涉及4个基本概念:
(1)标签(Tag)
标签是一种XML元素,通过标签可以使JSP网页变得简洁并且易于维护,还可以方便地实现同一个JSP文件支持多种语言版本。由于标签是XML元素,所以它的名称和属性都是大小写敏感的。
(2)标签库(Tag Library)
由一系列功能相似、逻辑上互相联系的标签构成的集合称为标签库。
(3)标签库描述文件(Tag Library Descriptor File)
标签库描述文件是一个XML文件,简称TLD文件,这个文件提供了标签库中类和JSP中对标签引用的映射关系。它是一个配置文件,和web.xml是类似的。
(4)标签处理类(Tag Handle Class)
标签处理类是一个Java类,这个类继承了TagSupport或者扩展了SimpleTag接口,通过这个类可以实现自定义JSP标签的具体功能。
开发一个自定义标签,主要工作就是创建TLD文件和编写标签处理类。
2.7.2 创建标签的处理类
标签处理类必须实现Tag接口的doStartTag和doEndTag方法。当JSP引擎碰到tag标签的开头时,doStartTag被调用,因为简单的tag没有body,所以此方法将返回SKIP_BODY。当JSP引擎碰到tag标签的结尾时,doEndTag被调用,如果余下的页面还要被计算,那它将返回EVAL_PAGE,否则将会返回SKIP_PAGE。
一般的做法是不必直接实现Tag接口而是实现TagSupport类,如实例2-18中标签的作用是打印字符串“Hello Reader!”。
【实例2-18】自定义标签示例SimpleTag.java
01 package com.book.web3; 02 import javax.servlet.jsp.JspException; 03 import javax.servlet.jsp.JspTagException; 04 import javax.servlet.jsp.tagext.TagSupport; 05 public class SimpleTag extends TagSupport { 06 public int doStartTag() throws JspException { //实现doStartTag()方法 07 try { 08 pageContext.getOut().print("Hello Reader! "); 09 pageContext.getOut().print("<br> "); 10 pageContext.getOut().print("I'm from custom Tag"); 11 } catch (Exception e) { 12 throw new JspTagException("SimpleTag: " + e.getMessage()); 13 } 14 return SKIP_BODY; 15 } 16 public int doEndTag() { //实现doEndTag()方法 17 return EVAL_PAGE; 18 } 19 }
【代码剖析】上面第5行代码使类SimpleTag继承TagSupport类,然后重写了方法doStartTag()和doEndTag(),前者是在标签开始时触发,而后者则是在标签结束时触发。
2.7.3 创建标签库描述文件
标签库文件简称TLD文件,是用XML语言描述的。TLD包括了标签库中所有标签的描述,它一般被JSP服务器用来校验标签的语法正确性,或者被JSP开发者用来开发新的标签。TLD的文件扩展名必须为.tld,而且必须放在当前Web应用的WEB-INF目录或其子目录中。如实例2-19与上一节中的处理类配合形成一个完整的标签。
【实例2-19】自定义标签的TLD文件helloreader.tld
01 <?xml version="1.0" encoding="ISO-8859-1" ?> 02 <!DOCTYPE taglib 03 PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" 04 "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"> 05 <taglib> 06 <tlibversion>1.0</tlibversion> 07 <jspversion>1.1</jspversion> 08 <shortname>hellodemo</shortname> 09 <tag> 10 <name>hello</name> 11 <tagclass>com.book.web3.SimpleTag</tagclass> 12 <bodycontent>empty</bodycontent> 13 </tag> 14 </taglib>
【代码剖析】上面第6行代码定义了Tag库的版本,第7行代码定义了该标签所需要的JSP版本,第8行代码为标签设置一个别名,最后通过<tag>标签来具体定义标签。
<taglib>包含的子元素见表2.10。
表2.10 taglib的子元素表
listener元素是一个tag库,可以定义一些类作为它的事件侦听类,JSP服务器将会实例化这些侦听类,并且注册它们。listener元素中有一个叫listener-class的子元素,这个元素的值必须是该侦听类的完整类名。
每个tag元素在tag库中都要指出它的名字、类名、脚本变量、tag的属性。其中脚本变量的值可以直接在TLD中定义或通过tag附加信息的类来取得。每个属性描述了这个属性是否可以省略、它的值是否可以通过<%=⋯%>这样的JSP语法来获得,以及属性的类型。
每一个tag在TLD中对应一个tag元素,表2.11所示是tag元素的子元素。
表2.11 tag的子元素表
2.7.4 使用自定义标签
首先要配置web.xml,使用自定义标签<taglib>。
<taglib-uri>/WEB-INF/ helloreader.tld</taglib-uri> <!--加载标签, 供页面中使用--> <taglib-location>/WEB-INF/ helloreader.tld</taglib-location> </taglib>
在JSP中引用标签,如实例2-20所示。
【实例2-20】显示自定义标签
01 <%@ taglib uri="/WEB-INF/helloreader.tld" prefix="demo"%> 02 <html> 03 <head> 04 <title>Tag Test</title> 05 </head> 06 <body> 07 <h1> 08 <demo:hello /> <!--使用自定义标签--> 09 </h1> 10 </body> 11 </html>
【运行程序】浏览该页面,结果如图2.25所示。
【代码剖析】上面第8行代码输出自定义标签。
图2.25 自定义标签结果图
2.7.5 JSP 2.0中新增的标签定义方法
JSP 2.0提供一些较为简单的方法,让开发人员来撰写自定义标签。JSP 2.0提供两种新的机制,分别为Simple Tag和Tag File。
SimpleTagSupport类别顾名思义,就是可以处理一些简单的自定义标签需求,它是在JSP 2.0之后新增的类别。对于一些简单的自定义标签需求,您可以继承它来实现标签处理类别,这样就不用处理一些TagSupport、BodyTagSupport类别中回传值的问题。
另一方面就是SimpleTagSupport类别所处理的功能受了些限制,它只处理标签与本体,要不要显示本体文字取决于您。对于标签之后的页面则不在SimpleTagSupport处理的范围之内(虽然还是可以使用forward之类的方式来决定要不要显示之后的页面,但直接实现TagSupport会更方便一些)。另外,SimpleTagSupport类别的本体文字不能设定为JSP,这也是使用SimpleTagSupport上的一些限制。Simple-Tag Handler和其他Tag Handler(如Body Tag Handler、Tag Handler和Iteration Tag Handler)不同之处在于:Simple Tag Handler并无doStartTag( )和doEndTag( ),它只有doTag( ),因此,实现标签能比以往更为方便。
Tag File就更为简单,可以把它当做直接使用JSP的语法来制作标签。例如:
Hello.tag
<% out.println("Hello from tag file."); %>
先制作一个名为Hello.tag的Tag File,然后将它放置在WEB-INF/tags/目录下。
<%@ taglib prefix="myTag" tagdir="/WEB-INF/tags" %> <myTag:Hello />
最后执行的结果如下:
Hello from tag file.
注意 在JSP网页使用TagFile时引用的是路径而非文件名。