随笔都是学习笔记
随笔仅供参考,为避免笔记中可能出现的错误误导他人,请勿转载。

自定义标签:

步骤:

  标签处理类(标签也是一个对象,那么就需要先有类!)
  tld文件,它是一个xml
  页面中使用<%@taglib%>来指定t1d文件的位置

标签类:

标签接口:
public
interface SimpleTag extends JspTag
每次执行标签都会调用这个方法(Tomcat调用):
public
void doTag() throws JspException,java.io.IOException 设置父标签:
public
void setParent(JspTag parent) 返回父标签(非生命周期方法):
public
JspTag getParent() 设置JSP上下文对象(子类是PageContext):
public
void setJspContext(JspContext pc) 设置标签体:
public
void setJspBody(JspFragment jspBody)

 

自定义的标签类

package tag;
import java.io.IOException;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTag;

/**
 * 自定义标签 1
 * @author CDU_LM
 *
 */
public class MyTag1 implements SimpleTag {
    private PageContext  pageContext;
    private JspFragment body;
    
    /**
     * 所有setXxx()方法都会在doTag()方法之前被Tomcat调用!
     * 所以在doTag()方法中就可以使用Tomcat传递过来的对象。
     */
    @Override
    public void doTag() throws JspException, IOException {
        // 使用一个顶九个的PageContext对象获取out来输出内容
        pageContext.getOut().print("Hello!MyTag1!!!");
    }

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

    @Override
    public void setJspBody(JspFragment jspBody) {
        // 接收标签体
        this.body = jspBody;
    }

    @Override
    public void setJspContext(JspContext context) {
        // 接收PageContext对象
        this.pageContext = (PageContext) context;  
    }

    @Override
    public void setParent(JspTag parent) {
        
    }
}

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">
    
  <tlib-version>1.0</tlib-version>    <!-- 版本 -->
  <short-name>tag1</short-name>    <!-- 前缀 -->
  <uri>http://www.cdml.cn/tag/tag-1.0</uri> <!-- 地址 -->
  
  <tag>
       <name>MyTag1</name><!-- 自定义当前标签名称 -->
       <tag-class>tag.MyTag1</tag-class>    <!-- 自定义的标签位置 -->
       <body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
  </tag>
 </taglib>

jsp测试:

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@taglib uri="/WEB-INF/tld/tag1.tld" prefix="t1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>title</title>
</head>
<body>
<h1><t1:MyTag1/></h1>
</body>
</html>

访问结果:

下面还有一个实现了SimpleTag接口的标签支持类SimpleTagSupport:

SimpleTagSupport:

这个类实现了SimpleTag接口,将所有Tomcat传递的参数都保存起来了,并提供了get方法供子类获取参数。

package tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class MyTag2 extends SimpleTagSupport {
    @Override
    public void doTag() throws JspException, IOException {
        // 获取标签体
        this.getJspBody();
        // 获取PageContext对象
        this.getJspContext().getOut().pring("Hello!2222222");
        // 获取父标签
        this.getParent();
    }
}

向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">
    
  <tlib-version>1.0</tlib-version>    <!-- 版本 -->
  <short-name>tag1</short-name>    <!-- 前缀 -->
  <uri>http://www.cdml.cn/tag/tag-1.0</uri> <!-- 地址 -->
  
  <tag>
       <name>MyTag1</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
       <tag-class>tag.MyTag1</tag-class>    <!-- 自定义的标签位置 -->
       <body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
  </tag>
  <tag>
       <name>MyTag2</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
       <tag-class>tag.MyTag2</tag-class>    <!-- 自定义的标签位置 -->
       <body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
  </tag>
 </taglib>

访问结果:

所以一个tld文件可以配置多个标签类。

 

标签体配置:

empty:无标签体

JSP:传统标签支持它,从JSP2.0后不再支持,已经不再支持使用<body-content>Jsp</body-content>。标签体内可以是任何东西:EL、JSTL、<%=%>、<%%>,以及html;

scriptless.:标签体内不能是Java脚本,但可以是EL、JSTL等。在simpleTag.中,如果需要有标签体,那么就使用该选项;

tagdependent:标签练内容不做运算﹐由标签处理类自行处理,无论标签体内容是EL、JSP、JSTL,都不会做运算。这个选项几乎没有人会使用!

简单的说就是无标签体用 empty,有标签体用 scriptless 。

创建类:

