1.4(学习笔记)JSP自定义标签

一、JSP自定义标签

   JSP自定义标签,可以通过实现Tag接口、继承TagSupport类来设置标签功能。

  后续通过配置文件将标签和具体的实现类关联。

 

二、自定义第一个标签(实现Tag接口)

  自定义标签需要先创建一个Java类,然后实现Tge接口或者继承S.....类

  我们先来看实现接口这种方法自定义标签:

  2.1创建Java类

HelloTag.java

import java.io.IOException;

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

public class HelloTag implements Tag {
    
    private PageContext pageContext;
    
    @Override
    public int doEndTag() throws JspException {
        // TODO Auto-generated method stub
        System.out.println("endTag");
        return EVAL_PAGE;//继续显示该标签后续内容
    }

    @Override
    public int doStartTag() throws JspException {
        // TODO Auto-generated method stub
        String msg = "MyTag";
        JspWriter out = pageContext.getOut();
        try {
            out.println(msg);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("startTag");
        return EVAL_BODY_INCLUDE;//显示标签体中的内容
    }

    @Override
    public Tag getParent() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void release() {
        // TODO Auto-generated method stub
    }

    @Override
    public void setPageContext(PageContext pageContext) {
        // TODO Auto-generated method stub
        //获取JSP页面的pageContext
        this.pageContext = pageContext;
        System.out.println("pageContext");
    }

    @Override
    public void setParent(Tag arg0) {
        // TODO Auto-generated method stub
    }
    
}

 

  2.2创建好java类后,需要创建配置文件

    2.2.1创建my_tag_config.tld文件

    在WEB-INF文件夹下新建XML文件。

    

    

     将.xml改为.tld(结果如下图所示)

     

    点击next,进入如下页面。(结果如下图所示)

    

    点击next(结果如下图所示)

    

    点击next,(效果如下图所示)

    

    点击finish,创建结束。

    打开创建好的文件,效果如下图所示。

    

 

    接着我们就要对其进行配置,将标签和我们创建的类关联。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd" >
<taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>1.2</jsp-version>
  <short-name>short-name</short-name>
  
  <!-- 此处的uri只是一个标识,可任意指定,后续JSP页面中引用时保持一致即可 -->
  <uri>http://www.myTag.com</uri>
  
  <tag>
    <name>hello</name>   <!-- 设置标签名 -->
    <tag-class>com.myTag.HelloTag</tag-class>  <!-- 设置标签名关联类 -->
    <body-content>JSP</body-content> <!-- 指定标签体显示格式 -->
  </tag>
</taglib>

其中<body-content>中的属性有四种:

tagdependent,empty,JSP,

各个属性的含义可参阅:https://www.cnblogs.com/keyi/p/7127685.html

 

以上都配置好了后,我们就来使用标签。

tag.jsp  

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<!-- 指定需要使用标签的URi和前缀 -->
<%@ taglib uri="http://www.myTag.com" prefix = "m" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <m:hello>include body</m:hello>
</body>
</html>

 

自定义标签的功能是输出“MyTag”,结果正常输出。

我们来看下控制台的输出:

 

最后我们分析下标签的执行流程

我们看下tag.jsp生存的servlet中的代码:

Servlet中调用了一个方法,我们来看下这个方法

查看代码可以很清楚的看到自定义标签的执行流程。

 

 三、自定义out标签(继承TagSupport类实现)

java类

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;

public class HelloTagEx extends TagSupport {
    private String value;
    private JspWriter out;
    
    public void setValue(String value) {//设置值
        this.value = value;
    }

