通过前面的例子,可以发现编写一个不需要对标签体做处理的标签处理程序是很容易的。对于一些较为复杂的标签,可能会包含有标签体,而标签处理程序则应对标签体中的内容予以适当的处理。
提示:所谓标签体是指标签开始标记和标签结束标记之间的内容,当标签开始标记和标签结束标记之间不存在任何内容时,通常可以将标签开始标记和标签结束标记合二为一,即在标签开始标记结束处的“>”之前添加一个“/”。
标签处理程序如果要处理标签体则必须实现BodyTag接口,BodyTag接口定义了处理标签体所需要的方法,该接口扩展了接口Tag。BodyTag接口定义的与处理标签体有关的方法主要有setBodyContent、setBodyContent、doInitBody、doAfterBody。类BodyTagSupport实现了BodyTag接口,所以我们在实现标签处理程序时,如果是扩展于类BodyTagSupport而非实现接口BodyTag时就可以只实现需要我们改写的方法,其它方法使用BodyTagSupport的实现就可以了。
使用方法getBodyContent可以得到一个对BodyContent对象(也就是标签体)的引用,通过这个引用就可以得到标签体的内容了,也就是说在适当的方法之中我们就可以对标签体进行处理了,通常我们在doAfterBody方法中处理标签体,doAfterBody方法会被JSP容器在标签体结束之后而在标签结束符号之前被调用。
以下通过对版权标签进行修改以处理标签体的内容为例进行说明。
首先,假定我们希望版权标签可以被添加HTML格式的标签体,在显示时以HTML代码设定的形式将标签体内容显示在版权信息之前。例如,我们可能希望以下格式的版权标签能够被正确处理。
<%@ taglib uri="WEB-INF/tlds/testlib.tld" prefix="yzj" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>自定义标签简单示例</title>
</head>
<body>
<p>这里是正文内容</p>
<yzj:copyright copyOwner="颜志军" startYear="2008">
<a href="http://www.yanzhijun.com">梦断酒醒无归处</a>
</yzj:copyright>
</body>
</html>
对于版权标签的描述文件(TLD文件),也需要做一些修改,需要指明版权标签可以包含有HTML代码。TLD文件中的bodycontent用于指明标签体的内容,它的合法值可以是empty、JSP或tagdependent,empty在前面的示例中已经用过,它表示标签体要是空的;JSP则表示标签体是正常的JSP代码;tagdependent的用法复杂一些,将在以后进行介绍。为了支持HTML语法,这里我们将bodycontent设定为JSP。
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
"http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>yzj</shortname>
<tag>
<name>copyright</name>
<tagclass>com.yanzhijun.CopyRightTag</tagclass>
<bodycontent>JSP</bodycontent>
<attribute>
<name>copyOwner</name>
</attribute>
<attribute>
<name>startYear</name>
</attribute>
</tag>
</taglib>
最后需要修改的是标签处理程序,标签处理程序有两处需要修改,一是标签处理程序要扩展于BodyTagSupport,以便支持对标签体的处理,二是添加方法doAfterBody,以便处理标签体。修改之后的代码如下:
package com.yanzhijun;
import java.io.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
public class CopyRightTag extends BodyTagSupport
{
private String copyOwner;
private String startYear;
public void setCopyOwner(String copyOwner)
{
this.copyOwner = copyOwner;
}
public void setStartYear(String startYear)
{
this.startYear = startYear;
}
public int doAfterBody() throws JspException
{
BodyContent bc = getBodyContent();
JspWriter out = getPreviousOut();
try
{
out.write(bc.getString());
}
catch(IOException e)
{
}
return SKIP_BODY;
}
public int doEndTag()
{
try
{
String copyPre = new String(copyOwner.getBytes("ISO8859_1"), "GB2312")
+ "版权所有 ©" + startYear;
String info = new String(copyPre.getBytes("GB2312"), "ISO8859_1");
pageContext.getOut().println(info);
}
catch(IOException e){}
return EVAL_PAGE;
}
}
上述代码需要特别说明的是在方法doAfterBody中,调用方法getBodyContent取得了BodyContent对象,而调用方法getPreviousOut可以取得外层标签的BodyContent对象或者页面的JspWriter对象(当该标签在最外层时)。doAfterBody方法取得标签体内容后未作任何处理而是直接将它们输出到了当前页面的JspWriter对象,因此标签体将会作为普通代码出现在JSP页面之中。
此外,doAfterBody方法的返回值为SKIP_BODY,表明该方法执行完毕后,应当忽略标签体不再继续处理它。而doEndTag方法返回的EVAL_PAGE值表明JSP容器应继续处理页面剩余的部分。