鉴于JSP1.x和JSP2.x自定义标签机制不同,这里先写JSP1.x。
任何一个标签都对应一个Java类,该类必须实现了Tag接口。JSP中遇到一个标签后,将通过一个tld文件查找该标签的实现类,并运行该类的相关方法。
先来看Tag接口,源代码如下:
public interface Tag
{
// 跳过标签体
public final static int SKIP_BODY = 0;
// 执行标签体内部的代码
public final static int EVAL_BODY_INCLUDE = 1;
// 不继续执行标签后面的代码
public final static int SKIP_PAGE = 5;
// 继续执行标签后面的代码
public final static int EVAL_PAGE = 6;
// 注释JSP的pageContext对象
void setPageContext(PageContext pageContext);
// 注释标签的父标签
void setParent(Tag parent);
Tag getParent();
// 进入标签时被执行
int doStartTag() throws JspException;
// 退出标签时被执行
int doEndTag() throws JspException;
// 在关闭Web应用的时候被容器调用
void release();
}
多数情况下不直接使用Tag接口,而是使用TagSupport类,所需要做的只有实现doStartTag()和doEndTag()方法。
Tag类写好后,还需要在tld(Tag Library Descriptor 标签库描述文件)中配置,以实现标签与实现类的映射。
如果tld文件在WEB-INF/下面,Tomcat会自动加载tld文件中的标签库,否则需要配置web.xml(之前一篇博客专门记录了这个知识点),例如:
<jsp-config>
<taglib>
<taglib-uri>http://www.loverabbit.com/tags</taglib-uri>
<taglib-location>/WEB-INF/somewhere/taglib.tld</taglib-location>
</taglib>
</jsp-config>
也可以直接在JSP中指定实际路径(这样的缺点显而易见,不灵活~)
<%@ taglib uri="/WEB-INF/somewhere/taglib.tld" prefix="Love" %>
示例:
带标签体的自定义标签,如果要显示标签体,则tld文件中的bodycontent属性不为empty,并且doStartTag()方法返回EVAL_BODY_INCLUDE。
对标签体进行分析,要使用BodyTag接口。如果doStartTag()方法返回EVAL_BODY_BUFFERED,则不会输出标签体,而是通过setBodyContent()方法注释到标签类里,然后使用getBodyContent()方法得到标签体的内容。
根据上一个示例小改动了下,结果如下:
如果想要多次使用标签体的内容,可以设置doAfterBody()的返回值为EVAL_BODY_AGAIN,注意,如果一直是此返回值,则会是死循环。
package my;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.TagSupport;
public class Rabbit extends BodyTagSupport
{
private String name;
private int age;
private int i;
public void setAge(int age)
{
this.age = age;
}
public void setName(String name)
{
this.name = name;
}
@Override
public int doStartTag() throws JspException
{
i = 0;
return super.doStartTag();
}
@Override
public int doAfterBody() throws JspException
{
i++;
if(i < 3)
{
try
{
this.pageContext.getOut().println(" " + i + " love ");
}
catch (IOException e)
{
e.printStackTrace();
}
return EVAL_BODY_AGAIN;
}
else
{
return SKIP_BODY;
}
}
@Override
public int doEndTag() throws JspException
{
try
{
String jsp = this.getBodyContent().getString();
this.pageContext.getOut().println("name is " + name + " age is " + age + " JspContent is " + jsp + " ");
}
catch (Exception e)
{
System.out.println("***************");
}
return EVAL_PAGE;
}
}
最后是“带动态属性的自定义标签”,不是很理解,把示例贴出来:
package my;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.DynamicAttributes;
import javax.servlet.jsp.tagext.TagSupport;
public class DynamicAttributeTag extends TagSupport implements DynamicAttributes
{
private static final long serialVersionUID = -1477571708507488373L;
private Map<String, Double> map = new HashMap<String, Double>();
@Override
public int doEndTag() throws JspException
{
JspWriter out = pageContext.getOut();
double min = 0, max = 0;
for (Double d : map.values())
{
min = Math.min(d, min);
max = Math.max(d, max);
}
StringBuffer buffer = new StringBuffer();
buffer.append("<table>");
for (Entry<String, Double> entry : map.entrySet())
{
buffer.append("<tr>");
buffer.append("<td>" + entry.getKey() + "</td>");
buffer.append("<td><img src='vote.gif' height='10' width='");
buffer.append((entry.getValue() - min) / (max - min + 1) * 200 + 50);
buffer.append("' /> " + entry.getValue() + "</td>");
buffer.append("</tr>");
}
buffer.append("</table>");
try
{
out.write(buffer.toString());
}
catch (Exception e)
{
}
return super.doEndTag();
}
@Override
public void setDynamicAttribute(String uri, String key, Object value) throws JspException
{
map.put(key, Double.parseDouble((String) value));
}
}
// end