    @Override
    public int doStartTag() throws JspException {
        // TODO Auto-generated method stub
     //不重写setPageContext方法,也可直接使用pageContext
     // 例如: this.out = pageContext.getOut();
try { out.println(value); //将设置的value输出 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return SKIP_BODY;//不输出标签体中内容 } @Override public int doEndTag() throws JspException { // TODO Auto-generated method stub return SKIP_PAGE;//不输出界面后续内容 } @Override public int doAfterBody() throws JspException { // TODO Auto-generated method stub return super.doAfterBody(); } @Override //此方法也可以不重写,在doStartTag、doEndTag中可以直接使用pageContext
         
public void setPageContext(PageContext pageContext) { this.pageContext = pageContext; this.out = pageContext.getOut(); } }

 

标签配置:

<tag>
          <name>helloEx</name>
          <tag-class>com.myTag.HelloTagEx</tag-class>
         <body-content>JSP</body-content>  
         
          <attribute>
              <name>value</name>  <!-- 属性名要和类中属性名对应 -->
              <required>true</required>      <!-- 该属性是否为必填项 true 代表为必填,不填会报错 -->
              <rtexprvalue>true</rtexprvalue> <!-- 能否使用表达式赋值  true表示可以用表达式-->
          </attribute>
    </tag>

 

tag.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<!-- 指定需要使用标签的URi和前缀 -->
<%@ taglib uri="http://www.myTag.com" prefix = "m" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <m:helloEx value="123">ss</m:helloEx>
    endTag方法返回值是SKIP_PAGE,不输出后续界面,所以这句话不会输出。
</body>
</html>

 

四、自定义if标签

 有了前面两个作为基础,后面的就很简单了。

标签类

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

public class IF extends TagSupport{
    private boolean flag;
    
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
    
    @Override
    public int doStartTag() throws JspException {
        // TODO Auto-generated method stub
        if(flag == true) {//如果为true,标签体中内容执行,反正不执行。
            return EVAL_BODY_INCLUDE;
        }else {
            return SKIP_BODY;
        }
    }
    
    @Override
    public int doEndTag() throws JspException {
        // TODO Auto-generated method stub
        return EVAL_PAGE;//IF标签结束后,继续执行页面内容
    }
    
    
}

 

配置:

<tag>
          <name>IF</name>
          <tag-class>com.myTag.IF</tag-class>
         <body-content>JSP</body-content>  
         
          <attribute>
              <name>flag</name>  <!-- 属性名要和类中属性名对应 -->
              <required>true</required>      <!-- 该属性是否为必填项 true 代表为必填,不填会报错 -->
              <rtexprvalue>true</rtexprvalue> <!-- 能否使用表达式赋值  true表示可以用表达式-->
          </attribute>
    </tag>

 

tag.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<!-- 指定需要使用标签的URi和前缀 -->
<%@ taglib uri="http://www.myTag.com" prefix = "m" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <m:IF flag="${3>2}">
        true
    </m:IF>
</body>
</html>

 

 

 

五、自定义foreach标签

标签类:ForEach.java

import java.util.Iterator;
import java.util.List;

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

public class ForEach extends TagSupport {
    
    private List<String> list;
    private String var;

    public void setList(List<String> list) {
        this.list = list;
    }
    
    public void setVar(String var) {
        this.var = var;
    }
    
    @Override
    public int doStartTag() throws JspException {
        // TODO Auto-generated method stub
        if(list == null) {
            return SKIP_BODY;
        }else {
            Iterator<String> items = list.iterator(); 
            pageContext.setAttribute("ite", items);
            pageContext.setAttribute("list", list);
            //由于doStartTage方法结束后是输出标签体,
            //而标签体中有${var}表达式用于输出迭代对象
            //所以此处最好先拿出一个对象。
            if(items.hasNext()) {//如果迭代器中有元素,设置值,并输出标签体
                pageContext.setAttribute(var, items.next());
                return EVAL_BODY_INCLUDE;
            }else {//反之则不输出标签体
                return SKIP_BODY;
            }
            
        }
    }
    
    @Override
    public int doAfterBody() throws JspException {
        // TODO Auto-generated method stub
        //获取迭代器
        Iterator<String> items = (Iterator<String>)pageContext.getAttribute("ite");
        if(items.hasNext()) {//将其中元素取出,并设置。
            String value = (String) items.next();
            pageContext.setAttribute(var, value);
            return EVAL_BODY_AGAIN; //再一次执行标签体
        }else {
            return SKIP_BODY; //迭代器为空,则停止输出标签体
        }
    }
    
    @Override
    public int doEndTag() throws JspException {//结束标签后的内容继续输出
        // TODO Auto-generated method stub
        return EVAL_PAGE;
    }
}

 

配置:

<tag>
          <name>FOREACH</name>
          <tag-class>com.myTag.ForEach</tag-class>
         <body-content>JSP</body-content>  
         
         <attribute>
              <name>var</name>  <!-- 属性名要和类中属性名对应 -->
              <required>true</required>      <!-- 该属性是否为必填项 true 代表为必填,不填会报错 -->
              <rtexprvalue>false</rtexprvalue> <!-- 能否使用表达式赋值  false表示不可以用表达式-->
          </attribute>
         
          <attribute>
              <name>list</name>  <!-- 属性名要和类中属性名对应 -->
              <required>true</required>      <!-- 该属性是否为必填项 true 代表为必填,不填会报错 -->
              <rtexprvalue>true</rtexprvalue> <!-- 能否使用表达式赋值  true表示可以用表达式-->
          </attribute>
          
    </tag>

 

tag.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import = "java.util.*" %>
<!-- 指定需要使用标签的URi和前缀 -->
<%@ taglib uri="http://www.myTag.com" prefix = "m" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

    <%
        List<String> list = new ArrayList<String>();
        for(int i = 0; i < 5 ; i++){
            list.add("str" + i);
        }
        pageContext.setAttribute("list", list);
    %>    
    <m:FOREACH list="${list}" var="s">
        ${s}
    </m:FOREACH>
</body>
</html>

 

foreach主要通过表达式将list对象传递到ForEach.java中,

在ForEach.java中主要通过doAfterBody()方法,将迭代器中元素

通过pageSetAttribute()设置到page中,然后输出${var},输出的表达式又会自动获取设置的值,

然后往复输出执行doAfterBody()方法,并且输出标签体(表达式${var}),来实现foreach。

直到迭代器元素全部输出,方法才终止。

 

那个doAfterBody()和return EVAL_BODY_AGAIN配合的流程可能不太好理解,

我们来看下tag.jsp生成的Servlet中的代码就很好理解了。

 

 

 

 

 

 执行顺序为(不考虑后续输出终止情况):

doStartTag->标签体内容->doAfterBody->doEndTag

 

 <xx>  标签开始(doStartTag)

   xxxxxx   标签体

  doAfterBody判断是否继续输出标签体(doAfterBody方法也可看作标签体的一部分)

 </xx>  标签结束(doEndTag)

 

 

参考资料: 

https://blog.csdn.net/qq_42246139/article/details/80623607

https://blog.csdn.net/qq_41815326/article/details/81356733  

 

posted @ 2019-02-01 13:37  gcmh  阅读(263)  评论(0编辑  收藏  举报