Java第四十八天,Jsp之Taglib,自定义标签详解

理论知识


一、标签的本质是什么

自定义标签实际上是一个实现了特定接口的Java类,它封装了一些常用功能,在运行时被相应的代码所替换;它与 JavaBean 的最大区别就是 JavaBean 没有默认的上下文(JspContext),但是标签有。

自定义标签由标记处理程序和标签描述组成;

  • 标记处理程序:当遇到特定标记时,标记处理程序就会告诉系统应该做什么,类中包含了要执行的 java 代码
  • 标签描述:声明了怎么使用这个标签
  • 标记:可以带有属性和主体,这些属性和主体是可选的,最简单的标记是既没有属性也没有主体

二、标签接口介绍

JSP 所有的标签都实现了 javax.servlet.jsp.tagext.JspTag 接口;该接口的两个直接子接口如下:

  • SimpleTag ===> JSP2.0 新增加的接口(后文中统一称作简单标签)
  • 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.标签的声明周期

  1. 当容器创建一个新的标签实例后,通过 setPageContext 来设置标签的页面上下文
  2. 使用 setParent 方法设置这个标签的上一级标签,如果没有上一级嵌套,设为 null
  3. 标签的属性,在标签库的描述文件中定义
  4. 调用 doStartTag 方法,这个方法返回 EVAL_BODY_INCLUDE 和 SKIP_BODY(EVAL_BODY_INCLUDE:计算标签的 Body;SKIP_BODY:不计算标签的 Body)
  5. 调用 doEndTag 方法,这个方法返回 EVAL_PAGE 或 SKIP_PAGE(EVAL_PAGE:容器将在结束时继续计算 jsp 页面的其他部分;SKIP_PAGE:容器将在标签结束时停止计算 jsp 页面的其他部分)
  6. 调用 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.创建自定义标签的步骤

  1. 创建标签处理类
  2. 编写、部署标签库描述(TLD)文件
  3. 在 web. xml 文件中配置标签库信息
  4. 在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)自定义标签的调用过程

  1. Web容器根据标签前缀,获得 taglib 指令中的 uri 属性值
  2. Web容器根据 uri 属性在 web.xml 找到对应的<taglib> 元素
  3. 从 <taglib> 元素中获得对应的 <taglib-location> 元素的值
  4. Web容器根据 < taglib-location> 元素的值从 WEB-INF/ 目录下找到对应的td文件
  5. 从 tld 文件中找到与标签名对应的 <tag> 元素
  6. 从 <tag> 元素中获得对应的 <tag- class> 元素的值
  7. Web容器根据<tag-class>元素的值创建相应的标签处理类实例
  8. 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.带有标签体的标签的生命周期:

  1. 当容器创建一个新的标签实例后,通过 setPageContext 来设置标签页面的上下文
  2. 使用 setParent 方法设置这个标签的上一级标签,如果没有上一级嵌套,设置为 null
  3. 设置标签的属性,在标签的描述文件中定义
  4. 调用 doStartTag 方法,如果返回 EVAL_BODY_INCLUDE,就计算标签的 BODY;如果返回SKIP_BODY,就不计算标签的 Body
  5. 调用 setBodyContent 设置当前的 BodyContent
  6. 调用 doInitBody,如果计算 BodyContent 时需要进行初始化,就在这个方法中进行
  7. 每次计算完 BodyTag 后调用 doAfterBody,如果返回 EVAL_BODY_TAG,表示继续计算一次 bodytag,直到返回 SKIP_BODY 才执行第 8 步
  8. 调用 doEndTag 方法,如果返回 EVAL_PAGE 时,容器将在标签结束后继续计算 jsp 页面其他部分;如果返回 SKIP_PAGE,容器将在标签结束时停止计算 jsp 页面的其他部分
  9. 调用 realse()方法释放标签程序占用的任何资源

3.BodyTagSupport 类

① BodyTagSupport 继承自 TagSupport 类,同时实现了 BodyTag 接口

② 该类增加了一个成员变量BodyContent;BodyContent类是JspWriter的子类,主要用于访问标签体,保存标签体处理结果

③ 该类增加了 setBodyContent(BodyContent b)、doInitBody()、doAfterBody() 方法

4.分析修改标签体的步骤

  1. 继承BodyTagSupport类或实现BodyTag接口 
  2. doStartTag()返回 EVAL_BODY_BUFFERED(表示标签体要执行,执行结果放在当前输出流中)
  3. 在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 内容

返回类型 方法名 方法描述
void doTag() 执行业务处理的方法,所有逻辑处理都在这里进行
static JspTag findAncestorWithClass(JspTag from, Class klass) 找到最接近给定实例的给定类类型的实例
protected JspFragment getJspBody() 返回容器通过 setJspBody 传入的 body
protected JspContext getJspContext() 返回容器通过 setJspContext 传入的页面上下文
JspTag getParent() 出于协作目的,返回此标记的父级
void setJspBody(JspFragment jspBody) 存储提供的 JspFragment
void setJspContext(JspContext pc) 将提供的 JSP 上下文存储在私有 jspContext 字段中
void setParent(JspTag parent) 设置此标签的父级,用于协作

SimpleTagSupport 生命周期

  1. 每次遇到标签时,容器构造一个 SimpleTag 的实例,并且这个构造方法没有参数。和传统标签一样,SimpleTag 不能进行缓冲,故不能重用,每次都要构造新的实例
  2. 调用构造方法之后,就调用 setJspContext()和 setParent()方法,只有这个标签在另一个标签之内时,才调用 setParent 方法
  3. 容器调用每个属性的 setter 方法以设置这些属性的值
  4. 如果存在 body,那么就使用 setJspBody 方法来设置这个标签的标签体。
  5. 容器调用 doTag 方法,所有的标签逻辑、迭代和 Body 计算,都在这个方法中
  6. 当 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>

猜你喜欢

转载自blog.csdn.net/ITlanyue/article/details/118674805