理论知识
一、标签的本质是什么
自定义标签实际上是一个实现了特定接口的Java类,它封装了一些常用功能,在运行时被相应的代码所替换;它与 JavaBean 的最大区别就是 JavaBean 没有默认的上下文(JspContext),但是标签有。
自定义标签由标记处理程序和标签描述组成;
- 标记处理程序:当遇到特定标记时,标记处理程序就会告诉系统应该做什么,类中包含了要执行的 java 代码
- 标签描述:声明了怎么使用这个标签
- 标记:可以带有属性和主体,这些属性和主体是可选的,最简单的标记是既没有属性也没有主体
二、标签接口介绍
JSP 所有的标签都实现了 javax.servlet.jsp.tagext.JspTag
- SimpleTag
- Tag ===> 它是经典的、必须实现的接口,它有一个直接子接口就是IterationTag(后文中统一称作传统标签)
Tag 接口有一个直接子接口 IterationTag (后文中统一称作传统标签),该接口继承了 Tag 接口;
Tag 接口有一个直接子接口 TagSupport,该接口实现了 Tag 接口;(TagSupport 接口有一个直接子接口 BodyTagSupport ;它允许带有 body 的标签)
三、自定义标签库基本理论知识
1.自定义标签库体系结构
2.自定义标签处理程序组件
3.基本概念
- 标签(Tag):让JSP页面实现特定功能,通过标签可以使JSP网页变得简洁并且易于维护,是一种XML元素,它的名称和属性都对大小写敏感
- 标签库( Tag library):由一系列功能相似、逻辑上互相联系的标签构成的集合,同一个标签库的“前缀”相同
- 标签库描述文件( Tag Library Descriptor):是一个ⅩML文件,它提供了标签库中类和JSP中标签引用的映射关系,也是一个配置文件,与 web.xm类似
- 标签处理类( Tag Handle Class):是一个Java类,这个类直接或间接的继承了 Tag 接口,也可能实现了Tag或其子接口,通过该类可以自已定义JSP标签的具体功能
4.标签的声明周期
- 当容器创建一个新的标签实例后,通过 setPageContext 来设置标签的页面上下文
- 使用 setParent 方法设置这个标签的上一级标签,如果没有上一级嵌套,设为 null
- 标签的属性,在标签库的描述文件中定义
- 调用 doStartTag 方法,这个方法返回 EVAL_BODY_INCLUDE 和 SKIP_BODY(EVAL_BODY_INCLUDE:计算标签的 Body;SKIP_BODY:不计算标签的 Body)
- 调用 doEndTag 方法,这个方法返回 EVAL_PAGE 或 SKIP_PAGE(EVAL_PAGE:容器将在结束时继续计算 jsp 页面的其他部分;SKIP_PAGE:容器将在标签结束时停止计算 jsp 页面的其他部分)
- 调用 realse()方法释放标签程序占用的任何资源
生命周期中各个函数与关键字的含义:
1.doStartTag()
遇到自定义标签的开始标记时去调用标签处理类的方法,返回值为含义如下
- EVAL_ BODY_INCLUDE(表示标签体要执行,执行结果放在当前输出流中)
- SKP_BODY(不执行标签体)
2.doEndTag()
遇到自定义标签的结束标记时去调用标签处理类的方法;返回值及其含义如下:
- EVAL_PAGE:JSP页面的剩余内容将继续执行
- SKIP_PAGE:Jsp页面的剩余内容不执行
3.doAfterBody()
是 IterationTag 接口増加的方法,在执行完标签体后调用,如果没有标签体,该方法将不会调用。该方法的返回值及其含义如下:
- SKIP_BODY:跳过标签体
- EVAL_BODY_AGAIN:重复执行标签体
4.setBodyContent()
是 BodyTag 接口中设置 bodyContent 属性的方法,以备后面获取标签体内容;只有在 doStartTag() 返回 EVAL_BODY _BUFFERED才执行
5.创建自定义标签的步骤
- 创建标签处理类
- 编写、部署标签库描述(TLD)文件
- 在 web. xml 文件中配置标签库信息
- 在JSP文件中使用标签库
6.标签库描述(TLD)文件
(1)作用
标签库描述(TLD)文件的作用是由标签找到对应的标签处理类
(2)注意事项
标签库描述(TLD)文件的扩展名为tld,是 xml 类型文件,通常放在 META INF 或 WEB-INF 或其子目录中,但不能存放在 WEB\INF\classes 目录和 WEB-INF\Iib目录中
(3)主要标记
url 标记 ===> 为每个自定义标签找到对应的处理类。uri包含了一个字符串,容器用它来定位TLD文件,在TLD文件中可以找到标签库中所有标签处理类的名称,也可以在 web.xml中设置
description 标记 ===> 描述信息
display-name 标记 ===> 被可视化工具用来显示的名称(可选)
tlib-version 标记 ===> 此标签库的版本
shortname 标记 ===> 标签的“前缀”;用来标识标签库,同一标签库的前缀相同
tag 标记 ===> 标签
其中 tag 标记可包含如下子标记
<name>标签名</name>
<tag-class>包名.标签处理类</tag- class>
<attibute>...</ attribute>:可设置属性名、是否必需、属性值是否为运行时的表达式等
<body-content>..</body-content>
<body-content/>标签体可以有4种取值:
- empty(无标签体)
- JSP(默认,标签体可含JSP代码)
- scriptless(标签体可以包含EL、JSP标准动作,但不能有脚本)
- tagdependent(标签体交由标签处理)
(4)自定义标签的调用过程
- Web容器根据标签前缀,获得 taglib 指令中的 uri 属性值
- Web容器根据 uri 属性在 web.xml 找到对应的<taglib> 元素
- 从 <taglib> 元素中获得对应的 <taglib-location> 元素的值
- Web容器根据 < taglib-location> 元素的值从 WEB-INF/ 目录下找到对应的td文件
- 从 tld 文件中找到与标签名对应的 <tag> 元素
- 从 <tag> 元素中获得对应的 <tag- class> 元素的值
- Web容器根据<tag-class>元素的值创建相应的标签处理类实例
- Web容器调用这个实例的 doStartTag/doEndTag 方法完成相应的处理
技术实战
一、基于 Tag 接口开发自定义标签(无属性、无标签体)
1.创建标签处理类
package taglib;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyTaglib implements Tag {
private PageContext pageContext;
private Tag parent;
public MyTaglib() {
super();
}
@Override
public void setPageContext(PageContext pageContext) {
this.pageContext = pageContext;
}
@Override
public void setParent(Tag tag) {
this.parent = tag;
}
@Override
public Tag getParent() {
return this.parent;
}
@Override
public int doStartTag() throws JspException {
//返回 SKIP_BODY,表示不计算标签体
return SKIP_BODY;
}
@Override
public int doEndTag() throws JspException {
try {
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.applyPattern("yyyy-MM-dd HH:mm:ss");
Date date = new Date();// 获取当前时间
pageContext.getOut().write(sdf.format(date));
} catch (IOException e) {
throw new JspTagException(e.getMessage());
}
return EVAL_PAGE;
}
@Override
public void release() {
}
}
2.编写、部署标签库描述(TLD)文件
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<description>学习如何使用 Tag 接口</description>
<tlib-version>1.0</tlib-version>
<!--该属性是设置该标签库下所有标签的前缀-->
<short-name>tools</short-name>
<!--该属性是设置该标签库的唯一 url-->
<uri>/learnTag</uri>
<!--为标签库添加 标签-->
<tag>
<description>基于 Tag 接口的自定义标签</description>
<!--为本标签设置所在标签库下唯一标签名-->
<name>showTime</name>
<!--指明标签处理类的位置-->
<tag-class>taglib.MyTaglib</tag-class>
<!--因为没有标签体所以设为 empty-->
<body-content>empty</body-content>
</tag>
</taglib>
3.在 web. xml 文件中配置标签库信息
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--配置taglib-->
<taglib>
<!--设置标签库唯一 url ;这里的 url 必须与 tld 文件中的 url 一致-->
<taglib-uri>/learnTag</taglib-uri>
<!--指明 tld 标签库描述文件的位置-->
<taglib-location>/WEB-INF/tlds/MyTaglib.tld</taglib-location>
</taglib>
<!---->
</web-app>
4.在JSP文件中使用标签库
<!--配置 taglib 标签库的前缀与 url,这里的前缀与 url 必须与 tld 文件的一致-->
<%@ taglib prefix="tools" uri="/learnTag" %>
<html>
<body>
<!--采取 标签库名:标签名 格式使用指定标签库下的指定标签-->
<tools:showTime/>
</body>
</html>
二、基于 TagSupport 抽象类开发自定义标签(无属性、无标签体)
1.创建标签处理类
注意:继承 TagSupport 抽象类实现自定义标签时,只需要实现 需要用到的方法 即可,即不必实现任何不需要的方法
package tagSupport;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.tagext.TagSupport;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyTaglibSupport extends TagSupport {
@Override
public int doEndTag() throws JspException {
try {
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.applyPattern("yyyy-MM-dd HH:mm:ss");
Date date = new Date();// 获取当前时间
pageContext.getOut().write(sdf.format(date));
} catch (IOException e) {
throw new JspTagException(e.getMessage());
}
return EVAL_PAGE;
}
}
2.编写、部署标签库描述(TLD)文件
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<description>学习如何使用 Tag 接口</description>
<tlib-version>1.0</tlib-version>
<!--该属性是设置该标签库下所有标签的前缀-->
<short-name>tools</short-name>
<!--该属性是设置该标签库的唯一 url-->
<uri>/learnTag</uri>
<!--为标签库添加 标签-->
<tag>
<description>基于 Tag 接口的自定义标签</description>
<!--为本标签设置所在标签库下唯一标签名-->
<name>showTime</name>
<!--指明标签处理类的位置-->
<tag-class>taglib.MyTaglib</tag-class>
<!--因为没有标签体所以设为 empty-->
<body-content>empty</body-content>
</tag>
<!--为标签库添加新的标签-->
<tag>
<!--为本标签设置所在标签库下唯一标签名-->
<name>showTimeV2</name>
<!--指明标签处理类的位置-->
<tag-class>tagSupport.MyTaglibSupport</tag-class>
<!--因为没有标签体所以设为 empty-->
<body-content>empty</body-content>
</tag>
</taglib>
3.在 web. xml 文件中配置标签库信息
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--配置taglib-->
<taglib>
<!--设置标签库唯一 url ;这里的 url 必须与 tld 文件中的 url 一致-->
<taglib-uri>/learnTag</taglib-uri>
<!--指明 tld 标签库描述文件的位置-->
<taglib-location>/WEB-INF/tlds/MyTaglib.tld</taglib-location>
</taglib>
<!---->
</web-app>
4.在JSP文件中使用标签库
<%@ taglib prefix="tools" uri="/learnTag" %>
<html>
<body>
<!--采取 标签库名:标签名 指明要使用的标签-->
<tools:showTimeV2/>
</body>
</html>
三、基于 TagSupport 抽象类开发自定义标签(有属性、无标签体)
1.创建标签处理类
package tagSupport;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.tagext.TagSupport;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyTaglibSupportAttr extends TagSupport {
// 对于有属性的标签,需要在标签处理类中设置同名的属性,并为属性设置 get 和 set 方法
private String country;
private String city;
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public int doEndTag() throws JspException {
try {
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.applyPattern("yyyy-MM-dd HH:mm:ss");
Date date = new Date();// 获取当前时间
pageContext.getOut().write(country + "-" + city + ": " + sdf.format(date));
} catch (IOException e) {
throw new JspTagException(e.getMessage());
}
return EVAL_PAGE;
}
}
2.编写、部署标签库描述(TLD)文件
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<description>学习如何使用 Tag 接口</description>
<tlib-version>1.0</tlib-version>
<!--该属性是设置该标签库下所有标签的前缀-->
<short-name>tools</short-name>
<!--该属性是设置该标签库的唯一 url-->
<uri>/learnTag</uri>
<!--为标签库添加 标签-->
<tag>
<description>基于 Tag 接口的自定义标签</description>
<!--为本标签设置所在标签库下唯一标签名-->
<name>showTime</name>
<!--指明标签处理类的位置-->
<tag-class>taglib.MyTaglib</tag-class>
<!--因为没有标签体所以设为 empty-->
<body-content>empty</body-content>
</tag>
<!--为标签库添加新的标签-->
<tag>
<!--为本标签设置所在标签库下唯一标签名-->
<name>showTimeV2</name>
<!--指明标签处理类的位置-->
<tag-class>tagSupport.MyTaglibSupport</tag-class>
<!--因为没有标签体所以设为 empty-->
<body-content>empty</body-content>
</tag>
<tag>
<name>showTimeV3</name>
<tag-class>tagSupport.MyTaglibSupportAttr</tag-class>
<body-content>empty</body-content>
<attribute>
<!--设置属性名,必须与标签处理类中的属性名一致-->
<name>country</name>
<!--设置该属性是否必须-->
<required>true</required>
<!--设置是否支持 EL 表达式赋值-->
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<!--设置属性名,必须与标签处理类中的属性名一致-->
<name>city</name>
<!--设置该属性是否必须-->
<required>true</required>
<!--设置是否支持 EL 表达式赋值-->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
3.在 web. xml 文件中配置标签库信息
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--配置taglib-->
<taglib>
<!--设置标签库唯一 url ;这里的 url 必须与 tld 文件中的 url 一致-->
<taglib-uri>/learnTag</taglib-uri>
<!--指明 tld 标签库描述文件的位置-->
<taglib-location>/WEB-INF/tlds/MyTaglib.tld</taglib-location>
</taglib>
<!---->
</web-app>
4.在JSP文件中使用标签库
<%@ taglib prefix="tools" uri="/learnTag" %>
<html>
<body>
<!--采取 标签库名:标签名 指明要使用的标签-->
<tools:showTimeV3 country="china" city="shi_jia_zhuang"/>
</body>
</html>
四、基于 BodyTagSupport 抽象类开发自定义标签(有属性、有标签体)
1.注意事项
带有 body 的 Tag 必须实现 javax.servlet.jsp.tagext.BodyTag 接口,BodyTag 接口中定义了处理标签的方法;
2.带有标签体的标签的生命周期:
- 当容器创建一个新的标签实例后,通过 setPageContext 来设置标签页面的上下文
- 使用 setParent 方法设置这个标签的上一级标签,如果没有上一级嵌套,设置为 null
- 设置标签的属性,在标签的描述文件中定义
- 调用 doStartTag 方法,如果返回 EVAL_BODY_INCLUDE,就计算标签的 BODY;如果返回SKIP_BODY,就不计算标签的 Body
- 调用 setBodyContent 设置当前的 BodyContent
- 调用 doInitBody,如果计算 BodyContent 时需要进行初始化,就在这个方法中进行
- 每次计算完 BodyTag 后调用 doAfterBody,如果返回 EVAL_BODY_TAG,表示继续计算一次 bodytag,直到返回 SKIP_BODY 才执行第 8 步
- 调用 doEndTag 方法,如果返回 EVAL_PAGE 时,容器将在标签结束后继续计算 jsp 页面其他部分;如果返回 SKIP_PAGE,容器将在标签结束时停止计算 jsp 页面的其他部分
- 调用 realse()方法释放标签程序占用的任何资源
3.BodyTagSupport 类
① BodyTagSupport 继承自 TagSupport 类,同时实现了 BodyTag 接口
② 该类增加了一个成员变量BodyContent;BodyContent类是JspWriter的子类,主要用于访问标签体,保存标签体处理结果
③ 该类增加了 setBodyContent(BodyContent b)、doInitBody()、doAfterBody() 方法
4.分析修改标签体的步骤
- 继承BodyTagSupport类或实现BodyTag接口
- doStartTag()返回 EVAL_BODY_BUFFERED(表示标签体要执行,执行结果放在当前输出流中)
- 在doAfterBody()方法中处理标签体(调用getBodyContent()、 BodyContent的有关方法,获取标签体内容,并将程序处理结果存放到输出流
由上可知,要得到标签体内容并进行修改,需要用到一个重要类— BodyContent,它有两个重要方法
String getString():以字符串方式返回标签体内容
public JspWriter getEnclosingWriter():得到封装的JspWriter对象
1.创建标签处理类
package tagSupport;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.TagSupport;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyTaglibSupportAttrBody extends BodyTagSupport {
// 对于有属性的标签,需要在标签处理类中设置同名的属性,并为属性设置 get 和 set 方法
private String country;
private String city;
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public int doStartTag() throws JspException {
return EVAL_BODY_BUFFERED;
}
@Override
public int doEndTag() throws JspException {
return EVAL_PAGE;
}
@Override
public void doInitBody() throws JspException {
super.doInitBody();
}
@Override
public int doAfterBody() throws JspException {
JspWriter out = bodyContent.getEnclosingWriter();
try {
out.println(bodyContent.getString() + country + "-" +city + "<br/>");
} catch (IOException e) {
e.printStackTrace();
}
bodyContent.clearBody();
return super.doAfterBody();
}
}
2.编写、部署标签库描述(TLD)文件
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<description>学习如何使用 Tag 接口</description>
<tlib-version>1.0</tlib-version>
<!--该属性是设置该标签库下所有标签的前缀-->
<short-name>tools</short-name>
<!--该属性是设置该标签库的唯一 url-->
<uri>/learnTag</uri>
<!--为标签库添加 标签-->
<tag>
<description>基于 Tag 接口的自定义标签</description>
<!--为本标签设置所在标签库下唯一标签名-->
<name>showTime</name>
<!--指明标签处理类的位置-->
<tag-class>taglib.MyTaglib</tag-class>
<!--因为没有标签体所以设为 empty-->
<body-content>empty</body-content>
</tag>
<!--为标签库添加新的标签-->
<tag>
<!--为本标签设置所在标签库下唯一标签名-->
<name>showTimeV2</name>
<!--指明标签处理类的位置-->
<tag-class>tagSupport.MyTaglibSupport</tag-class>
<!--因为没有标签体所以设为 empty-->
<body-content>empty</body-content>
</tag>
<tag>
<name>showTimeV3</name>
<tag-class>tagSupport.MyTaglibSupportAttr</tag-class>
<body-content>empty</body-content>
<attribute>
<!--设置属性名,必须与标签处理类中的属性名一致-->
<name>country</name>
<!--设置该属性是否必须-->
<required>true</required>
<!--设置是否支持 EL 表达式赋值-->
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<!--设置属性名,必须与标签处理类中的属性名一致-->
<name>city</name>
<!--设置该属性是否必须-->
<required>true</required>
<!--设置是否支持 EL 表达式赋值-->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>showTimeV4</name>
<tag-class>tagSupport.MyTaglibSupportAttrBody</tag-class>
<body-content>JSP</body-content>
<attribute>
<!--设置属性名,必须与标签处理类中的属性名一致-->
<name>country</name>
<!--设置该属性是否必须-->
<required>true</required>
<!--设置是否支持 EL 表达式赋值-->
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<!--设置属性名,必须与标签处理类中的属性名一致-->
<name>city</name>
<!--设置该属性是否必须-->
<required>true</required>
<!--设置是否支持 EL 表达式赋值-->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
3.在 web. xml 文件中配置标签库信息
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--配置taglib-->
<taglib>
<!--设置标签库唯一 url ;这里的 url 必须与 tld 文件中的 url 一致-->
<taglib-uri>/learnTag</taglib-uri>
<!--指明 tld 标签库描述文件的位置-->
<taglib-location>/WEB-INF/tlds/MyTaglib.tld</taglib-location>
</taglib>
<!---->
</web-app>
4.在JSP文件中使用标签库
<%@ taglib prefix="tools" uri="/learnTag" %>
<html>
<body>
<!--采取 标签库名:标签名 指明要使用的标签-->
<tools:showTimeV4 country="china" city="shi_jia_zhuang">
My home is in :
</tools:showTimeV4>
</body>
</html>
五、基于 SimpleTag 接口开发自定义标签(有属性、无标签体)
SimpleTag 是JSP2.0 规范新增的一种类型标签,简化了传统标签开发中的复杂操作;
JSP 2.0 中加入了新的创建自制标记的 API,javax.servlet.jsp.tagext.SimpleTag 定义了用来实现简单标记的接口。和JSP 1.2中的已有接口不同的是,SimpleTag接口不使用 doStartTag()和 doEndTag()方法,而提供了一个简单的 doTag()方法。这个方法在调用该标记时只被使用一次。而需要在一个自制标记中实现的所有逻辑过程、循环和对标记体的评估等都在这个方法中实现。
从这个方面来讲,SimpleTag 和 IterationTag 可以达到同等的作用。但 SimpleTag的方法和处理周期要简单得多。在 SimpleTag 中还有用来设置 JSP 内容的 seJspBody()和getJspBody()方法。Web 容器会使用 setJspBody()方法定义一个代表 JSP 内容的 JspFragment 对 象 。 实 现 SimpleTag 标 记 的 程 序 可 以 在 doTag 方 法 中 根 据 需 要 多 次 调 用getJspBody().invoke()方法以处理 JSP 内容
返回类型方法名方法描述voiddoTag()执行业务处理的方法,所有逻辑处理都在这里进行static JspTagfindAncestorWithClass(JspTag from, Class klass)找到最接近给定实例的给定类类型的实例protected JspFragmentgetJspBody()返回容器通过 setJspBody 传入的 bodyprotected JspContextgetJspContext()返回容器通过 setJspContext 传入的页面上下文JspTaggetParent()出于协作目的,返回此标记的父级voidsetJspBody(JspFragment jspBody)存储提供的 JspFragmentvoidsetJspContext(JspContext pc)将提供的 JSP 上下文存储在私有 jspContext 字段中voidsetParent(JspTag parent)设置此标签的父级,用于协作
SimpleTagSupport 生命周期
- 每次遇到标签时,容器构造一个 SimpleTag 的实例,并且这个构造方法没有参数。和传统标签一样,SimpleTag 不能进行缓冲,故不能重用,每次都要构造新的实例
- 调用构造方法之后,就调用 setJspContext()和 setParent()方法,只有这个标签在另一个标签之内时,才调用 setParent 方法
- 容器调用每个属性的 setter 方法以设置这些属性的值
- 如果存在 body,那么就使用 setJspBody 方法来设置这个标签的标签体。
- 容器调用 doTag 方法,所有的标签逻辑、迭代和 Body 计算,都在这个方法中
- 当 doTag 方法返回时,所有的参数被锁定
1.创建标签处理类
package simpleTablib;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.io.IOException;
public class MySimpleTaglib extends SimpleTagSupport {
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Override
public void doTag() throws JspException, IOException {
getJspContext().getOut().println("Your name is " + userName);
}
}
2.编写、部署标签库描述(TLD)文件
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<description>学习如何使用 Tag 接口</description>
<tlib-version>1.0</tlib-version>
<!--该属性是设置该标签库下所有标签的前缀-->
<short-name>tools</short-name>
<!--该属性是设置该标签库的唯一 url-->
<uri>/learnTag</uri>
<!--为标签库添加 标签-->
<tag>
<description>基于 Tag 接口的自定义标签</description>
<!--为本标签设置所在标签库下唯一标签名-->
<name>showTime</name>
<!--指明标签处理类的位置-->
<tag-class>taglib.MyTaglib</tag-class>
<!--因为没有标签体所以设为 empty-->
<body-content>empty</body-content>
</tag>
<!--为标签库添加新的标签-->
<tag>
<!--为本标签设置所在标签库下唯一标签名-->
<name>showTimeV2</name>
<!--指明标签处理类的位置-->
<tag-class>tagSupport.MyTaglibSupport</tag-class>
<!--因为没有标签体所以设为 empty-->
<body-content>empty</body-content>
</tag>
<tag>
<name>showTimeV3</name>
<tag-class>tagSupport.MyTaglibSupportAttr</tag-class>
<body-content>empty</body-content>
<attribute>
<!--设置属性名,必须与标签处理类中的属性名一致-->
<name>country</name>
<!--设置该属性是否必须-->
<required>true</required>
<!--设置是否支持 EL 表达式赋值-->
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<!--设置属性名,必须与标签处理类中的属性名一致-->
<name>city</name>
<!--设置该属性是否必须-->
<required>true</required>
<!--设置是否支持 EL 表达式赋值-->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>showTimeV4</name>
<tag-class>tagSupport.MyTaglibSupportAttrBody</tag-class>
<body-content>JSP</body-content>
<attribute>
<!--设置属性名,必须与标签处理类中的属性名一致-->
<name>country</name>
<!--设置该属性是否必须-->
<required>true</required>
<!--设置是否支持 EL 表达式赋值-->
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<!--设置属性名,必须与标签处理类中的属性名一致-->
<name>city</name>
<!--设置该属性是否必须-->
<required>true</required>
<!--设置是否支持 EL 表达式赋值-->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>showName</name>
<tag-class>simpleTablib.MySimpleTaglib</tag-class>
<body-content>empty</body-content>
<attribute>
<!--设置属性名,必须与标签处理类中的属性名一致-->
<name>userName</name>
<!--设置该属性是否必须-->
<required>true</required>
<!--设置是否支持 EL 表达式赋值-->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
3.在 web. xml 文件中配置标签库信息
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--配置taglib-->
<taglib>
<!--设置标签库唯一 url ;这里的 url 必须与 tld 文件中的 url 一致-->
<taglib-uri>/learnTag</taglib-uri>
<!--指明 tld 标签库描述文件的位置-->
<taglib-location>/WEB-INF/tlds/MyTaglib.tld</taglib-location>
</taglib>
<!---->
</web-app>
4.在JSP文件中使用标签库
<%@ taglib prefix="tools" uri="/learnTag" %>
<html>
<body>
<!--采取 标签库名:标签名 指明要使用的标签-->
<tools:showName userName="John"/>
</body>
</html>