让我们创建一个定义一个 HashMap
scriptlet 变量的标签。为此,需要实现标签处理程序接口 (javax.servlet.jsp.tagext.Tag)。因此,我们要创建的第一个标签将是一个简单标签。
这个标签将实例化一个 map。使用这个标签的开发人员可以指定要实例化的 map 的类型 —— HashMap
、TreeMap
、FastHashMap
或者 FastTreeMap
。FastHashMap
和 FastTreeMap
来自 Jakarta Commons Collection library (有关链接请参阅 参考资料)。开发人员还可以指定标签所在的范围 —— 页、请求、会话还是应用程序范围。
要构建这个简单标签,我们需要完成以下步骤:
Tag
接口(准确地说是 javax.servlet.jsp.tagext.Tag)的标签处理程序类。doStartTag()
方法。在标签处理程序类中,根据属性将值设置到 scriptlet 变量中。如果您像我一样,可能会提前阅读书的结尾,所以请查看 附录 中标签处理程序类的完整列表以了解这个过程是如何结束的。
在下面几小节中,我们将分析 MapDefineTag
的实现,并分析如何到达这一步。
为了编写标签处理程序,必须实现 Tag
接口。如前所述,这个接口用于不操纵其标签正文的简单标签处理程序。就像 J2EE API 文档 (有关链接请参阅 参考资料)所说的:Tag
接口定义了标签处理程序和 JSP 页实现类之间的基本协议。它定义了在标签开始和结束时调用的生存周期和方法。
标签处理程序接口有以下方法:
int doStartTag() throws JspException |
处理开始标签 |
int doEndTag() throws JspException |
处理结束标签 |
Tag getParent() /void setParent(Tag t) |
获得/设置标签的父标签 |
void setPageContext(PageContext pc) |
pageContext 属性的 setter 方法 |
void release() |
释放获得的所有资源 |
TagSupport
现在,不必直接实现 Tag
接口,相反,用 map 定义的(map-defining)标签将继承 TagSupport 类。这个类以有意义的默认方法实现 Tag
接口,因而使开发自定义标签更容易 (有关 TagSupport 的 API 文档的链接请参阅 参考资料)。 例如,TagSupport 类定义了 get
/setParent()
和 setPageContext()
,这与所有标签处理程序几乎相同。 get
/setParent()
方法允许标签嵌套。TagSupport 类还定义了一个可以被子类使用的 pageContext
实例变量 (protected PageContext pageContext
),这个变量是由 setPageContext()
方法设置的。
在默认情况下,TagSupport 实现了 doStartTag()
以使它返回 SKIP_BODY
常量,表示将不对标签正文进行判断。 此外,在默认情况下,doEndTag()
方法返回 EVAL_PAGE
,它表示 JSP 运行时引擎应当对页面的其余部分进行判断。 最后,TagSupport 实现了 release()
,它设置 pageContext
及其父元素为 null
。
TagSupport 类还实现了 IterationTag
接口和 doAfterBody()
,这样它就返回 SKIP_BODY
。 在后面讨论进行迭代的标签时我将对此加以更详细的解释(请参阅 用自定义标签控制流程)。
好了,现在让我们通过继承 TagSupport 来实现 Tag
接口:
... import javax.servlet.jsp.tagext.TagSupport; ... public class MapDefineTag extends TagSupport { ...
我们已经定义了标签处理程序,现在需要增加从处理程序到 TLD 文件中的标签的映射。我们将在下一小节中对此进行处理。然后,将完成 MapDefineTag
中剩余的代码。
TLD 文件对自定义标签处理程序的作用就像 Web 部署描述符对 servlet 的作用。 TLD 文件列出了从标签名到标签处理程序的映射。 这个文件中的大多数数据都是在 JSP 页转换时使用的。 TLD 文件通常保存在 Web 应用程序的 WEB-INF
目录,并在 web.xml 文件中声明。它们一般用 .tld
扩展名结束。
TLD 文件有一个 导言(preamble),在这里标识 JSP 技术的版本和使用的标签库。这个导言通常看起来像这样:
<taglib> <tlib-version>1.0</tlib-version> <jsp-version>1.2</jsp-version> <short-name>map</short-name> </taglib>
让我们更详细地分析一下这些标签:
taglib
。taglib
描述了一个 标签库 —— 即一组标签/标签处理程序对。 tlib-version
和 short-name
元素。tlib-version
元素对应于标签库版本。 jsp-version
对应于标签库所依赖的 JSP 技术的版本。short-name
元素定义了 IDE 和其他开发工具可以使用的标签库的简单名。taglib
元素包含许多 tag
元素,标签库中每一个标签有一个 tag
元素。因为我们刚创建了自己的类,所以我们将继续往下进行,在 TLD 文件中声明这个类,如下所示:
<taglib> ... <tag> <name>mapDefine</name> <tag-class>trivera.tags.map.MapDefineTag</tag-class> <body-content>JSP</body-content> ... </tag></taglib>
tag
元素用于将自定义标签映射到它们的自定义标签处理程序。上述清单中的 tag
元素将自定义标签 mapDefine
映射到处理程序 trivera.tags.map.MapDefineTag
。 因此,不论在 mapDefine
上运行的是什么转换引擎,都会调用 trivera.tags.map.MapDefineTag
。
已经在 TLD 中定义了标签,接下来要在标签处理程序类中定义这个标签的一些属性了。