深入分析JavaWeb 23 -- jsp自定义标签开发入门

一、自定义标签的作用

  自定义标签主要用于移除Jsp页面中的java代码。

二、自定义标签开发和使用

2.1、自定义标签开发步骤

   1、编写一个实现Tag接口的Java类(标签处理器类)

要编写一个自定义标签,首先要实现一个Tag接口的类。但是Jsp内部已经有实现该接口的类,我们先自己实现一个。

package me.gacl.web.tag;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;

public class ViewIPTag implements Tag {

    //接收传递进来的PageContext对象
    private PageContext pageContext;

    @Override
    public int doEndTag() throws JspException {
        System.out.println("调用doEndTag()方法");
        return 0;
    }

    @Override
    public int doStartTag() throws JspException {
        System.out.println("调用doStartTag()方法");
        HttpServletRequest request =(HttpServletRequest) pageContext.getRequest();
        JspWriter out = pageContext.getOut();
        String ip = request.getRemoteAddr();
        try {
            //这里输出的时候会抛出IOException异常
            out.write(ip);
        } catch (IOException e) {
            //捕获IOException异常后继续抛出
            throw new RuntimeException(e);
        }
        return 0;
    }

    @Override
    public Tag getParent() {
        return null;
    }

    @Override
    public void release() {
        System.out.println("调用release()方法");
    }

    @Override
    public void setPageContext(PageContext pageContext) {
        System.out.println("setPageContext(PageContext pageContext)");
        this.pageContext = pageContext;
    }

    @Override
    public void setParent(Tag arg0) {

    }

}

  2、在WEB-INF/目录下新建tld文件,在tld文件中对标签处理器类进行描述

  深入分析JavaWeb 23 -- jsp自定义标签开发入门_第1张图片

  这里的标签描述可以抄写tomcat服务器example里的例子,抄头抄屁股就可以了。gacl.tld文件的代码如下:

<?xml version="1.0" encoding="UTF-8" ?>

<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用来添加对taglib(标签库)的描述 -->
    <description>孤傲苍狼开发的自定义标签库</description>
    <!--taglib(标签库)的版本号 -->
    <tlib-version>1.0</tlib-version>
    <short-name>GaclTagLibrary</short-name>
    <!-- 为自定义标签库设置一个uri,uri以/开头,/后面的内容随便写,如这里的/gacl , 在Jsp页面中引用标签库时,需要通过uri找到标签库 在Jsp页面中就要这样引入标签库:<%@taglib uri="/gacl" prefix="gacl"%> -->
    <uri>/gacl</uri>

    <!--一个taglib(标签库)中包含多个自定义标签,每一个自定义标签使用一个tag标记来描述 -->
    <!-- 一个tag标记对应一个自定义标签 -->
     <tag>
        <description>这个标签的作用是用来输出客户端的IP地址</description>
        <!-- 为标签处理器类配一个标签名,在Jsp页面中使用标签时是通过标签名来找到要调用的标签处理器类的 通过viewIP就能找到对应的me.gacl.web.tag.ViewIPTag类 -->
        <name>viewIP</name>
        <!-- 标签对应的处理器类-->
        <tag-class>me.gacl.web.tag.ViewIPTag</tag-class>
        <body-content>empty</body-content>
    </tag>

</taglib>

2.2、在Jsp页面中使用自定义标签

  1、使用”<%@taglib uri=”标签库的uri” prefix=”标签的使用前缀”%>”指令引入要使用的标签库。

例如:在jspTag_Test1.jsp中引用gacl标签库

<%@ page language="java" pageEncoding="UTF-8"%>
<!-- 使用taglib指令引用gacl标签库,标签库的前缀(prefix)可以随便设置,如这里设置成 prefix="xdp" -->
<%@taglib uri="/gacl" prefix="xdp"%>
<!DOCTYPE HTML>
<html>
  <head>
    <title>输出客户端的IP</title>
  </head>

  <body>
    你的IP地址是(使用java代码获取输出):
    <% //在jsp页面中使用java代码获取客户端IP地址 String ip = request.getRemoteAddr(); out.write(ip); %>
    <hr/>
     你的IP地址是(使用自定义标签获取输出):
     <%--使用自定义标签viewIP --%>
     <xdp:viewIP/>
  </body>
