JSP变量在规范中的范围
JavaServer Pages (JSP) 和 JSP规范标准标记库 (JSTL) 为 Web 开发人员提供了许多有用的标记(也称作操作)。此外,JSP 2.0 还提供两个 API,即标准标记 API 和简单标记 API,用于构建定制标记/操作。前一个 API 继承自 JSP 1.x,并由于历史原因而由 JSTL 使用。(由于 JSTL 1.0 的开发在 JSP 2.0 之前,因此新 API 不包含 JSTL 1.1。)此外,JSTL 也不使用 JSP 片段和动态属性等 JSP 新特性。本文使用 JSP 2.0 的新 API 和特性构建定制标记扩展 JSTL。本文提供 API 概述并演示如何开发
◆导出变量的标记
◆条件标记
◆迭代标记
◆具有动态属性的标记
◆协调标记
简单标记API 概述
在 JSP 页面中使用定制标记时,应用服务器的 JSP容器将 ... 转换为调用称为标记处理类的方法的 Java 代码。因此,如果要开发定制标记,必须提供一个标记处理类,此类必须使用 JSP 1.x 标准标记 API 或 JSP 2.0 简单标记 API。比较一下这两个 API,就会发现新 API 更易于使用。简单标记 API 只有一个接口 (javax.servlet.jsp.tagext.SimpleTag),它定义了处理定制标记的方法。通常从 JSP容器从 JSP 页面中自动生成的 Java Servlet 中调用这些方法。
javax.servlet.jsp.tagext.SimpleTagSupport 类实现了 SimpleTag 接口,因此当标记处理类扩展 SimpleTagSupport 时只须编写 doTag() 方法即可。以下步骤介绍了如何开发一个简单的标记处理类:
第 1 步:设计定制标记
首先,必须为标记选择一个名称并设置它的属性。然后,创建一个标记库描述符 (TLD) 文件(采用由 JSP规范定义的 XML 格式),以告知 JSP容器如何处理和验证定制标记。文本提供了一个名为 util.tld 的示例 TLD 文件。
第 2 步:创建标记处理类
必须提供一个用于实现 SimpleTag 接口的 Java 类。最简单的方法是扩展 SimpleTagSupport 或它的某个子类。本文中的 VarTagSupport、IfTag 和 WhileTag 类用于扩展 SimpleTagSupport。其他标记处理类示例扩展 VarTagSupport。
如果要使用未在 TLD 文件中指定的属性,则标记处理类必须实现 javax.servlet.jsp.tagext.DynamicAttributes 接口(如“具有动态属性的标记”部分中介绍的 MapTag 示例所示)。
第 3 步:初始化标记处理类实例
每个标记处理类都必须包含一个不带参数的公共构造函数,用于放置初始化代码。本文中的某些标记处理类(EvalTag、ListTag 和 MapTag)包含一个无参数的公共构造函数,它使用默认值初始化实例变量。其他类(IfTag、WhileTag 和 ItemTag)没有构造函数。请注意,Java 编译器在类不包含任何构造函数的情况下自动生成一个无参数的公共构造函数,该函数不执行任何操作。
第 4 步:提供属性设置方法
JSP 页面中的标记属性值通过 setAttribute() 方法传递给标记处理类。例如,本文中的 标记包含四个属性:var、scope、expr 和 type。EvalTag 处理类实现 setExpr() 和 setType() 方法,并从 VarTagSupport 继承 setVar() 和 setScope()。
动态属性通过 DynamicAttributes 接口定义的 setDynamicAttribute() 方法传递。
第 5 步:实现 doTag() 方法
该方法用于实现定制标记的逻辑。doTag() 方法由 JSP容器继所有属性设置方法之后调用。此处可以使用 getJspContext() 获得一个 javax.servlet.jsp.JspContext 对象来访问 JSP 环境。可以调用 getJspBody(),它返回 javax.servlet.jsp.tagext.JspFragment 的实例,该实例表示位于 和 之间的 JSP 主体。如果要开发协同工作的标记,如 和 (本文的最后一部分将对其进行介绍),则还可以使用 getParent() 和 findAncestorWithClass() 方法。
第 6 步:测试定制标记
使用定制标记的 JSP 页面必须使用 指令导入该标记的标记库。当定制标记出现在 JSP 页面中时,JSP容器将生成创建标记处理类实例、调用属性设置方法和调用 doTag() 方法的代码。因此,在使用定制标记的 JSP 页面的执行过程中将调用标记处理类方法。
限制和变通方法
为简化标记处理 API,JSP 2.0 采取了一个限制:如果定制标记的处理类是基于简单标记 API 的,则页面作者不得在 和 之间使用 JSP 1.x 声明 ()、JSP 1.x 表达式 () 和 scriptlet ()。大多数情况下,您可以将 JSP 页面中的 Java 代码移动到标记处理类中,或在 JSP 2.0 表达式 (${...})(可以在定制标记的主体中使用)中使用 JSTL。请注意,JSP 2.0 允许您在基于标准标记 API 的定制标记主体中使用 scriptlet。然而,由于不使用脚本的 JSP 页面更易于维护,因此最好避免在 Web 页中使用 Java 代码。
我的上一篇 Oracle 技术网 (OTN) 文章“使用 JSP 2.0 EL API”介绍了简单标记 API 的另一个限制并提供了变通方法。JspContext 类未提供对 JSP 隐式对象(如application、session、request 和 response)的访问。大多数应用服务器(包括 Oracle Application Server Containers for J2EE (OC4J) 10g)允许将 JSP 上下文转换为 PageContext
标记处理类不适用于使用 println() 语句生成大量可重用的 HTML 代码。JSP 2.0 为此工作提供了一个更好的方法。所谓的标记文件使用 JSP 语法并由 JSP容器自动转换为基于简单标记 API 的标记处理类。我的另一篇 OTN 文章“创建 JSP 2.0 标记文件”介绍了这个 JSP 新特性。
导出变量的标记
许多 JSTL 标记实现某个逻辑并导出 JSP变量以报告结果。例如, 包含一个 var 属性,该属性必须指定用于保存 SQL 结果集的 JSP变量的名称。var 属性对其他 JSTL 标记(如 和 )来说是可选的。如果 var 属性不存在,则这些标记将输出它们的结果。所有包含 var 属性的标记还包含一个 scope 属性,该属性可用于指示以下 JSP变量的作用域:page、request、session 或 application。