本文自定义输出helloworld标签和自定义list循环遍历标签
自定义标签的基本步骤如下:
(1)把标签处理类及相关类的class文件存放在WEB-INF/classes目录下。
(2)把TLD标签库描述文件存放在WEB-INF目录或者其自定义的子目录下。
(3)在web.xml文件中声明所引用的标签库。
(4)在JSP文件中使用标签库中的标签。
自定义实现Tag接口的标签步骤
一、创建处理标签的java类,标签处理类要实现javax.servlet.jsp.tagext.Tag接口
输出helloworld标签的形式<h:hello></h:hello>
(1)Tag接口中的方法简介
1.public void setPageContext(PageContext pc)由Servlet容器调用传递给处理类pageContext对象
2.public void setParent(Tag t)由Servlet容器调用传递给标签处理类该标签的父标签
3.public Tag getParent()返回该标签的父标签
4.doStartTag()当Servlet容器遇到该标签的启始标记的时候会调用该方法。
doStartTag()方法返回一个整数值,用来决定程序的后续流程。
它有两个可选值,即Tag.SKIP_BODY和Tag.EVAL_BODY_INCLUDE。
Tag.SKIP_BODY表示标签之间的主体内容被忽略,
Tag.EVAL_BODY_INCLUDE表示标签之间的主体内容被正常执行。
5.doEndTag()当Servlet容器遇到标签的结束标志时,就会调用doEndTag()方法。
doEndTag()方法也返回一个整数值,用来决定程序后续流程。
它有两个可选值,即Tag.SKIP_PAGE和Tag.EVAL_PAGE。
Tag.SKIP_PAGE表示立刻停止执行标签后面的JSP代码,网页上未处理的静态内容和Java程序片段均被忽略,任何已有的输出内容立刻返回到客户的浏览器上。
Tag.EVAL_PAGE表示按正常的流程继续执行JSP文件。
6.public void release()当Servlet容器需要释放Tag对象占用的资源时,会调用此方法。
(2)Servlet容器调用Tag对象的相关方法的流程
1.Servlet容器调用Tag对象的setPageContext()和setParent()方法,把当前JSP页面的PageContext对象及父标签处理对象传给当前Tag对象。如果不存在父标签,则把父标签处理对象设为null。
2.Servlet容器调用Tag对象的一系列set方法,设置Tag对象的属性。如果标签没有属性,则无需这个步骤。
3.Servlet容器调用Tag对象的doStartTag()方法。
4.如果doStartTag()方法返回Tag.SKIP_BODY,就不执行标签主体的内容;如果doStartTag()方法返回Tag.EVAL_BODY_INCLUDE,就执行标签主体的内容。
5.Servlet容器调用Tag对象的doEndTag()方法。
6.如果doEndTag()方法返回Tag.SKIP_PAGE,就不执行标签后续的JSP代码;如果doEndTag()方法返回Tag.EVAL_PAGE,就执行标签后续的JSP代码。
注意:一个Tag对象在被创建后,就会一直存在,可以被Servlet容器重复调用。当Web应用终止时,Serlvet容器会先调用该Web应用中的所有Tag对象的release()方法,然后销毁这些Tag对象。
(3)HelloWorld标签处理类cn.pdsu.HelloTaglib
package cn.pdsu;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;
/**
* 类说明:自定义helloword标签
*
* @author 作者: LiuJunGuang
* @version 创建时间:2011-11-18 下午01:41:09
*/
public class HelloTaglib implements Tag {
private PageContext pc;
public void setPageContext(PageContext pc) {
System.out.println("设置PageContext对象!");
this.pc = pc;
}
public void setParent(Tag t) {
System.out.println("设置标签的父标签!");
}
public Tag getParent() {
System.out.println("得到标签的父标签!");
return null;
}
public int doStartTag() throws JspException {
System.out.println("标签开始处理..");
// 输出helloworld
try {
pc.getOut().println("helloworld");
} catch (IOException e) {
e.printStackTrace();
}
return EVAL_BODY_INCLUDE;// 处理标签中的内容
}
public int doEndTag() throws JspException {
System.out.println("标签结束处理..");
return EVAL_PAGE;// 处理标签之后的jsp内容
}
public void release() {
System.out.println("释放标签资源");
}
}
(4)HelloWorld标签描述TLD文件如下:
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
version="2.1">
<description>My first taglib!</description>
<display-name>MyTaglib</display-name>
<tlib-version>1.0</tlib-version>
<short-name>h</short-name>
<uri>http://www.mytaglib.com/taglib</uri>
<tag>
<name>hello</name>
<tag-class>cn.pdsu.HelloTaglib</tag-class>
<body-content>JSP</body-content>
</tag>
</taglib>
(5)在web.xml中注册标签描述tld文件
添加如下内容:
<jsp-config>
<taglib>
<taglib-uri>http://www.mytaglib.com/taglib</taglib-uri>
<taglib-location>/WEB-INF/hello.tld</taglib-location>
</taglib>
</jsp-config>
(6)在jsp页面中使用标签
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://www.mytaglib.com/taglib" prefix="h" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My first taglib!</title>
</head>
<body>
<h:hello></h:hello>
</body>
</html>
(7)运行结果
设置PageContext对象!
设置标签的父标签!
标签开始处理..
标签结束处理..
二、自定义实现IterationTag接口的标签步骤
(1)IterationTag接口简介
IterationTag接口继承自Tag接口,IterationTag接口增加了重复执行标签主体内容的功能。
IterationTag接口定义了一个doAfterBody()方法,Servlet容器在执行完标签主体内容后,会调用此方法。
如果Serlvet容器未执行标签主体内容,那么就不会调用此方法。
doAfterBody()方法也返回一个整数值,用来决定程序后续流程,它有两个可选值:Tag.SKIP_BODY和IterationTag.EVAL_BODY_AGAIN。
Tag.SKIP_BODY表示不再执行标签主体内容;
IterationTag.EVAL_BODY_AGAIN表示重复执行标签主体内容。
(2)Servlet容器执行IterationTag接口的流程
1.Servlet容器调用IterationTag对象的setPageContext()和setParent()方法,把当前JSP页面的PageContext对象及父标签处理对象传给当前IterationTag对象。如果不存在父标签,则把父标签处理对象设为null。
2.Servlet容器调用IterationTag对象的一系列set方法,设置Tag对象的属性。如果标签没有属性,则无需这个步骤。
3.Servlet容器调用IterationTag对象的doStartTag()方法。
4.如果doStartTag()方法返回Tag.SKIP_BODY,就不执行标签主体的内容;如果doStartTag()方法返回Tag.EVAL_BODY_INCLUDE,就执行标签主体的内容。
5.如果在步骤(4)中Servlet容器执行了标签主体的内容,那么就调用doAfterBody()方法。
6.如果doAfterBody()方法返回Tag.SKIP_BODY,就不再执行标签主体的内容;如果doAfterBody()方法返回IterationTag.EVAL_BODY_AGAIN,就继续重复执行标签主体的内容。
7.Servlet容器调用IterationTag对象的doEndTag()方法。
8.如果doEndTag()方法返回Tag.SKIP_PAGE,就不执行标签后续的JSP代码;如果doEndTag()方法返回Tag.EVAL_PAGE,就执行标签后续的JSP代码。
(3)实例代码见ForTagLib类
三、自定义实现BodyTag接口的标签
(1)BodyTag接口简介
BodyTag接口继承自IterationTag接口,增加了直接访问和操纵标签主体内容的功能。BodyTag接口定义了两个方法。
setBodyContent(BodyContent bc):Servlet容器通过此方法向BodyTag对象传递一个用于缓存标签主体的执行结果的BodyConent对象。
doInitBody():当Servlet容器调用完setBodyContent()方法之后,在第一次执行标签主体之前,先调用此方法,该方法用于为执行标签主体做初始化工作。
(2)只要符合以下两种条件之一,setBodyContent(BodyContent bc)和doInitBody()就不会被Servlet容器调用:
1.标签主体为空。
2.doStartTag()方法的返回值为Tag.SKIP_BODY或者Tag.EVAL_BODY_INCLUDE。
只有同时符合以下两个条件,Servlet容器才会调用setBodyContent(BodyContent bc)和doInitBody()方法:
1.标签主体不为空。
2.doStartTag()方法的返回值为BodyTag.EVAL_BODY_BUFFERED。
以上提到的BodyTag.EVAL_BODY_BUFFERED是在BodyTag接口中定义的int类型的静态常量,它可作为doStartTag()方法的返回值,指示Servlet容器调用BodyTag对象的setBodyContent()和doInitBody()方法。
(3)Servlet容器调用BodyTag对象的流程
1.Servlet容器调用BodyTag对象的setPageContext()和setParent()方法,把当前JSP页面的PageContext对象及父标签处理对象传给当前BodyTag对象。如果不存在父标签,则把父标签处理对象设为null。
2.Servlet容器调用BodyTag对象的一系列set方法,设置Tag对象的属性。如果标签没有属性,则无需这个步骤。
3.Servlet容器调用BodyTag对象的doStartTag()方法。
4.如果doStartTag()方法返回Tag.SKIP_BODY,就不执行标签主体的内容;如果doStartTag()方法返回Tag.EVAL_BODY_INCLUDE,就执行标签主体的内容;如果doStartTag()方法返回BodyTag.EVAL_BODY_BUFFERED,就先调用setBodyContent()和doInitBody()方法,再执行标签主体的内容。
5.如果在步骤(4)中Servlet容器执行了标签主体的内容,那么就调用doAfterBody()方法。
6.如果doAfterBody()方法返回Tag.SKIP_BODY,就不再执行标签主体的内容;如果doAfterBody()方法返回IterationTag.EVAL_BODY_AGAIN,就继续重复执行标签主体的内容。
7.Servlet容器调用BodyTag对象的doEndTag()方法。
8.如果doEndTag()方法返回Tag.SKIP_PAGE,就不执行标签后续的JSP代码;如果doEndTag()方法返回Tag.EVAL_PAGE,就执行标签后续的JSP代码。
四、TagSupport类和BodyTagSupport类
TagSupport类和BodyTagSupport类是标签实现类,其中TagSupport类实现了IterationTag接口,而BodyTagSupport类则继承自TagSupport类,并且实现了BodyTag接口。
用户自定义的标签处理类可以继承TagSupport类或者BodyTagSupport类。
五、创建标签库描述文件
标签库描述文件(Tag Library Descriptor,TLD),采用XML文件格式,对标签库及库中的标签做了描述。TLD文件中的元素可以分为3类:
1.<taglib>:标签库元素。
2.<tag>:标签元素。
3.<attribute>:标签属性元素。
1、标签库元素<taglib>
<taglib>元素的子元素
tlib-version
指定标签库的版本
jsp-version
指定JSP的版本
short-name
指定标签库默认的前缀名(prefix)
uri
设定标签库的唯一访问标识符
info
设定标签库的说明信息
2、标签元素<tag>
name
设定标签的名字
tag-class
设定Tag的处理类
body-content
设定标签主体的类型
info
设定标签的说明信息
empty:标签主体为空。
scriptless:标签主体不为空,并且包含JSP的EL表达式和动作元素,但不能包含JSP的脚本元素。所谓动作元素是指<jsp:include>和<jsp:forward>等以“jsp”为前缀的JSP内置标签。所谓脚本元素是指“<%!”和“%>”、“<%”和“%>”和“<%=”和“%>”这3种以“<%”开头的JSP标记。
JSP:标签主体不为空,并且包含JSP代码。在JSP代码中可以包含EL表达式、动作元素和脚本元素。<body-content>子元素的scriptless可选值与jsp可选值的区别在于前者不能包含JSP的脚本元素。
tagdependant:标签主体不为空,并且标签主体内容由标签处理类来解析和处理。标签主体的所有代码都会原封不动的传给标签处理类,而不是把标签主体的执行结果传给标签处理类。假定用户定义了一个<sql:query>标签,它的<body-content>元素的值为tagdependant。
3、标签属性元素<attribute>
name
属性名称
required
属性是否是必须的,默认为false
rtexprvalue 属性值是否可以为基于“<%=”和“%>”形式的Java表达式或者EL表达式