JavaEE

JavaWeb了解之入门篇2-1(自定义标签、开发标签库)

2022-10-03  本文已影响0人  平安喜乐698
目录
  1. 自定义标签
  2. 开发标签库

本篇笔记是从个人笔记中摘录,不属于教程

1. 自定义标签

旨在移除JSP页面中的Java代码。

  1. 相关接口
JspTag接口
  所有自定义标签的父接口(没有任何属性和方法),有2个直接子接口:
    1. Tag接口(传统标签)。
    2. SimpleTag接口(简单标签)。
Tag接口
  继承自JspTag接口。实现Tag接口的自定义标签称做传统标签。
  doStartTag()  
    返回常量EVAL_BODY_INCLUDE则执行标签体。
    返回常量SKIP_BODY则跳过(忽略)标签体,直接执行结束标签。
  doEndTag()  
    返回常量EVAL_PAGE则会执行结束标签后的jsp代码。
    返回常量SKIP_PAGE则忽略结束标签后的所有内容。
  setParent()、getParent()、setPageContext()、release()

IterationTag接口(添加功能:重复执行标签体)
  继承自Tag接口,TagSupport为IterationTag接口的默认实现类(简化开发)。
  在执行完自定义标签的标签体后,会调用标签类的doAfterBody方法。
  doAfterBody()  
    返回常量EVAL_BODY_AGAIN则重复执行标签体内容。
    返回常量SKIP_BODY则去执行doEndTag()。

BodyTag接口(添加功能:修改标签体内容)
  继承自IterationTag接口,BodyTagSupport为BodyTag接口的默认实现类(简化开发)。
  setBodyContent()、doInitBody()
  doStartTag方法还可以返回常量EVAL_BODY_BUFFERED ,WEB容器就会创建一个BodyContent对象(用于捕获标签体运行结果),然后调用setBodyContent方法将BodyContent对象的引用传递给标签处理器,WEB容器接着将标签体的执行结果写入到BodyContent对象中。
  在doEndTag方法中可以通过先前保存的BodyContent对象的引用来获取标签体的执行结果,然后调用BodyContent对象特有的方法对BodyContent对象中的内容(即标签体的执行结果)进行修改和控制其输出。

传统标签使用三个标签接口来完成不同的功能,繁琐且不利于推广,所以sun公司推出了SimpleTag接口。
SimpleTag接口
  继承自JspTag接口。实现SimpleTag接口的自定义标签称做简单标签。
  SimpleTagSupport为SimpleTag接口的默认实现类(用于简化开发)。
  doTag()、getParent()、setParent()、setJspContext()、setJspBody()。
  是否执行标签体、迭代标签体、对标签体内容进行修改等功能都可以在doTag方法中完成。
  1. 自定义传统标签
JSP引擎遇到自定义标签时的【执行流程】:
  首先创建标签类的实例对象,然后依次调用该对象的如下方法:
   1. public void setPageContext(PageContext pc) 
      将JSP页面的pageContext对象传递给标签类,标签类通过pageContext对象和JSP页面通信。
   2. public void setParent(Tag t) 
      将当前标签的父标签传递给标签类,如果没有则为null。
   3. public int doStartTag() 
      处理标签的开始标记。
   4. public int doEndTag() 
      执行完标签体后,会处理标签的结束标记。
   5. public void release() 
      执行完自定义标签后,标签类的实例对象会驻留在内存中直至web应用关闭时会调用release方法进行释放。
自定义标签除了能移除JSP页面中的Java代码外,也可以在JSP页面中实现以下功能:
  1. 控制jsp页面的某一部分内容是否执行。
    实现Tag接口 或 继承TagSupport类,然后覆写doStartTag() 返回不同常量。
  2. 控制整个jsp页面是否执行。
    实现Tag接口 或 继承TagSupport类,然后覆写doEndTag() 返回不同常量。
  3. 控制jsp页面内容重复执行。
    实现IterationTag接口 或 继承TagSupport类,然后覆写doStartTag()返回Tag.EVAL_BODY_INCLUDE、doEndTag()返回不同常量
  4. 修改jsp页面内容输出
    实现BodyTag接口 或 继承BodyTagSupport类,然后覆写doStartTag()返回BodyTag.EVAL_BODY_BUFFERED、doEndTag()如下:
    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;
    }

第1步. 创建自定义标签类(用于获取客户端IP)

