• java_第一年_JavaWeb(11)


    自定义标签:主要是用来移除JSP页面中的java代码。

    先从一个简单的案例了解其怎么移除代码:

    一个正常的jsp页面:

    <%@ page language="java" pageEncoding="UTF-8"%>
    <!DOCTYPE HTML>
    <html>
      <head>
        <title>输出客户端的IP</title>
      </head>
      
      <body>
        你的IP地址是(使用java代码获取输出):
        <%
            //在jsp页面中使用java代码获取客户端IP地址
            String ip = request.getRemoteAddr();
            out.write(ip);
        %>
    
      </body>
    </html>

    要想将其中的代码通过自定义标签引入需要通过@taglib指令进行声明,如:

    <%@ page language="java" pageEncoding="UTF-8"%>
    <%@taglib uri="/xxx"  prefix="ttt"%>
    <!DOCTYPE HTML>
    <html>
      <head>
        <title>输出客户端的IP</title>
      </head>
      
      <body>
         你的IP地址是(使用自定义标签获取输出):
         <%--使用自定义标签tagname --%>
         <ttt:tagname/>
      </body>
    </html>

    其中uri是标签库的uri,prefix是jsp进行引用时的前缀,tagname是标签库中的一个标签名,用来区分不同的标签;因此,我们需定义一个标签库,用来连接JSP页面和java类(标签处理器类),如自定义一个tag.tld文件,其位置位于WEB-INF目录下:

    <?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>小兆的自定义标签库测试</description>
        <!--标签库的版本号 -->
        <tlib-version>1.0</tlib-version>
        <short-name>LzjLibrary</short-name>
        <!-- 
            为自定义标签库设置一个uri,uri以/开头,/后面的内容可以随便写,如这里的/xxx ;
            在Jsp页面中引用标签库时,需要通过uri找到标签库
        -->
        <uri>/xxx</uri>
        <!-- 一个tag标记对应一个自定义标签 -->
         <tag>
            <description>这个标签的作用是用来输出客户端的IP地址</description>
            <!-- 
                为标签处理器类配一个标签名,在Jsp页面中使用标签时是通过标签名来找到要调用的标签处理器类的
                通过tagname就能找到对应的lzj.learn.tag.ViewIPTag类
             -->
            <name>tagname</name>
            <!-- 标签对应的处理器类-->
            <tag-class>lzj.learn.tag.ViewIPTag</tag-class>
            <body-content>empty</body-content>
        </tag>
        
    </taglib>

    最后的一步就是编写java类了,这在开发中其实是要第一步,只是这里为了了解其流程我放到了最后一步,前面的标签库中的<tag-class>其路径要与java类相对应;如下java类(标签处理器类):

    package lzj.learn.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) {
    
        }
    
    }
    1. 在JSP引擎实例化标签处理器后,其处理流程是先调用setPageContext方法将JSP 页面的pageContext对象传给标签处理器,标签处理器通过pageContext对象实现和JSP的通信;
    2. Web容器调用setParent方法标签的父标签传给当前的标签处理器,如无父标签,则传递的参数值为null;
    3. 之后开始执行doStartTag方法,输出ip
    4. 执行完后web容器会调用doEndTag方法,至此,自定义标签执行结束;不过其标签处理器会驻留在内存中,直至停止web应用,web容器才会调用release方法;

    看到这,相信你已经对自定义标签的作用和处理流程有了一定的了解,接下来是更加详细的介绍;

    JspTag是所有自定义标签的父接口;没有任何属性和方法,JSP2.0后有两个子接口:Tag和SimpleTag;

    Tag接口

    Tag接口定义了2个重要方法(doStartTag和doEndTag)以及四个常量(EVAL_BODY_INCLUDE、SKIP_BODY(位于doStartTag方法中,决定是否要忽略自定义标签的标签体)以及EVAL_PAGE、SKIP_PAGE(位于doEndTag方法中,决定位于结束标记后面的内容是否执行));

    进一步地,有IterationTag接口继承Tag接口,增加了doAfterBody方法和EVAL_BODY_AGAIN常量,执行完自定义标签的标签体后会执行doAfterBody方法,返回常量EVAL_BODY_AGAIN或SKIP_BODY,如果返回EVAL_BODY_AGAIN,标签体内容会重复执行一次,直到返回SKIP_BODY;

    再进一步,有BodyTag接口继承了IterationTag接口,又多了两个方法(setBodyContent和doInitBody)和一个常量EVAL_BODY_BUFFERED;其作用是可以对标签体的运行结果进行修改,具体的流程是在执行完doStartTag方法后还可以返回这个EVAL_BODY_BUFFERED常量,这样web容器就会创建一个捕获标签体运行结果的BodyContent对象,并调用这个setBodyContent方法将其传递给标签处理器,标签处理器就可以调用特有的方法对这个BodyContent对象进行修改并控制其输出;

    对应地,在JSP API中也提供了BodyTag接口的实现类BodyTagSupport,因此在编写标签处理类时可以继承和扩展BodyTagSupport类,简化开发工作;

    这里给一个修改标签体运行结果的范例,其余的返回方法及返回常量大家有时间也可以实践实践:

    package lzj.learn.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;
    
    public class TagDemo 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;
        }
    }

    以上介绍的Tag接口这一分支被称为传统标签,很少用来开发了,(ノ`Д)ノ!不过过程流程还是要熟悉的,有助对自定义标签的理解,用的比较多的是下面的简单标签SimpleTag!

    突然发现这节写得有点多了,所以简单标签的开发还是放到下节讲解啦!!

  • 相关阅读:
    HDFS datanode源码分析
    hive udaf开发入门和运行过程详解
    hive原生和复合类型的数据加载和使用
    tomcat部署web应用(转)
    HDFS namenode源码分析
    HDFS dfsclient写文件过程 源码分析
    hive中UDTF编写和使用(转)
    HDFS dfsclient读文件过程 源码分析
    MapReduce源码分析总结(转)
    DataRabbit 轻量的数据访问框架(09) -- IDataSchemaAccesser
  • 原文地址:https://www.cnblogs.com/lzj-learn/p/11642815.html
Copyright © 2020-2023  润新知