</html>

  标签的运行效果如下:

  深入分析JavaWeb 23 -- jsp自定义标签开发入门_第2张图片

  从运行效果种可以看到,使用自定义标签就可以将jsp页面上的java代码移除掉,如需要在jsp页面上输出客户端的IP地址时,使用 <xdp:viewIP/>标签就可以代替jsp页面上的这些代码:

 <%
         //在jsp页面中使用java代码获取客户端IP地址
         String ip = request.getRemoteAddr();
         out.write(ip);
 %>

  这就是开发和使用自定义标签的好处,可以让我们的Jsp页面上不嵌套java代码。

三、自定义标签的执行流程

  JSP引擎遇到自定义标签时,首先创建标签处理器类的实例对象,然后按照JSP规范定义的通信规则依次调用它的方法。
  
1、public void setPageContext(PageContext pc), JSP引擎实例化标签处理器后,将调用setPageContext方法将JSP页面的pageContext对象传递给标签处理器,标签处理器以后可以通过这个pageContext对象与JSP页面进行通信。

2、public void setParent(Tag t),setPageContext方法执行完后,WEB容器接着调用的setParent方法将当前标签的父标签传递给当前标签处理器,如果当前标签没有父标签,则传递给setParent方法的参数值为null。

3、public int doStartTag(),调用了setPageContext方法和setParent方法之后,WEB容器执行到自定义标签的开始标记时,就会调用标签处理器的doStartTag方法。

4、public int doEndTag(),WEB容器执行完自定义标签的标签体后,就会接着去执行自定义标签的结束标记,此时,WEB容器会去调用标签处理器的doEndTag方法。

5、public void release(),通常WEB容器执行完自定义标签后,标签处理器会驻留在内存中,为其它请求服务器,直至停止web应用时,web容器才会调用release方法。

调用图如下所示

深入分析JavaWeb 23 -- jsp自定义标签开发入门_第3张图片
深入分析JavaWeb 23 -- jsp自定义标签开发入门_第4张图片

我们在tomcat服务器的"work\Catalina\localhost\JavaWeb_JspTag_study_20140816\org\apache\jsp“目录下可以找到将jspTag_Test1.jsp翻译成Servlet后的java源代码,如下图所示:

