第 3 步:在标签处理程序 Java 类中创建属性 | 第 5 页(共9 页) |
我们希望为 mapDefine
标签指定三个属性,如下所示:
属性说明 | |
---|---|
id | 新 scriptlet 变量的名字。 |
scope | 新 scriptlet 变量所在的范围。 |
type | 新 scriptlet 变量的类型 (HashMap 、FastHashMap 、TreeMap 或者 FastTreeMap )。 如果 type 设置为 hash ,那么就会创建一个 HashMap 。如果 type 设置为 fasthash ,那么将创建 FastHashMap 。 |
在 JSP 页中使用这个标签时,它看起来将像下面这样:
<map:mapDefine id="editParams" scope="session" type="hash"> ... </map:mapDefine>
这个标签将在会话范围内创建一个名为 editParams
的 HashMap
。
为了在标签处理程序中创建属性,需要定义相应的 JavaBean 属性。 因此,每一个属性在标签处理程序中都有对应的 setter 方法,如下所示:
public class MapDefineTag extends TagSupport { ... private String type = FASTTREE; private String id; private String scope; public void setType(String string) { type = string; } public void setId(String string) { id = string; } public void setScope(String string) { scope = string; }
转换引擎将用硬编码的配置数据或者运行时表达式设置这个标签的属性。 我们将在 第 4 步:在 TLD 文件中定义属性 中对此做更详细的讨论。
在 第 5 步:实现 doStartTag() 方法 中,我们将在标签处理程序的 doStartTag()
方法中使用这些属性。
第 4 步:在 TLD 文件中定义属性 | 第 6 页(共9 页) |
就像上一小节中所做的那样,通过声明 JavaBean 属性定义自定义属性,然后在 TLD 文件中声明这些属性。 每一个 JavaBean 属性都必须与相应的自定义标签属性相匹配。 在 TLD 中定义的属性必须匹配 JavaBean 属性,不过却可以有与标签属性不匹配的 JavaBean 属性。
下面是 MapDefineTag
的属性声明:
<tag> <name>mapDefine</name> <tag-class>trivera.tags.map.MapDefineTag</tag-class> <body-content>JSP</body-content> ... <attribute> <name>id</name> <required>true</required> <rtexprvalue>false</rtexprvalue> <description>The id attribute</description> </attribute> <attribute> <name>scope</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <description>The scope attribute</description> </attribute> <attribute> <name>type</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <description> Specifies the type of map valid values are fasttree, fasthash, hash, tree </description> </attribute> </tag>
name
元素指定属性的名字。required
元素指定属性是否是必需的(默认值是 false
)。rtexprvalue
元素表明属性是硬编码了转换时的值还是允许使用运行时 scriptlet 表达式。
记住,MapDefineTag
类必须为前面描述的每一个属性定义一个 JavaBean 属性,我们在 第 3 步:在标签处理程序 Java 类中创建属性 中完成这个任务。
第 5 步:实现 doStartTag() 方法 | 第 7 页(共9 页) |
标签开始时调用 doStartTag()
方法 —— 从开发人员的角度看,这是当引擎遇到 <map:mapDefine>
时发生的。如果 doStartTag()
返回 SKIP_BODY
,那么将不处理标签正文。 如果它返回一个 EVAL_BODY_INCLUDE
,那么将处理正文。
MapDefine
类的 doStartTag()
方法完成以下工作:
- 根据
type
属性确定要创建的 map 的属性。 - 根据
scope
属性确定新的 map 对象放在什么范围内。 - 根据
id
属性确定新 map 对象要放入的范围的名字。
让我们更详细地分析这个过程。MapDefine
类检查 type
属性是设置为 FASTTREE
、HASH
、TREE
还是 FASTHASH
。然后创建相应的 map,如下所示:
/* String constants for the different types of maps we support */ public static final String FASTHASH = "FASTHASH"; public static final String FASTTREE = "FASTTREE"; public static final String HASH = "HASH"; public static final String TREE = "TREE"; /** The map we are going to create */ private Map map = null; /** The member variable that holds the type attribute */ private String type = FASTTREE; ... public int doStartTag() throws JspException { /** Based on the type attribute, determines which type of Map to create */ if (type.equalsIgnoreCase(FASTTREE)) { map = new FastTreeMap(); } else if (type.equalsIgnoreCase(HASH)) { map = new HashMap(); } else if (type.equalsIgnoreCase(TREE)) { map = new TreeMap(); } else if (type.equalsIgnoreCase(FASTHASH)) { map = new FastHashMap(); }
然后,用 id
和 scope
属性将 hashmap 以一个给定的名字设置到一个给定范围中:
private String id; private String scope; public int doStartTag() throws JspException { ... if (scope == null){ pageContext.setAttribute(id, map); }else if("page".equalsIgnoreCase(scope)){ pageContext.setAttribute(id, map); }else if("request".equalsIgnoreCase(scope)){ pageContext.getRequest().setAttribute(id, map); }else if("session".equalsIgnoreCase(scope)){ pageContext.getSession().setAttribute(id, map); }else if("application".equalsIgnoreCase(scope)){ pageContext.getServletContext().setAttribute(id, map); } return EVAL_BODY_INCLUDE; }
如果范围属性是 null
,那么 map 将放入页范围。否则,参数将放入通过 scope
属性传递的范围名所对应的范围中。
到目前为止,我们已经有一个非常简单的标签,它有三个属性:id
、scope
和 type
。 我们将用给定的名字将 map 放到一个范围中。但是,我们还有一件事没做,就是声明 scriptlet 变量。 为了做到这一点,需要向 TLD 再添加一项,这就是我们在下一小节中所要做的事。
未完待续