package tag;
import java.io.IOException; import java.io.Writer; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.SimpleTagSupport; public class MyTag3 extends SimpleTagSupport { @Override public void doTag() throws JspException, IOException { Writer write = this.getJspContext().getOut(); // 获取当前jsp页面的输出流 write.write("********************<br/>"); this.getJspBody().invoke(write); // 执行标签体内容,把结果写到指定的流中,即页面中。 write.write("<br/>********************"); } }

配置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">
  <tlib-version>1.0</tlib-version>    <!-- 版本 -->
  <short-name>tag</short-name>    <!-- 前缀 -->
  <uri>http://www.cdml.cn/tag/tag-1.0</uri> <!-- 地址 -->
  
  <tag>
       <name>MyTag1</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
       <tag-class>tag.MyTag1</tag-class>    <!-- 自定义的标签位置 -->
       <body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
  </tag>
  <tag>
       <name>MyTag2</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
       <tag-class>tag.MyTag2</tag-class>    <!-- 自定义的标签位置 -->
       <body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
  </tag>
  <tag>
       <name>MyTag3</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
       <tag-class>tag.MyTag3</tag-class>    <!-- 自定义的标签位置 -->
       <body-content>scriptless</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
  </tag>
 </taglib>

jsp测试:

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@taglib uri="/WEB-INF/tld/tag.tld" prefix="t1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>title</title>
</head>
<body>
<%
    request.setAttribute("req", "这是张三娃娃");
%>
<t1:MyTag3>
${req}
</t1:MyTag3>
</body>
</html>

访问结果:

 

不在执行标签下面内容的标签:

在标签处理类中的doTag()中使用skipPageException来结束!
Tomcat会调用标签处理类的doTag()方法,然后Tomcat会得到skipPageException,它会跳过本页面其他内容!

创建自定义标签类:

package tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class MyTag4 extends SimpleTagSupport{
    @Override
    public void doTag() throws JspException, IOException {
        this.getJspContext().getOut().print("只能看到我这里了,下面的内容看不见了!!");
        throw new SkipPageException();    // 抛出这个异常后,标签后面的内容将不可见!
    }
}

配置tld文件:

加入MyTag4标签之前的访问页面:

加入MyTag4标签后的访问页面:

 

 

 

 

查看内容不显示的原因:

 打开编译后的jsp文件tag1_jsp.class:

这里会定义一些变量,就是在jsp或类中需要用到的变量;

向下滑到使用MyTag4标签的位置:

发现这里是一个判断句,if中有一个函数_jspx_meth_t1_005fMyTag4_005f0,下面查看这个函数:

 

方法最后返回的是false,所以不会执行if中的return; 也就是说正常情况下if判断失败会继续向下执行,从而显示下面的jsp页面内容,但是这里执行doTag()方法时,执行的是类MyTag4中的doTag()方法:

这个方法抛出了一个异常,那么在函数_jspx_meth_t1_005fMyTag4_005f0执行doTag()方法的时候就会跟着向上级抛出MyTag4中的异常,也就是SkipPageException

当他向外抛出这个异常的时候,再看if所处的范围是在try语句中:

那么它抛出的SkipPageException就会被捕获,然后执行对应的catch语句:

 

在这之后,它执行的内容或者步骤是什么都不重要了,此时需要关注的就是:

    if语句中的函数抛出了异常,异常抛到了此时的try语句中

    异常被捕获,代码执行跳转到catch语句中

    结果就是if后面的语句都被跳过了

    而finally语句块中只是执行释放PageContext对象,而没有其它内容

 

所以这就是访问jsp页面后在标签MyTag4后面的内容全部都不会显示的原因。

 

 

带有属性的自定义标签

创建一个自定义标签类,类中创建属性,该属性必须由set()方法,该set()方法是由Tomcat在doTag()方法之前进行调用,所以set()方法中将属性任意设置都可以在doTag()方法中使用:

自定义标签类:

package tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class MyTag5 extends SimpleTagSupport {
    private boolean test;

    @Override
    public void doTag() throws JspException, IOException {
        if (test) { // test为true才执行标签体
            // 执行标签体
            this.getJspBody().invoke(null); // 输出传递null,默认使用的是当前页面的out
        }
    }

    /**
     * 这个方法是Tomcat调用,在doTag()方法之前调用
     * 
     * @param test
     * @throws IOException
     * @throws JspException
     */
    public void setTest(boolean test) throws JspException, IOException {
        this.test = test;
    }
}

在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">

    <tlib-version>1.0</tlib-version>    <!-- 版本 -->
    <short-name>tag</short-name>    <!-- 前缀 -->
    <uri>http://www.cdml.cn/tag/tag-1.0</uri> <!-- 地址 -->

    <tag>
        <name>MyTag1</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
        <tag-class>tag.MyTag1</tag-class>    <!-- 自定义的标签位置 -->
        <body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
    </tag>
    <tag>
        <name>MyTag2</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
        <tag-class>tag.MyTag2</tag-class>    <!-- 自定义的标签位置 -->
        <body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
    </tag>
    <tag>
        <name>MyTag3</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
        <tag-class>tag.MyTag3</tag-class>    <!-- 自定义的标签位置 -->
        <body-content>scriptless</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
    </tag>
    <tag>
        <name>MyTag4</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
        <tag-class>tag.MyTag4</tag-class>    <!-- 自定义的标签位置 -->
        <body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
    </tag>
    <tag>
        <name>MyTag5</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
        <tag-class>tag.MyTag5</tag-class>    <!-- 自定义的标签位置 -->
        <body-content>script</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
        <attribute><!-- 配置属性标签 -->
            <name>test</name><!-- 属性名称 -->
            <required>true</required><!-- 该属性是否为必需,是则为true,否为false -->
            <rtexprvalue>true</rtexprvalue><!-- 属性值是否为EL表达式,是为true,否为false -->
        </attribute>
    </tag>
</taglib>

jsp页面代码:

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@taglib uri="/WEB-INF/tld/tag.tld" prefix="t1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>title</title>
</head>
<body>
    <t1:MyTag5 test="${empty param.xxx }">
        <h1>
            <t1:MyTag4 />
        </h1>
    </t1:MyTag5>
    <%
    request.setAttribute("req", "这是张三娃娃");
    %>
    <h1>
        <t1:MyTag1 />
    </h1>
    <h1>
        <t1:MyTag2 />
    </h1>
    <t1:MyTag3>
${req}
    </t1:MyTag3>

</body>
</html>

当进行无参访问时:

当进行有参访问时:

 

 

那么带有属性的标签就自定义成功了。

 

posted on 2022-04-30 11:27  时间完全不够用啊  阅读(231)  评论(0编辑  收藏  举报