package com.sst.cx;
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 CusTag  implements Tag{    
    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()方法");
        // 可以看到pageContext对象在自定义标签中的重要性。
        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步. 创建MyCusTag.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">
    <!-- 
      taglib标签库的描述(有哪些功能)
    -->
    <description>自定义标签库</description>
    <!--
      taglib标签库的版本号 
    -->
    <tlib-version>1.0</tlib-version>
    <short-name>MyCusTag</short-name>
    <!-- 
        为标签库设置一个uri(以/开头),/标签库名 
        在Jsp页面中引用标签库时,需要通过uri找到对应的标签库:
            <%@taglib uri="/标签库名" prefix="sx"%>
    -->
    <uri>/MyCusTag</uri>
    <!--
      一个taglib标签库可包含多个自定义标签。
      一个tag标记对应一个自定义标签。 
    -->
     <tag>
        <description>这个标签的作用是用来输出客户端的IP地址</description>
        <!-- 
            为标签类配一个标签名,在Jsp页面中使用标签时是通过标签名来找到要调用的标签类。
         -->
        <name>viewIP</name>
        <!-- 
            标签对应的标签类(包含包路径)
        -->
        <tag-class>com.sst.cx.CusTag</tag-class>
        <body-content>empty</body-content>
    </tag>
</taglib>

第3步. 在jsp中使用

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@taglib uri="/MyCusTag" prefix="sx" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    <title>My JSP 'index.jsp' starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->
  </head>
  <body>
    <sx:viewIP/>
  </body>
</html>

不使用<sx:viewIP/>时,需要使用JSP脚本片段:
    <%
        // 
        String ip = request.getRemoteAddr();
        out.write(ip);
    %>
可以看到,自定义标签可以将JSP中的Java代码移除。
  1. 自定义简单标签
自定义简单标签的执行流程
  1. setJspContext() 
    将JSP页面的pageContext对象传递给标签类对象。
  2. setParent() 
    将当前标签的父标签类对象传递给标签类,只有当父标签存在时才会调用。
    // getParent() 可获取父标签类对象。
  3. 如果标签设置了属性则分别调用setter方法设值。
  4. 如果有标签体则调用setJspBody() 方法,并传入代表标签体的JspFragment对象。
  5. 执行标签时会调用doTag() ,通过操作JspFragment对象,就可以实现 是否执行、迭代、修改标签体内容。
      抛出javax.servlet.jsp.SkipPageException异常,则不再执行标签后的所有页面内容。
 
JspFragment对象
  代表标签体,JSP页面中的一段符合JSP语法规范的JSP片段(不能包含JSP脚本元素)
  只有2个方法:
    1. getJspContext方法
      获取JSP页面的pageContext对象。
    2. public abstract void invoke(java.io.Writer out)
      执行标签体,并将标签体的结果内容写入参数指定的流中(可以将流中的标签体内容进行修改后再输出)。可以传StringWriter输出流对象,也可以传null(会使用JspContext.getOut()方法返回的输出流对象)。
      不调用invoke方法则不会执行标签体(即不会输出标签体内容,即忽略标签体内容)。
      多次调用invoke方法则会多次执行标签体(即多次输出标签体内容)。

第1步. 创建自定义标签类

package com.sst.cx;
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
// 不要使用实现SimpleTag接口这种方式,而应该使用继承SimpleTagSupport类的方式来自定义简单标签。
public class SimpleTag extends SimpleTagSupport {
    /* 
    * 一般只需重写doTag方法
    */
    @Override
    public void doTag() throws JspException, IOException {
        // 得到代表jsp标签体的JspFragment对象
        JspFragment jspFragment = this.getJspBody();
        
        // 得到jsp页面的的PageContext对象
        // PageContext pageContext = (PageContext) jspFragment.getJspContext();
        // 调用JspWriter将标签体的内容输出到浏览器
        // jspFragment.invoke(pageContext.getOut());

       /* 
        1. 控制jsp页面某一部分内容是否执行(控制标签体是否执行)。
          调用则会执行标签体,注释掉则不再执行标签体。
          jspFragment.invoke(null);
       */ 
       /*
        2. 控制jsp页面内容重复执行。
          重复调用jspFragment.invoke(null);方法
          for (int i = 0; i < 5; i++) {
            // 将标签体的内容输出到浏览器
            jspFragment.invoke(null);
          }
       */
        /*
         3. 修改jsp页面内容输出
        StringWriter sw = new StringWriter();
        // 将标签体的内容写入到sw流中
        jspFragment.invoke(sw);
        // 获取sw流缓冲区的内容
        String content = sw.getBuffer().toString();
        content = content.toUpperCase();
        PageContext pageContext = (PageContext) this.getJspContext();
        // 将修改后的content输出到浏览器中
        pageContext.getOut().write(content);
        */
        /*
         4. 控制整个jsp页面是否执行
          抛出异常则不再执行标签后的所有内容。
          throw new SkipPageException();
        */
    }
}

第2步. tld中+(tld文件通常放在WENB-INF下)

      <tag>
        <description>SimpleTag(简单标签)</description> 
        <name>simple</name>
        <!-- 
          标签对应的标签处理器类
        -->
        <tag-class>com.sst.cx.SimpleTag</tag-class>
        <!--
        标签体类型(4种) 
            1. empty         没有标签体
            2. JSP           有标签体(可以是任意内容)不符合避免出现Java代码的初衷。
            3. scriptless    标签体的内容不允许是jsp脚本片段<%java代码%>
            4. tagdepentend  标签体的内容是给标签类使用的(很少使用)
              <hello:sql>SELECT * FROM USER</hello:sql> 中的SQL语句则是给标签类使用的。
        【存疑】在简单标签中标签体body-content的值只允许是empty和scriptless、tagdependent,不允许设置成JSP 否则异常。
        【存疑】在传统标签中标签体body-content的值4个类型都可以。
        -->
        <body-content>scriptless</body-content>        
      </tag>

第3步. 在jsp中使用

引入
<%@taglib uri="/MyCusTag" prefix="hello" %> 
使用
<hello:simple>nihao</hello:simple>

<!--
引用标签库

方式1
        <%@taglib uri="/MyCusTag" prefix="hello" %> 
方式2 (多个uri相同时,使用td文件路径来区分)
        <%@taglib uri="/WEB-INF/MyCusTag.tld" prefix="hello"%>
        <%@taglib uri="/WEB-INF/OtherCusTag.tld" prefix="hi"%>
-->

开发带有属性标签

自定义标签中可以定义多个属性,在JSP页面中使用标签时设置属性值,通过这些属性可以给标签处理类传递参数信息,从而提高标签的灵活性和复用性。

步骤:
  1. 在标签处理类中编写每个属性及对应的setter方法(必须符合JavaBean格式)。
  2. 在TLD文件中描述标签的属性。

说明:
  1. 传统标签会在执行doStartTag方法前调用setter方法设值,简单标签会在setParent()之后setJspBody()方法之前调用setter方法设值。
  2. 如果标签的属性值是8种基本数据类型,JSP引擎会自动将字符串转换成相应的类型。但如果标签的属性是复合数据类型则无法自动转换,可使用JSP表达式或EL表达式来解决(如:Date类型 <hello:tag date="<%=new Date()%>")。
第1步. 标签类中+
  private int count;  // 重复执行的次数
  public void setCount(int count) {
    this.count = count;
  }
  doTag()方法中使用+
  for (int i = 0; i < this.count; i++) {
    // 将标签体的内容输出到浏览器
    jspFragment.invoke(null);
  }

第2步. tld文件的tag中+(一个属性对应一个<attribute>)
  <attribute>
    <description>描述(可选)</description>
    <!-- 属性名(必填)大小写敏感,不能以jsp、_jsp、java、sun开头 -->
    <name>count</name>
    <!-- 是否必填(可选)默认:false-->
    <required>true</required>
    <!-- 是否可以是一个表达式,一般都为true(可选)默认:false只能为静态文本-->
    <rtexprvalue>true</rtexprvalue>
    <!-- 指定属性的Java类型(可选)-->
    <type>int</type>
  </attribute>

第3步. jsp中使用(会输出3遍nihao)
  <hello:simple count="3">nihao</hello:simple>

2. 开发标签库

  1. 防盗链标签(防止用户直接输入网址的请求)

第1步. 创建标签类(在com.sst.cx.simpletag包下新建)

package com.sst.cx.simpletag;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class RefererTag extends SimpleTagSupport {
    /**
     * 网站域名
     */
    private String site;
    /**
     * 请求来路不明时 要跳转的页面
     */
    private String page;
    @Override
    public void doTag() throws JspException, IOException {
        // 获取jsp页面的PageContext对象
        PageContext pageContext = (PageContext) this.getJspContext();
        // 通过PageContext对象来获取HttpServletRequest对象
        HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
        // 获取请求的来路(Referer)
        String referer = request.getHeader("referer");
        // 如果来路是null或者来路不是来自我们自己的site,那么就将请求重定向到page页面
        if (referer == null || !referer.startsWith(site)) {
            // 获取HttpServletResponse对象
            HttpServletResponse response = (HttpServletResponse)pageContext.getResponse();
            String webRoot = request.getContextPath();
            if (page.startsWith(webRoot)) {
                // 重定向到page页面
                response.sendRedirect(page);
            } else {
                // 重定向到page页面
                response.sendRedirect(webRoot+page);
            }
            // 重定向后,控制保护的页面不要执行
            throw new SkipPageException();
        }
    }
    public void setSite(String site) {
        this.site = site;
    }
    public void setPage(String page) {
        this.page = page;
    }
}

第2步. 创建CusTagLib.tld(在WEB-INF目录下新建)

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 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 web-jsptaglibrary_2_0.xsd">
    <description>简单标签库</description>
    <tlib-version>1.0</tlib-version>
    <short-name>TagLib</short-name>
    <uri>/CusTagLib</uri>
    <tag>
        <!-- 标签名 -->
        <name>referer</name>
        <!-- 标签处理器类 -->
        <tag-class>com.sst.cx.simpletag.RefererTag</tag-class>
        <!-- 标签体允许的内容 -->
        <body-content>empty</body-content>
        <!-- 标签的属性描述 -->
        <attribute>
            <description>描述标签的site属性</description>
            <!-- 标签的site属性 -->
            <name>site</name>
            <required>true</required>
            <!-- 标签的属性值是否可以是一个表达式 -->
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <description>描述标签的page属性</description>
            <!-- 标签的page属性 -->
            <name>page</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
    </tag>
</taglib>

第3步. 在test.jsp文件中测试(访问则跳主页)

<%@ page language="java" pageEncoding="UTF-8"%>
<%--在jsp页面中导入自定义标签库 --%>
<%@taglib uri="/WEB-INF/CusTagLib.tld" prefix="hello"%>
<%--
在Jsp页面中使用防盗链标签 
  当用户尝试直接通过URL地址(http://localhost:8080/TestWeb2/simpletag/refererTagTest.jsp)访问这个页面时,防盗链标签的标签处理器内部就会进行处理,将请求重定向到/index.jsp。
--%>
<hello:referer site="http://localhost:8080" page="/index.jsp"/>
<!DOCTYPE HTML>
<html>
  <head>
    <title>防盗链标签测试</title>
  </head>
  <body>
     网站
  </body>
</html>
  1. if标签

第1步. 创建标签类(com.sst.cx.simpletag包下新建)

package com.sst.cx.simpletag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class IFTag extends SimpleTagSupport {
    /**
     * if标签的test属性
     */
    private boolean test;
    @Override
    public void doTag() throws JspException, IOException {
        if (test) {
            this.getJspBody().invoke(null);
        }
    }
    public void setTest(boolean test) {
        this.test = test;
    }
}

第2步. CusTagLib.tld中+

<tag>
    <description>if标签</description>
    <name>if</name>
    <tag-class>com.sst.cx.simpletag.IFTag</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
        <description>if标签的test属性</description>
        <name>test</name>
        <rtexprvalue>true</rtexprvalue>
        <required>true</required>
    </attribute>
</tag>

第3步. 在test.jsp中测试

<%@ page language="java" pageEncoding="UTF-8"%>
<%--在jsp页面中导入自定义标签库 --%>
<%@taglib uri="/WEB-INF/CusTagLib.tld" prefix="hello"%>
<!DOCTYPE HTML>
<html>
  <head>
    <title></title>
  </head>
  <body>
    <%--if标签的test属性值为true ,标签体的内容会输出--%>
    <hello:if test="true">
         <h3>网站</h3>
    </hello:if>
    <%--if标签的test属性值为false ,标签体的内容不会输出--%>
    <hello:if test="false">
        不输出
    </hello:if>
    
  </body>
</html>
  1. when otherwise标签
when标签和otherwise标签对应两个不同的标签处理器类。
希望当when标签执行后otherwise标签就不再执行,这时涉及到相互通讯的问题,可以让两个标签类拥有同一个父标签类来共享同一个变量来解决通信问题。

第1步-1. 创建标签类-父(com.sst.cx.simpletag包下新建)

package com.sst.cx.simpletag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class ChooseTag extends SimpleTagSupport {
    /**
     * 定义一个boolean类型的属性,该属性用于标识该标签下的某一个子标签是否已经执行过了,如果该标签下的某一个子标签已经执行过了,就将该属性设置为true。
     */
    private boolean isExecute;
    @Override
    public void doTag() throws JspException, IOException {
        // 输出标签体中的内容
        this.getJspBody().invoke(null);
    }
    public boolean isExecute() {
        return isExecute;
    }
    public void setExecute(boolean isExecute) {
        this.isExecute = isExecute;
    }
}

第1步-2. 创建标签类-when

package com.sst.cx.simpletag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class WhenTag extends SimpleTagSupport {
    /**
     * test属性,该属性值为true时,输出标签体中的内容
     */
    private boolean test;
    @Override
    public void doTag() throws JspException, IOException {
        // 获取标签的父标签
        ChooseTag parentTag = (ChooseTag) this.getParent();
        if (test == true && parentTag.isExecute() == false) {
            // 输出标签体中的内容
            this.getJspBody().invoke(null);
            // 将父标签的isExecute属性设置为true,告诉父标签,我(when标签)已经执行过了
            parentTag.setExecute(true);
        }
    }
    public void setTest(boolean test) {
        this.test = test;
    }
}

第1步-3. 标签处理类-otherWise

package com.sst.cx.simpletag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class OtherWiseTag extends SimpleTagSupport {
       @Override
        public void doTag() throws JspException, IOException {
            // 获取标签的父标签
            ChooseTag parentTag = (ChooseTag) this.getParent();
            // 如果父标签下的when标签没有执行过
            if (parentTag.isExecute() == false) {
                // 输出标签体中的内容
                this.getJspBody().invoke(null);
                // 设置父标签的isExecute属性为true,告诉父标签,我(otherwise标签)已经执行过了
                parentTag.setExecute(true);
            }
        }
}

第2步. CusTagLib.tld中+

<tag>
        <description>choose标签</description>
        <name>choose</name>
        <tag-class>com.sst.cx.simpletag.ChooseTag</tag-class>
        <body-content>scriptless</body-content>
    </tag>
    <tag>
        <description>when标签</description>
        <name>when</name>
        <tag-class>com.sst.cx.simpletag.WhenTag</tag-class>
        <body-content>scriptless</body-content>
        <attribute>
            <description>when标签的test属性</description>
            <name>test</name>
            <rtexprvalue>true</rtexprvalue>
            <required>true</required>
        </attribute>
    </tag>
    <tag>
        <description>otherwise标签</description>
        <name>otherwise</name>
        <tag-class>com.sst.cx.simpletag.OtherWiseTag</tag-class>
        <body-content>scriptless</body-content>
</tag>

第3步. 在test.jsp中测试

<%@ page language="java" pageEncoding="UTF-8"%>
<%--在jsp页面中导入自定义标签库 --%>
<%@taglib uri="/WEB-INF/CusTagLib.tld" prefix="hello"%>
<!DOCTYPE HTML>
<html>
  <head>
    <title></title>
  </head>
    <hello:choose>
          <hello:when test="${user==null}">
          when标签标签体输出的内容:
              <h3>用户为空</h3>
          </hello:when>
          <hello:otherwise>
              用户不为空
          </hello:otherwise>
      </hello:choose>
  </body>
</html>
  1. foreach迭代标签

第1步. 创建标签类

package com.sst.cx.simpletag;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class ForEachTag extends SimpleTagSupport {
    /**
     * 存储数据
     */
    private Object items;
    /**
     * 迭代集合时使用的变量
     */
    private String var;
    /**
     * 集合,用于存储items中的数据
     */
    private Collection collectionT;
    @Override
    public void doTag() throws JspException, IOException {
        PageContext pageContext = (PageContext) this.getJspContext();
        // 迭代collection集合
        Iterator it = collectionT.iterator();
        while (it.hasNext()) {
            // 得到一个迭代出来的对象
            Object object = (Object) it.next();
            // 将迭代出来的对象存放到pageContext对象中
            pageContext.setAttribute(var, object);
            // 输出标签体中的内容
            this.getJspBody().invoke(null);
        }
    }
    public void setVar(String var) {
        this.var = var;
    }
    public void setItems(Object items) {
        if (items instanceof Collection) {
            collectionT = (Collection) items;//list
        }else if (items instanceof Map) {
            Map map = (Map) items;
            collectionT = map.entrySet();//map
        }else if (items.getClass().isArray()) {
            collectionT = new ArrayList();
            // 获取数组的长度
            int len = Array.getLength(items);
            for (int i = 0; i < len; i++) {
                // 获取数组元素
                Object object = Array.get(items, i);
                collectionT.add(object);
            }
        }
        this.items = items;
    }
}

第2步. CusTagLib.tld中+

    <tag>
        <description>foreach标签</description>
        <name>foreach</name>
        <tag-class>com.sst.cx.simpletag.ForEachTag</tag-class>
        <body-content>scriptless</body-content>
        <attribute>
            <description>foreach标签的items属性</description>
            <name>items</name>
            <rtexprvalue>true</rtexprvalue>
            <required>true</required>
        </attribute>
        <attribute>
            <description>foreach标签的var属性</description>
            <name>var</name>
            <rtexprvalue>false</rtexprvalue>
            <required>true</required>
        </attribute>
    </tag>

第3步. 在test.jsp中测试

<%@ page language="java" pageEncoding="UTF-8"%>
<%--在jsp页面中导入自定义标签库 --%>
<%@taglib uri="/WEB-INF/CusTagLib.tld" prefix="hello"%>
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@page import="java.util.HashSet"%>
<%@page import="java.util.Set"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<!DOCTYPE HTML>
<html>
  <head>
    <title></title>
  </head>
<%
    // list集合
    List<String> listData = new ArrayList<String>();
    listData.add("hello");
    listData.add("hello2");
    // 对象数组
    Integer intObjArr[] = new Integer[]{1,2,3};
    // 基本数据类型数组
    int intArr[] = new int[]{4,5,6};
    // map集合
    Map<String,String> mapData = new HashMap<String,String>();
    mapData.put("a", "aaaaaa");
    mapData.put("b", "bbbbbb");
    // 将集合存储到pageContext对象中
    pageContext.setAttribute("listData", listData);
    pageContext.setAttribute("intObjArr", intObjArr);
    pageContext.setAttribute("intArr", intArr);
    pageContext.setAttribute("mapData", mapData);
%>
  <body>
          <%--迭代存储在pageContext对象中的list集合 --%>
         <hello:foreach items="${listData}" var="str">
             ${str}<br/>
         </hello:foreach>
         <hr/>
         <%--迭代存储在pageContext对象中的数组 --%>
         <hello:foreach items="${intObjArr}" var="num">
             ${num}<br/>
         </hello:foreach>
         <hr/>
         <%--迭代存储在pageContext对象中的数组 --%>
         <hello:foreach items="${intArr}" var="num">
             ${num}<br/>
         </hello:foreach>
         <hr/>
             <%--迭代存储在pageContext对象中的map集合 --%>
         <hello:foreach items="${mapData}" var="me">
             ${me}<br/>
         </hello:foreach>
  </body>
</html>
  1. html转义标签(将标签原样输出)

第1步. 创建标签类

package com.sst.cx.simpletag;
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class HtmlEscapeTag extends SimpleTagSupport {
    /**
     * @param message
     * @return 转义html标签
     */
    private String filter(String message) {
        if (message == null){
            return (null);
        }
        char content[] = new char[message.length()];
        message.getChars(0, message.length(), content, 0);
        StringBuilder result = new StringBuilder(content.length + 50);
        for (int i = 0; i < content.length; i++) {
            switch (content[i]) {
            case '<':
                result.append("&lt;");
                break;
            case '>':
                result.append("&gt;");
                break;
            case '&':
                result.append("&amp;");
                break;
            case '"':
                result.append("&quot;");
                break;
            default:
                result.append(content[I]);
            }
        }
        return (result.toString());
    }
    @Override
    public void doTag() throws JspException, IOException {
        StringWriter sw = new StringWriter();
        // 将标签体中的内容先输出到StringWriter流
        this.getJspBody().invoke(sw);
        // 得到标签体中的内容
        String content = sw.getBuffer().toString();
        // 转义标签体中的html代码
        content = filter(content);
        // 输出转义后的content
        this.getJspContext().getOut().write(content);
    }
}

第2步. CusTagLib.tld中+

<tag>
     <description>HtmlEscape标签</description>
     <name>htmlEscape</name>
     <tag-class>com.sst.cx.simpletag.HtmlEscapeTag</tag-class>
     <body-content>scriptless</body-content>
</tag>

第3步. test.jsp测试

<%@ page language="java" pageEncoding="UTF-8"%>
<%--在jsp页面中导入自定义标签库 --%>
<%@taglib uri="/WEB-INF/CusTagLib.tld" prefix="hello"%>
<!DOCTYPE HTML>
<html>
  <head>
    <title></title>
  </head>
  <body>
         <hello:htmlEscape>
              <a href="http://www.cnblogs.com">nihao</a>
          </hello:htmlEscape>
         
  </body>
</html>
  1. out输出标签

第1步. 创建标签类

package com.sst.cx.simpletag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class OutTag extends SimpleTagSupport {
    /**
     * 要输出的内容
     */
    private String content;
    /**
     * 是否将内容中的html进行转义后输出
     */
    private boolean escapeHtml;
    public void setContent(String content) {
        this.content = content;
    }
    public void setEscapeHtml(boolean escapeHtml) {
        this.escapeHtml = escapeHtml;
    }
    @Override
    public void doTag() throws JspException, IOException {
        if (escapeHtml == true) {
            // 转义内容中的html代码
            content = filter(content);
            // 输出转义后的content
            this.getJspContext().getOut().write(content);
        }else {
            this.getJspContext().getOut().write(content);
        }
    }
    /**
     * @param message
     * @return 转义html标签
     */
    private String filter(String message) {
        if (message == null){
            return (null);
        }
        char content[] = new char[message.length()];
        message.getChars(0, message.length(), content, 0);
        StringBuilder result = new StringBuilder(content.length + 50);
        for (int i = 0; i < content.length; i++) {
            switch (content[i]) {
            case '<':
                result.append("&lt;");
                break;
            case '>':
                result.append("&gt;");
                break;
            case '&':
                result.append("&amp;");
                break;
            case '"':
                result.append("&quot;");
                break;
            default:
                result.append(content[I]);
            }
        }
        return (result.toString());
    }
}

第2步. CusTagLib.tld中+

<tag>
        <description>out标签</description>
        <name>out</name>
        <tag-class>com.sst.cx.simpletag.OutTag</tag-class>
        <body-content>empty</body-content>
        <attribute>
            <description>out标签的content属性,表示要输出的内容</description>
            <name>content</name>
            <rtexprvalue>true</rtexprvalue>
            <required>true</required>
        </attribute>
        <attribute>
            <description>out标签的escapeHtml属性,表示是否将内容中的html进行转义后输出</description>
            <name>escapeHtml</name>
            <rtexprvalue>true</rtexprvalue>
            <required>false</required>
        </attribute>
</tag>

第3步. test.jsp测试

<%@ page language="java" pageEncoding="UTF-8"%>
<%--在jsp页面中导入自定义标签库 --%>
<%@taglib uri="/WEB-INF/CusTagLib.tld" prefix="hello"%>
<!DOCTYPE HTML>
<html>
  <head>
    <title></title>
  </head>
  <body>
       <%--使用out标签输出content属性的内容 --%>
          <hello:out content="<a href='http://www.cnblogs.com'>hello</a>"/>
          <hr/>
          <%--使用out标签输出 content属性的内容,内容中的html代码会进行转义处理--%>
          <hello:out content="<a href='http://www.cnblogs.com'>hello</a>" escapeHtml="true"/>
  </body>
</html>

打包开发好的标签库

打包

1. 新建Java项目
    1. 将前面开发好的src目录下连包复制到src下
    2. 新建lib目录(从/Tomcat/lib下找jsp-api.jar和servlet-api.jar,复制到lib下)
    3. 新建META-INF目录,将前面的CusTagLib.tld复制到该目录下
2. Export项目 | Java | Jar file,不勾选.classpath .project(忽略警告)    
要打包的项目

使用

1. 将jar包放在WEB-INF的lib下
2. jsp使用
  <%@taglib uri="www.com.sst.cx/CusTagLib" prefix="hello"%>
上一篇下一篇

猜你喜欢

热点阅读