这里写图片描述

  打开jspTag_005fTest1_jsp.java文件,可以看到setPageContext(PageContext pc)、setParent(Tag t)、doStartTag()、doEndTag()、release()这5个方法的调用顺序和过程。

  jspTag_005fTest1_jsp.java的代码如下:

      out.write(" 你的IP地址是(使用java代码获取输出):\r\n");
      out.write(" ");

        //在jsp页面中使用java代码获取客户端IP地址
        String ip = request.getRemoteAddr();
        out.write(ip);

      out.write("\r\n");
      out.write(" <hr/>\r\n");
      out.write(" 你的IP地址是(使用自定义标签获取输出):");
      if (_jspx_meth_xdp_005fviewIP_005f0(_jspx_page_context))
        return;
      out.write("\r\n");
      out.write(" </body>\r\n");
      out.write("</html>\r\n");
    } catch (Throwable t) {
      if (!(t instanceof SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try { out.clearBuffer(); } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }

  private boolean _jspx_meth_xdp_005fviewIP_005f0(PageContext _jspx_page_context)
          throws Throwable {
    PageContext pageContext = _jspx_page_context;
    JspWriter out = _jspx_page_context.getOut();
    //  xdp:viewIP
    me.gacl.web.tag.ViewIPTag _jspx_th_xdp_005fviewIP_005f0 = (me.gacl.web.tag.ViewIPTag) _005fjspx_005ftagPool_005fxdp_005fviewIP_005fnobody.get(me.gacl.web.tag.ViewIPTag.class);
    _jspx_th_xdp_005fviewIP_005f0.setPageContext(_jspx_page_context);
    _jspx_th_xdp_005fviewIP_005f0.setParent(null);
    int _jspx_eval_xdp_005fviewIP_005f0 = _jspx_th_xdp_005fviewIP_005f0.doStartTag();
    if (_jspx_th_xdp_005fviewIP_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
      _005fjspx_005ftagPool_005fxdp_005fviewIP_005fnobody.reuse(_jspx_th_xdp_005fviewIP_005f0);
      return true;
    }
    _005fjspx_005ftagPool_005fxdp_005fviewIP_005fnobody.reuse(_jspx_th_xdp_005fviewIP_005f0);
    return false;
  }
}

  下面重点分析一下 private boolean _jspx_meth_xdp_005fviewIP_005f0(PageContext _jspx_page_context)方法中的代码

  ①、这里是实例化一个viewIP标签处理器类me.gacl.web.tag.ViewIPTag的对象

//  xdp:viewIP
     me.gacl.web.tag.ViewIPTag _jspx_th_xdp_005fviewIP_005f0 = (me.gacl.web.tag.ViewIPTag) _005fjspx_005ftagPool_005fxdp_005fviewIP_005fnobody.get(me.gacl.web.tag.ViewIPTag.class);

  ②、实例化标签处理器后,调用setPageContext方法将JSP页面的pageContext对象传递给标签处理器

_jspx_th_xdp_005fviewIP_005f0.setPageContext(_jspx_page_context);

  ③、setPageContext方法执行完后,接着调用的setParent方法将当前标签的父标签传递给当前标签处理器,如果当前标签没有父标签,则传递给setParent方法的参数值为null

 _jspx_th_xdp_005fviewIP_005f0.setParent(null);

  ④、调用了setPageContext方法和setParent方法之后,WEB容器执行到自定义标签的开始标记时,就会调用标签处理器的doStartTag方法

 int _jspx_eval_xdp_005fviewIP_005f0 = _jspx_th_xdp_005fviewIP_005f0.doStartTag();

  ⑤、WEB容器执行完自定义标签的标签体后,就会接着去执行自定义标签的结束标记,此时,WEB容器会去调用标签处理器的doEndTag方法

 if (_jspx_th_xdp_005fviewIP_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE)

  这就是自定义标签的执行流程。

  这里以一个入门级的案例来讲解javaweb的自定义标签开发。

四、自定义标签技术的API

4.1、标签技术的API类继承关系

  深入分析JavaWeb 23 -- jsp自定义标签开发入门_第5张图片

五、标签API简单介绍

5.1、JspTag接口

  JspTag接口是所有自定义标签的父接口,它是JSP2.0中新定义的一个标记接口,没有任何属性和方法。JspTag接口有Tag和SimpleTag两个直接子接口,JSP2.0以前的版本中只有Tag接口,所以把实现Tag接口的自定义标签也叫做传统标签,把实现SimpleTag接口的自定义标签叫做简单标签。

5.2、Tag接口

  Tag接口是所有传统标签的父接口,其中定义了两个重要方法(doStartTag、doEndTag)方法和四个常量(EVAL_BODY_INCLUDESKIP_BODYEVAL_PAGESKIP_PAGE),这两个方法和四个常量的作用如下:

  (1)WEB容器在解释执行JSP页面的过程中,遇到自定义标签的开始标记就会去调用标签处理器的doStartTag方法,doStartTag方法执行完后可以向WEB容器返回常量EVAL_BODY_INCLUDESKIP_BODY。如果doStartTag方法返回EVAL_BODY_INCLUDE,WEB容器就会接着执行自定义标签的标签体;如果doStartTag方法返回SKIP_BODY,WEB容器就会忽略自定义标签的标签体,直接解释执行自定义标签的结束标记。

  (2)WEB容器解释执行到自定义标签的结束标记时,就会调用标签处理器的doEndTag方法,doEndTag方法执行完后可以向WEB容器返回常量EVAL_PAGESKIP_PAGE。如果doEndTag方法返回常量EVAL_PAGE,WEB容器就会接着执行JSP页面中位于结束标记后面的JSP代码;如果doEndTag方法返回SKIP_PAGE,WEB容器就会忽略JSP页面中位于结束标记后面的所有内容。

  从doStartTag和doEndTag方法的作用和返回值的作用可以看出,开发自定义标签时可以在doStartTag方法和doEndTag方法体内编写合适的Java程序代码来实现具体的功能,通过控制doStartTag方法和doEndTag方法的返回值,还可以告诉WEB容器是否执行自定义标签中的标签体内容和JSP页面中位于自定义标签的结束标记后面的内容。

5.3、IterationTag接口

  IterationTag接口继承了Tag接口,并在Tag接口的基础上增加了一个doAfterBody方法和一个EVAL_BODY_AGAIN常量。实现IterationTag接口的标签除了可以完成Tag接口所能完成的功能外,还能够通知WEB容器是否重复执行标签体内容。对于实现了IterationTag接口的自定义标签,WEB容器在执行完自定义标签的标签体后,将调用标签处理器的doAfterBody方法,doAfterBody方法可以向WEB容器返回常量EVAL_BODY_AGAINSKIP_BODY。如果doAfterBody方法返回EVAL_BODY_AGAIN,WEB容器就会把标签体内容再重复执行一次,执行完后接着再调用doAfterBody方法,如此往复,直到doAfterBody方法返回常量SKIP_BODY,WEB容器才会开始处理标签的结束标记和调用doEndTag方法。

  可见,开发自定义标签时,可以通过控制doAfterBody方法的返回值来告诉WEB容器是否重复执行标签体内容,从而达到循环处理标签体内容的效果。例如,可以通过一个实现IterationTag接口的标签来迭代输出一个集合中的所有元素,在标签体部分指定元素的输出格式。

  在JSP API中也提供了IterationTag接口的默认实现类TagSupport,我们在编写自定义标签的标签处理器类时,可以继承和扩展TagSupport类,这相比实现IterationTag接口将简化开发工作。

5.4、BodyTag接口

  BodyTag接口继承了IterationTag接口,并在IterationTag接口的基础上增加了两个方法(setBodyContent、doInitBody)和一个EVAL_BODY_BUFFERED常量。实现BodyTag接口的标签除了可以完成IterationTag接口所能完成的功能,还可以对标签体内容进行修改。对于实现了BodyTag接口的自定义标签,标签处理器的doStartTag方法不仅可以返回前面讲解的常量EVAL_BODY_INCLUDE或SKIP_BODY,还可以返回常量EVAL_BODY_BUFFERED。如果doStartTag方法返回EVAL_BODY_BUFFERED,WEB容器就会创建一个专用于捕获标签体运行结果的BodyContent对象,然后调用标签处理器的setBodyContent方法将BodyContent对象的引用传递给标签处理器,WEB容器接着将标签体的执行结果写入到BodyContent对象中。在标签处理器的后续事件方法中,可以通过先前保存的BodyContent对象的引用来获取标签体的执行结果,然后调用BodyContent对象特有的方法对BodyContent对象中的内容(即标签体的执行结果)进行修改和控制其输出。

  在JSP API中也提供了BodyTag接口的实现类BodyTagSupport,我们在编写能够修改标签体内容的自定义标签的标签处理器类时,可以继承和扩展BodyTagSupport类,这相比实现BodyTag接口将简化开发工作。

5.5、 SimpleTag接口

  SimpleTag接口是JSP2.0中新增的一个标签接口。由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广,因此,SUN公司为降低标签技术的学习难度,在JSP 2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口。SimpleTag接口与传统标签接口最大的区别在于,SimpleTag接口只定义了一个用于处理标签逻辑的doTag方法,该方法在WEB容器执行自定义标签时调用,并且只被调用一次。那些使用传统标签接口所完成的功能,例如是否执行标签体、迭代标签体、对标签体内容进行修改等功能都可以在doTag方法中完成。

  在JSP API中也提供了SimpleTag接口的实现类SimpleTagSupport,我们在编写简单标签时,可以继承和扩展SimpleTagSupport类,这相比实现SimpleTag接口将简化开发工作。

5.6、传统标签接口中的各个方法可以返回的返回值说明

  下图列举了Tag接口、IterationTag接口和BodyTag接口中的主要方法及它们分别可以返回的返回值的说明。

  深入分析JavaWeb 23 -- jsp自定义标签开发入门_第6张图片

六、开发传统标签实现页面逻辑

  开发人员在编写Jsp页面时,经常还需要在页面中引入一些逻辑,例如:

  • 控制jsp页面某一部分内容是否执行。
  • 控制整个jsp页面是否执行。
  • 控制jsp页面内容重复执行。
  • 修改jsp页面内容输出。

      自定义标签除了可以移除jsp页面java代码外,它也可以实现以上功能。

6.1、控制jsp页面某一部分内容是否执行  

  编写一个类实现tag接口,控制doStartTag()方法的返回值,如果这个方法返回EVAL_BODY_INCLUDE,则执行标签体,如果返回SKIP_BODY,则不执行标签体。

  SUN公司针对tag接口提供了一个默认的实现类TagSupport,TagSupport类中实现了tag接口的所有方法,因此我们可以编写一个类继承TagSupport类,然后再重写doStartTag方法。

示例代码如下:

TagDemo1.java

package me.gacl.web.tag;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;

/** * @author gacl * TagSupport类实现了Tag接口,TagDemo1继承TagSupport类 * */
public class TagDemo1 extends TagSupport {

    /* 重写doStartTag方法,控制标签体是否执行 * @see javax.servlet.jsp.tagext.TagSupport#doStartTag() */
    @Override
    public int doStartTag() throws JspException {
        //如果这个方法返回EVAL_BODY_INCLUDE,则执行标签体,如果返回SKIP_BODY,则不执行标签体
        //return Tag.EVAL_BODY_INCLUDE;
        return Tag.SKIP_BODY;
    }
}

  在WEB-INF目录下的tld文件中添加对该标签处理类的描述,如下:

 <tag>
         <name>demo1</name>
         <tag-class>me.gacl.web.tag.TagDemo1</tag-class>
         <!--demo1标签有标签体,所以这里的body-content设置为JSP-->
         <body-content>JSP</body-content>
 </tag>

  在jsp页面中导入并使用自定义标签,如下:

<%@ page language="java" pageEncoding="UTF-8"%>
<%--在jsp页面中导入自定义标签库 --%>
<%@taglib uri="/gacl" prefix="gacl" %>
<!DOCTYPE HTML>
<html>
  <head>
    <title>控制标签体是否执行</title>
  </head>

  <body>
  <%--在jsp页面中使用自定义标签 demo1标签是带有标签体的,标签体的内容是"孤傲苍狼"这几个字符串--%>
    <gacl:demo1>
        孤傲苍狼
    </gacl:demo1>
  </body>
</html>

  运行效果如下:

深入分析JavaWeb 23 -- jsp自定义标签开发入门_第7张图片

6.2、控制整个jsp页面是否执行

  编写一个类实现tag接口,控制doEndTag()方法的返回值,如果这个方法返回EVAL_PAGE,则执行标签余下的jsp页面,如果返回SKIP_PAGE,则不执行余下的jsp。

示例代码如下:

TagDemo2.java

package me.gacl.web.tag;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;

/** * @author gacl * TagSupport类实现了Tag接口,TagDemo2继承TagSupport类 */
public class TagDemo2 extends TagSupport{

    /* 重写doEndTag方法,控制jsp页面是否执行 * @see javax.servlet.jsp.tagext.TagSupport#doEndTag() */
    @Override
    public int doEndTag() throws JspException {
        //如果这个方法返回EVAL_PAGE,则执行标签余下的jsp页面,如果返回SKIP_PAGE,则不执行余下的jsp
        return Tag.SKIP_PAGE;
        //return Tag.EVAL_PAGE;
    }


}

  在WEB-INF目录下的tld文件中添加对该标签处理类的描述,如下:

 <tag>
         <name>demo2</name>
         <tag-class>me.gacl.web.tag.TagDemo2</tag-class>
         <!--demo2标签没有标签体,所以这里的body-content设置为empty-->
         <body-content>empty</body-content>
 </tag>

  在jsp页面中导入并使用自定义标签,如下:

<%@ page language="java" pageEncoding="UTF-8"%>
<%--在jsp页面中导入自定义标签库 --%>
<%@taglib uri="/gacl" prefix="gacl" %>
<!DOCTYPE HTML>
<html>
  <head>
    <title>控制jsp页面是否执行</title>
  </head>

  <body>
         <h1>jsp页面的内容1</h1>
         <%--在jsp页面中使用自定义标签 demo2标签是不带标签体的--%>
         <gacl:demo2/>
         <h1>jsp页面的内容2</h1>
  </body>
</html>

  运行效果如下:

 深入分析JavaWeb 23 -- jsp自定义标签开发入门_第8张图片

6.3、控制jsp页面内容重复执行

  编写一个类实现Iterationtag接口,控制doAfterBody()方法的返回值,如果这个方法返回EVAL_BODY_AGAIN, 则web服务器又执行一次标签体,依次类推,一直执行到doAfterBody方法返回SKIP_BODY,则标签体才不会重复执行。

示例代码如下:

TagDemo3.java

package me.gacl.web.tag;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.IterationTag;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;

public class TagDemo3 extends TagSupport {

    int x = 5;
    @Override
    public int doStartTag() throws JspException {
        return Tag.EVAL_BODY_INCLUDE;
    }

    /* 控制doAfterBody()方法的返回值, * 如果这个方法返回EVAL_BODY_AGAIN, 则web服务器又执行一次标签体, * 依次类推,一直执行到doAfterBody方法返回SKIP_BODY,则标签体才不会重复执行。 * @see javax.servlet.jsp.tagext.TagSupport#doAfterBody() */
    @Override
    public int doAfterBody() throws JspException {
        x--;
        if(x>0){
            return IterationTag.EVAL_BODY_AGAIN;
        }else{
            return IterationTag.SKIP_BODY;
        }
    }

}

  在WEB-INF目录下的tld文件中添加对该标签处理类的描述,如下:

 <tag>
         <name>demo3</name>
         <tag-class>me.gacl.web.tag.TagDemo3</tag-class>
         <!--demo3标签有标签体,所以这里的body-content设置为JSP-->
         <body-content>JSP</body-content>
 </tag>

  在jsp页面中导入并使用自定义标签,如下:

<%@ page language="java" pageEncoding="UTF-8"%>
<%--在jsp页面中导入自定义标签库 --%>
<%@taglib uri="/gacl" prefix="gacl" %>
<!DOCTYPE HTML>
<html>
  <head>
    <title>控制页面内容重复执行5次</title>
  </head>

  <body>
  <%--在jsp页面中使用自定义标签 demo3标签--%>
      <gacl:demo3>
          <h3>jsp页面的内容</h3>
      </gacl:demo3>
  </body>
</html>

  运行效果如下:

  深入分析JavaWeb 23 -- jsp自定义标签开发入门_第9张图片

6.4、修改jsp页面内容输出

  编写一个类实现BodyTag接口,控制doStartTag()方法返回EVAL_BODY_BUFFERED,则web服务器会创建BodyContent对象捕获标签体,然后在doEndTag()方法体内,得到代表标签体的bodyContent对象,从而就可以对标签体进行修改操作。

  SUN公司针对BodyTag接口提供了一个默认的实现类BodyTagSupport,BodyTagSupport类中实现了BodyTag接口的所有方法,因此我们可以编写一个类继承BodyTagSupport类,然后再根据需要重写doStartTag方法和doEndTag()方法。

示例代码如下:

TagDemo4.java

package me.gacl.web.tag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTag;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.Tag;

/** * @author gacl * BodyTagSupport类实现了BodyTag接口接口,TagDemo4继承 BodyTagSupport类 */
public class TagDemo4 extends BodyTagSupport {

    /* 控制doStartTag()方法返回EVAL_BODY_BUFFERED * @see javax.servlet.jsp.tagext.BodyTagSupport#doStartTag() */
    @Override
    public int doStartTag() throws JspException {
        return BodyTag.EVAL_BODY_BUFFERED;
    }

    @Override
    public int doEndTag() throws JspException {

        //this.getBodyContent()得到代表标签体的bodyContent对象
        BodyContent bodyContent = this.getBodyContent();
        //拿到标签体
        String content = bodyContent.getString();
        //修改标签体里面的内容,将标签体的内容转换成大写
        String result = content.toUpperCase();
        try {
            //输出修改后的内容
            this.pageContext.getOut().write(result);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return Tag.EVAL_PAGE;
    }
}

  在WEB-INF目录下的tld文件中添加对该标签处理类的描述,如下:

 <tag>
         <name>demo4</name>
         <tag-class>me.gacl.web.tag.TagDemo4</tag-class>
         <!--demo4标签有标签体,所以这里的body-content设置为JSP-->
         <body-content>JSP</body-content>
 </tag>

  在jsp页面中导入并使用自定义标签,如下:

<%@ page language="java" pageEncoding="UTF-8"%>
<%--在jsp页面中导入自定义标签库 --%>
<%@taglib uri="/gacl" prefix="gacl" %>
<!DOCTYPE HTML>
<html>
  <head>
    <title>修改jsp页面内容输出</title>
  </head>

  <body>
  <%--在jsp页面中使用自定义标签 demo4标签--%>
      <gacl:demo4>
          <h3>xdp_gacl</h3>
      </gacl:demo4>
  </body>
</html>

  运行效果如下:

  深入分析JavaWeb 23 -- jsp自定义标签开发入门_第10张图片

七、jsp传统标签开发总结

  在现在的jsp标签开发中,很少直接使用传统标签来开发了,目前用得较多的都是简单标签,所以Jsp的传统标签开发了解一下即可,下一篇重点介绍jsp简单标签的开发

你可能感兴趣的:(java,Web)