jsp自定义标签

一、概述

JSP 2.0 中提供了两种新的开发自定义标记的方法:

1、简单标签机制SimpleTag

JSP 2.0 中加入了新的创建自定义标记的API:javax.servlet.jsp.tagext.SimpleTag,该API 定义了用来实现简单标记的接口。和JSP 1.2 中的已有接口不同的是,SimpleTag 接口不使用doStartTag()和doEndTag()方法,而提供了一个简单的doTag()方法。这个方法在调用该标记时只被使用一次。一个自定义标记中实现的所有逻辑都在这个方法中实现。相对JSP1.2 中自定义标记机制,SimpleTag 的方法和处理周期要简单得多。

注意:SimpleTag接口:只提供了一个doTag()方法,在这个方法中实现标记的所有逻辑。

2、 标签文件

标签文件允许JSP 网页作者使用JSP 语法创建可复用的标签库。标签文件的扩展名必须是.tag。

 注意:网页引用标签文件,文件扩展名必须是.tag

1.1 使用简单标签机制

与JSP1.2 相似,开发自定义标签要遵循“开发标记类---配置TLD 文件----在JSP 中使用”的过程,

示例如下:

步骤一:编写标记处理类AddTag.java

package tag;

import java.io.IOException;

import javax.servlet.jsp.JspContext;

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.JspWriter;

import javax.servlet.jsp.tagext.SimpleTagSupport;

public class AddTag extends SimpleTagSupport{

         private int num1 = 0;

         private int num2 = 0;

         public void setNum1(int num1) {

                   this.num1 = num1;

         }

         public void setNum2(int num2) {

                   this.num2 = num2;

         }

         public void doTag() throws JspException, IOException {

                   JspContext ctx = getJspContext();

                   JspWriter out = ctx.getOut();

                   int sun = num1+num2;

                   out.print(num1+"+"+num2+"="+sun);

         }

}

步骤二:编写描述符文件 test.tld:放在/WEB-INF/test-tld/test.tld

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

<!DOCTYPE taglib

        PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"

        "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

<taglib> <!-- 标签定义成<test:add /> -->

    <tlibversion>1.0</tlibversion>

    <jspversion>1.2</jspversion>

    <shortname>test</shortname> <!-- 这个test可以设置为空,你标签就可以定义成<add />了,不过一般比较常见的都是<test:add />这种类型的 -->

    <tag>

       <name>add</name>

       <tagclass>tag.AddTag</tagclass>

       <bodycontent>empty</bodycontent> <!-- 就是<test:add ></test>中间的内容是空的 -->

       <info>Add Tag</info>

       <attribute>

           <name>num1</name>

           <required>true</required>

           <rtexprvalue>true</rtexprvalue>

       </attribute>

       <attribute>

           <name>num2</name>

           <required>true</required>

           <rtexprvalue>true</rtexprvalue>

       </attribute>

    </tag>

</taglib>

步骤三:在JSP 中使用标记:

<%@ page language="java"   pageEncoding="UTF-8"%>

<%@ taglib prefix="test" uri="/WEB-INF/test-tld/test.tld" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <title>测试自定义标签</title>

  </head>

  <body>

        SimpleTag 测试:<br />

        <h1><test:add num1="2" num2="3"/> </h1>

  </body>

</html

无需在web.xml下配置,

运行结果如下:

1.2 使用标签文件

通过标签文件实际上可以将一个JSP 文件的内容作为标签处理程序,但该文件扩展名必须是.tag,

示例如下:

1) 标记文件hello.tag,该文件存放在 WEB-INF/tags 目录下

hello.tag.<br>

IP:<%= request.getRemoteAddr() %>

2) 在JSP 中使用tag 文件

<%@ page contentType="text/html;charset=gb2312" %>

<%@ taglib prefix="test" tagdir="/WEB-INF/tags/" %>

<h2>Tag File 测试</h2>

<test:hello/>

3) 运行效果如下:

 

二 、自定义标签简介

2.1 自定义标签概念

 JSP 自定义标记为在动态Web 页中将表示与业务逻辑分离提供了一种标准化的机制,使页面设计者可以将注意力放到表示上,而应用程序开发人员编写后端的代码。

注意:自定义标记可以在后台完成某些操作,而HTML 标记只能完成前台显示的功能,自定义标签的使用方法和标准HTML标签使用方法一样。

2.2 标签相关概念

JSP 自定义标签的使用语法与普通HTML标签相同,与自定义标签相关的基本术语简单说明如下,

这些术语在开发JSP 自定义标签时要用到:

1) 自结束标签——没有标记体的标签

示例:<test:myhrtag />

说明:假设myhrtag 是一个自定义标签

2) 属性

示例:<test:myhrtag color=”red” />

说明:以上标签中包含了color 属性,值为red

3) 带标记体的标签

示例:<test:myhrtag > xxxxx </test:myhrtag>

说明:以上标签中间的xxxxx 即为标记体

4) 子标记

示例: <test:myhrtag >

<test:mytag2/>

</test:myhrtag>

说明:以上myhrtag 标签中间的mytag2 即为子标记

2.3 如何创建自定义标签

自定义标签功能的实现要求在后台必须有一个相关的JAVA 类的支持,但并不是任意编写一个JAVA 类就能处理JSP 标签,这个类也必须实现指定的规范才能用于支持JSP 标签,这些规范表现形式也是接口和类,它们在javax.servlet.jsp.tagext包中声明,主要接口/类的描述如下:

javax.servlet.jsp.tagext.Tag 接口,所有处理JSP 标签的类必须实现该接口。该接口中声明了6个方法,如果直接从该接口生成类则必须实现所有的6 个方法,通常不会直接通过该接口生成标签的处理类。

 javax.servlet.jsp.tagext.TagSupport 类,该类实现了Tag 接口,用于创建不带标记体的自结束标签,这些标签中可以带属性。

javax.servlet.jsp.tagext.BodyTagSupport 类,该类继承了TagSupport,用于创建带标记体的标签。

    通常我们自定义的标签,编写处理程序时使用TagSupport 和BodyTagSupport 即可,不需要涉及到标签体的,继承TagSupport,需要用标签体的,用BodyTagSupport,以下是开发和使用一个JSP 自定义标签的全过程:

1) 开发标记处理类,编译生成class 文件,该类要继承TagSupport 或BodyTagSupport;

2) 创建标记库描述符文件*.tld,在该文件中为标记处理类指定标签名、声明标签属性;

3) 在JSP 中引用标签库;

4) 在JSP 中使用标JSP 标签

三、自结束标签(不带标签体,TagSupport)

3.1 自结束标签简介

这是一种不带标记体的标签,所以该类标签的处理类直接继承javax.servlet.jsp.tagext.TagSupport即可。

TagSupport 的主要方法如下:

public int doStartTag() throws JspException           //该方法实现是可选的,不实现该方法:当遇到开始标签时,什么都不做。

在WEB 容器遇到标签开始时,该方法会运行。

public int doEndTag() throws JspException

在WEB 容器遇到标签结束时,该方法会运行。

(一)PageContext类

         TagSupport 类中有一个重要的成员:pageContext,该成员的功能与JSP 的内置对象pageContex完全相同。通过该对象可以得到其他几个JSP 对象的引用。这样,我们就可以在JAVA 类中与JSP 进行交互了。如: JspWriter out=pageContext.getOut();这一语句可以得到JSP 内置对象out 的引用,通过out 我们就可以向客户端浏览器中输出内容了。要使用其他几个JSP 对象原理与此相同。

  pageContext是javax.servlet.jsp.PageContext类的实例对象,可以使用PageContext类的方法。

实际上,pageContext对象提供了对JSP页面所有的对象及命名空间的访问,正如前面所介绍的一样,

使用pageContext对象可以访问application对象、exception对象,还有session对象等。

pageContext对象的方法可以访问除本身以外的8个JSP内部对象,还可以直接访问绑定在application对象、page对象、

request对象、session对象上的Java对象。pageContext对象相当于JSP程序中所有对象功能的集成者。

不过,这里存在着一个问题,既然可以直接访问JSP内部对象,为什么还要多此一举,通过pageContext对象来访问它们呢?

getOut()

该方法返回一个JspWriter类的实例对象,也就是JSP内置对象——out对象,可以往客户端写入输入流。

<%

       JspWriter myout=pageContext.getOut();

       myout.println(“myout write: hello world”+”<br>”);

       out.println(“out write: hello world”); //或者使用write(String str)方法

%>

3.2 自结束标签开发示例

方式二:动态引用

步骤一:编写标记处理类

package tag;

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.JspWriter;

import javax.servlet.jsp.tagext.Tag;

import javax.servlet.jsp.tagext.TagSupport;

/**

 * 自定义自结束标签,不含标签体。

 *

 * 1、在自定义的类中,重写了父类TagSupport 的两个方法:doStartTag()doEndTag(),在容器遇到标记开始时会运行doStartTag(),遇到标记结束时运行doEndTag()方法;

 * 2doStartTag()方法的返回值:通常可以取两个值:

 *      EVAL_BODY_INCLUDE——包含标记体,本例中要编写自结束标记所以不使用该值;

 *      SKIP_BODY——跳过标记体,即不处理标记体,开发自结束标记应该使用该值。

 

 * 3doEndTag()方法的返回值:通常可以取两个值:

 *      SKIP_PAGE——返回这个值,则终止页面执行;

 *      EVAL_PAGE——返回该值则处理完当前标记后,JSP 页面中止运行。

 */

public class MyHrTag extends TagSupport{

    private static final long serialVersionUID = 1L;

    /*

     * WEB 容器遇到标签开始时,该方法会运行。

     * 该方法可以自行定义,也可以不定义。不定义该方法则遇到开始标签什么都不做

     * */

    public int doStartTag() throws JspException {

       try {

           //得到网络输出流,pageContext 是从父类继承过来的成员

           JspWriter out = pageContext.getOut();

           //向网页输出内容

           out.println("<h4>开始执行doStartTag()......</h4>");

           //输出条水平线;

           for(int i=1; i<=5; i++){

              out.println("<hr>");

           }

       catch (Exception e) {

           e.printStackTrace();

       }

       //return EVAL_BODY_INCLUDE; //处理标记体

       return Tag.SKIP_BODY//跳过标记体;

    }   

    /*

     * WEB 容器遇到标签结束时,该方法会运行。

     * 该方法可以自行定义,也可以不定义。不定义该方法则遇到结束标签什么都不做

     * */

    public int doEndTag() throws JspException {

       try {

           JspWriter out=pageContext.getOut();

           out.println("<h3>开始执行doEndTag().....</h3>.");

       catch (Exception e) {

           e.printStackTrace();

       }

       //return Tag.SKIP_PAGE; //返回这个值,则终止页面执行;

       return EVAL_PAGE;

    }

} 

步骤二:创建标记库描述符文件myhr.tld,该文件要存放在 WEB-INF/test-tld 目录下:

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

<!DOCTYPE taglib

        PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"

        "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">    

<!--

解释:

tld 文件中,映射了标记名和处理程序类;

<tallib>元素,代表开始一个标记库的描述

<tligversion>元素,代表标记库的版本

<jspversion>元素,代表标记所支持的JSP 的版本

<shortname>为标记库起别名,相当于注释,无实际用途

<tag>元素,代表开始描述一个标记,其下子元素如下:

    <name>——为标记处理类起的标记名

    <tagclass>——指定标记处理类的全名(即带包的名字)

    <bodycontent>——标记体的类型,该示例中不需要标记体,所有设置为EMPTY,该值的其他取值在后续内容中讲解

 -->

<taglib>

    <tlibversion>1.0</tlibversion>

    <jspversion>1.1</jspversion>

    <shortname>myhr</shortname> <!-- 标签以<myhr:XXX />形式 -->

    <tag>

       <name>MyHr</name> <!-- 该标签为<myhr:MyHr /> -->

       <tagclass>tag.MyHrTag</tagclass>

       <bodycontent>EMPTY</bodycontent>

    </tag>

</taglib>

步骤三:在JSP 中引用标记库描述文件

引用标记库有两种方式,分别称为静态引用和动态引用。

方式一:动态引用(即直接在JSP 页面中使用TLD 文件)

<%@ page language="java"  pageEncoding="UTF-8"%>

<%@ taglib uri="/WEB-INF/test-tld/myhr.tld" prefix="myhr" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <title>My JSP 'MyHr1.jsp' starting page</title>

  </head>

  <body>

   <myhr:MyHr/>

  </body>

</html>

JSP 指令<%@ taglib... %>用于引用标记库,该指令的两个属性作用如下:

uri——指明要引用的标记库,在静态引用中就是TLD 文件的路径

prefix——为标记起的前缀名,可以防止多个标记重名的情况出现

方式二:静态引用

首先在web.xml 中为TLD 文件声明别名:

<?xml version="1.0" encoding="ISO-8859-1" ?>

<Web-app>

……

<taglib>

<taglib-uri>myhr2</taglib-uri>

<taglib-location>/WEB-INF/myhr.tld</taglib-location>

</taglib>

……

</Web-app>

然后在JSP 中通过别名引用TLD 文件:

<%@ page language="java"  pageEncoding="UTF-8"%>

<%@ taglib uri="myhr2" prefix="myhr" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <title>My JSP 'MyHr1.jsp' starting page</title>

  </head>

  <body>

   <myhr:MyHr/>

  </body>

</html>

到此为止,自结束标签开发完毕,其中主要工作有两个:开发标记处理类、配置TLD 文件。访

问JSP,运行结果如下:

 

四、标签中的属性

4.1 为自定义标签添加属性

以上的示例中开发了一个简单的JSP 标签,但一个实用的标签通常还要由属性来制定标签的特定行为,以下示例演示为自定义标签添加属性。该示例在1.2 示例基础上,为标签添加了color 和loop两个自定义属性,以控制水平线的颜色和输出的水平线的数量。

步骤一:编写标记处理类

package tag;

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.JspWriter;

import javax.servlet.jsp.tagext.Tag;

import javax.servlet.jsp.tagext.TagSupport;

/**

 *

 * 该类为自定义标签添加了两个属性,属性的声明与javabean 语法完全相同,即属性本身是private 类型,

 * 但要求提供public getset 方法。

 * 

 */

public class MyHrTag2 extends TagSupport{  

    //声明属性

    private String color = "black"//定义线条颜色

    private String loop = "1"//定义输出水平线的条数   

    //严格按照javabean模式

    public void setColor(String color) {

       this.color = color;

    }   

    //严格按照javabean模式

    public void setLoop(String loop) {

       this.loop = loop;

    }   

    //只定义遇到开始标签执行方法即可了。

    public int doStartTag() throws JspException {

       try {

           //得到网络输出流

           JspWriter out = pageContext.getOut();

           //向网页输出内容;

           out.println("<h4>开始执行doStartTag()......</h4>");

           int n = Integer.parseInt(loop);

           for (int i=1;i<=n;i++) {

              out.print("<hr color='"+this.color+"' />");

           }

       catch (Exception e) {

           e.printStackTrace();

       }

       return Tag.SKIP_BODY;

    }   

步骤二:创建TLD 文件,本例中是在1.2 中的myhr.tld 文件中进行修改得到:

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

<!DOCTYPE taglib

        PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"

        "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">    

<!--

解释:

   tld 文件中,映射了标记名和处理程序类;

   <tallib>元素,代表开始一个标记库的描述

   <tligversion>元素,代表标记库的版本

   <jspversion>元素,代表标记所支持的JSP 的版本

   <shortname>为标记库起别名,相当于注释,无实际用途

   <tag>元素,代表开始描述一个标记,其下子元素如下:

    <name>——为标记处理类起的标记名

    <tagclass>——指定标记处理类的全名(即带包的名字)

    <bodycontent>——标记体的类型,该示例中不需要标记体,所有设置为EMPTY,该值的其他取值在后续内容中讲解

    <tag>中的子元素

       <attribute>用于为标签声明属性,其子元素如下:

           <name>——用于指定属性名称

           <required>——用于声明该属性是否为必需的,本例中声明colorloop 两个属性都不是必需的。

 -->

<taglib>

    <tlibversion>1.0</tlibversion>

    <jspversion>1.1</jspversion>

    <shortname>myhr</shortname> <!-- 标签以<myhr:XXX />形式 -->

    <tag>

       <name>MyHr</name> <!-- 该标签为<myhr:MyHr /> -->

       <tagclass>tag.MyHrTag</tagclass>

       <bodycontent>EMPTY</bodycontent>

    </tag>

    <tag>

       <name>MyHr2</name> <!-- 该标签为<myhr:MyHr /> -->

       <tagclass>tag.MyHrTag2</tagclass>

       <bodycontent>EMPTY</bodycontent>

       <attribute>

           <name>color</name>

           <required>false</required>

       </attribute>

       <attribute>

           <name>loop</name>

           <required>false</required>

       </attribute>

    </tag>

</taglib

步骤三:在JSP 中引用TLD,并使用标签

<%@ page language="java"  pageEncoding="UTF-8"%>

<%@ taglib uri="/WEB-INF/test-tld/myhr.tld" prefix="myhr" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <title>My JSP 'MyHr3.jsp' starting page</title>

  </head>

  <body>

    第一次测试(未赋属性值):<br>

    <myhr:MyHr2/> 

    第二次测试(使用两个属性):<br>

    <myhr:MyHr2 color="red" loop="3"/>   

    第三次测试(使用一个属性):<br>

    <myhr:MyHr2 color="blue"/>  

    测试完毕.

  </body>

</html>

运行图

 

4.2 标签综合示例

该示例中创建了一个JSP 标签,用于在JSP 中判断用户是否登录过,如果没登录过则自动转到登录页,这样就可以避免在JSP 中使用代码段进行业务判断了。

第一步:定义标签类LoginTag.java,为标记处理程序,从session 中取出登录标志进行判断用户是否登录过:

package tag;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.tagext.Tag;

import javax.servlet.jsp.tagext.TagSupport;

public class LoginTag extends TagSupport{

    public int doStartTag() throws JspException {

       try {

           HttpSession session = pageContext.getSession();

           Object obj = session.getAttribute("User");

           //判断是否从未登录过,如果没登录过则转到登录页;

           if(obj==null){

              ((HttpServletResponse)pageContext.getResponse()).sendRedirect("login.html");

              return SKIP_BODY;

           }

       catch (Exception e) {

           e.printStackTrace();

       }

       return Tag.SKIP_BODY;

    }

第二步:编写login.tld

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

<!DOCTYPE taglib

        PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"

        "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">    

<!--

解释:

    tld 文件中,映射了标记名和处理程序类;

    <tallib>元素,代表开始一个标记库的描述

    <tligversion>元素,代表标记库的版本

    <jspversion>元素,代表标记所支持的JSP 的版本

    <shortname>为标记库起别名,相当于注释,无实际用途

    <tag>元素,代表开始描述一个标记,其下子元素如下:

    <name>——为标记处理类起的标记名

    <tagclass>——指定标记处理类的全名(即带包的名字)

    <bodycontent>——标记体的类型,该示例中不需要标记体,所有设置为EMPTY,该值的其他取值在后续内容中讲解

    <tag>中的子元素

       <attribute>用于为标签声明属性,其子元素如下:

           <name>——用于指定属性名称

           <required>——用于声明该属性是否为必需的,本例中声明colorloop 两个属性都不是必需的。

 -->

<taglib>

    <tlibversion>1.0</tlibversion>

    <jspversion>1.1</jspversion>

    <shortname>test</shortname> <!-- 标签以<myhr:XXX />形式 -->

    <tag>

       <name>islogin</name> <!-- 该标签为<myhr:MyHr /> -->

       <tagclass>tag.LoginTag</tagclass>

       <bodycontent>EMPTY</bodycontent>

    </tag>

</taglib>

第三步:动态调用标签

部分内容如下:

<%@ page language="java" contentType="text/html;charset=GB2312"%>

<%@ taglib uri="/WEB-INF/myhr.tld" prefix="test" %>

….

<test:islogin/>

<h3>欢迎</h3>

….

4.3 TLD 文件概述

以上示例中创建了标记描述符文件*.TLD,现总结该文件的用法如下:

该文件必须放在 WEB-INF 目录下;

该文件是XML 格式的文件,各元素及功能说明如下:

元素    说明

<taglib> 代表开始一个标记库的描述

<tlibversion> 代表标记库的版本,是自定义的

<jspversion> 代表标记所支持的JSP 的版本

<shortname> 为标记库起别名,相当于注释,无实际用途

<tag>     代表开始描述一个标记

表11-1 标记描述符TLD 文件元素说明

其中<tag>元素中又包含若干子元素,说明如下:

元素 说明

<name> 为标记处理类起的标记名

<tagclass> 指定标记处理类的全名(即带包的名字)

<bodycontent> 标记体的内容类型,如果为EMPTY 代表无标记体

<attribute> 用于为标签声明属性

表11-2 <tag>元素的子元素

<attribute>元素为标签声明属性时,需要两个子元素:

<name> 用于指定属性名称

<required> 用于声明该属性是否为必需的

五、标签中的标记体

5.1 标记体简介

标签的标记体是 JSP 页中出现在自定义标签的开始和结束标签之间的数据,标记体也称正文。操纵其正文的标签称为带标记体的标签(也称为正文标签)。

可以编写标签处理程序对标签的标记体进行操作。要编写标记体标签处理程序,必须实现BodyTag 接口。BodyTag 继承了Tag 的所有方法,而且还实现了另外两个处理正文内容的方法,见下表:

                   方法                            说明

setBodyContent(BodyContent b)                 bodyContent 属性的 Setter 方法

doInitBody()                                             对正文内容进行初始化操作

 

为方便开发,在JSP 类库中为BodyTag 接口提供了实现类:javax.servlet.jsp.tagext.BodyTagSupport。该类继承了TagSupport 并实现了BodyTag 接口。因此,标记体标签处理程序只需要覆盖要使用的方法。BodyTagSupport 类中定义了一个protected bodyContent 成员变量及get/setBodyContent()方法,bodyContent 是一个缓冲区,用以保存标记体正文内容。

在一个标签处理类中,BodyTag 的处理流程如下:

         1、当容器创建一个新的标签实例后,通过setPageContext 来设置标签的页面上下文。

2、使用setParent 方法设置这个标签的上一级标签,如果没有上一级嵌套,设置为null。

3、设置标签的属性,如果没有定义属性,就不调用此类方法。

4、调用doStartTag 方法,这个方法可以返回以下三者之一:EVAL_BODY_INCLUDE、

EVAL_BODY_BUFFERED、SKIP_BODY,当返回EVAL_BODY_INCLUDE 时,就将标记

体直接写到输出流中,如果返回SKIP_BODY,就不再计算标签的正文,如果返回EVAL_BODY_BUFFERED,就将标记体的正文包含到bodyContent 成员中。

5、调用setBodyContent 设置当前的BodyContent.

6、调用doInitBody,可以在该方法中对BodyContent 进行一些初始化操作.每次计算完Body 后调用doAfterBody,如果返回EVAL_BODY_AGAIN,表示继续处理一次标记体,直到返回SKIP_BODY 才继续往下执行.

7、调用doEndTag 方法,结束标签处理.

5.2 一个简单的带标记体的标签

本示例中创建了一个标签用于在浏览器中输出其标记体内容,且输出的次数由标签的属性决定:

         步骤一:编写标记处理类

package tag;

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.tagext.BodyTagSupport;

/**

 *

 * doStartTag()中的返回值EVAL_BODY_INCLUDE,可以直接将标签的正文内容输出到浏览器中。

 * doAfterBody()在处理完一次正文后会自动执行,

 * 该方法如果返回EVAL_BODY_AGAIN,则代表再处理一遍正文(即输出到浏览器),返回SKIP_BODY 代表正文处理到此结束。

 * 本例中循环向浏览器中输出标记体的正文,直到属性loop 的值小于1

 *

 */

public class TestBodyTag extends BodyTagSupport {

    private int loop ; //定义输出标签体的次数属性,比如:2的话就表示连续重复输出标签体2

    public void setLoop(int loop) {

       this.loop = loop;

    }

    public int doStartTag() throws JspException {

       if(loop>0){

           return EVAL_BODY_INCLUDE//自动将标签体包含到输出流中,第一次将标签体输出到浏览器中.

       }else {

           return SKIP_BODY//跳过标签体,不将标签体包含到输出流,不处理标签体,直接忽略.

       }

    }

    public int doAfterBody() throws JspException {

       /**

        * doAfterBody()在处理完一次正文后会自动执行,

        * 该方法如果返回EVAL_BODY_AGAIN,则代表再处理一遍正文(即输出到浏览器),返回SKIP_BODY 代表正文处理到此结束。

        * 本例中循环向浏览器中输出标记体的正文,直到属性loop 的值小于1

        */

       if(loop>1){

           loop--;

           return EVAL_BODY_AGAIN;

       }else {

           return SKIP_BODY;

       }

    }

}

步骤二:创建标记库描述符文件testbodytag.tld,该文件要存放在 WEB-INF/test-tld 目录下:

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

<!DOCTYPE taglib

        PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"

        "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">    

<!--

解释:

    tld 文件中,映射了标记名和处理程序类;

    <tallib>元素,代表开始一个标记库的描述

    <tligversion>元素,代表标记库的版本

    <jspversion>元素,代表标记所支持的JSP 的版本

    <shortname>为标记库起别名,相当于注释,无实际用途

    <tag>元素,代表开始描述一个标记,其下子元素如下:

    <name>——为标记处理类起的标记名

    <tagclass>——指定标记处理类的全名(即带包的名字)

    <bodycontent>——标记体的类型,该示例中不需要标记体,所有设置为EMPTY,该值的其他取值在后续内容中讲解

    <tag>中的子元素

       <attribute>用于为标签声明属性,其子元素如下:

           <name>——用于指定属性名称

           <required>——用于声明该属性是否为必需的,本例中声明colorloop 两个属性都不是必需的。

 -->

<taglib>

    <tlibversion>1.0</tlibversion>

    <jspversion>1.1</jspversion>

    <shortname>test</shortname> <!-- 标签以<myhr:XXX />形式 -->

    <tag>

       <name>bodytag</name> <!-- 该标签为<myhr:MyHr /> -->

       <tagclass>tag.TestBodyTag</tagclass>

       <bodycontent>tagdependent</bodycontent>

       <attribute>

           <name>loop</name>

           <required>true</required>

       </attribute>

    </tag>

</taglib

步骤三:在JSP 中使用该标记

<%@ page language="java"   pageEncoding="UTF-8"%>

<%@ taglib prefix="test" uri="/WEB-INF/test-tld/testbodytag.tld" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <title>测试自定义带标签体的标签</title>

  </head>

  <body>

        测试带标记体的自定义标记:<br>

        <test:bodytag loop="4">

           这是标记体<br />

        </test:bodytag>

  </body>

</html>

运行图:

 

5.3 一个简单的带标记体的标签(二)

在doStartTag()方法中返回EVAL_BODY_INCLUDE,简单地将标记体的内容直接输出到了浏览器中,并未对内容进行任何处理,在一些业务中有时需要对标记体正文进行处理,以下示例演示了如何读取标记体内容并进行处理:

步骤一:编写标记处理类

package tag;

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.JspWriter;

import javax.servlet.jsp.tagext.BodyContent;

import javax.servlet.jsp.tagext.BodyTagSupport;

/*

 * doStratTag()中的返回值EVAL_BODY_BUFFERED 代表不直接将标记体内容写到输出流中,

 而是缓存到成员变量bodyContent 中(该成员从BodyTagSupport 继承过来),

 * EVAL_BODY_INCLUDE是直接将标记体内容写到输出流中

 * */

public class EqualTag extends BodyTagSupport{

    private String name = "";

    private String value = "";

    public void setName(String name) {

       this.name = name;

    }

    public void setValue(String value) {

       this.value = value;

    }

    public int doStartTag() throws JspException {

       System.out.println("do starttag()....");

       return EVAL_BODY_BUFFERED;  //不直接将标记体内容写到输出流中,而是缓存到成员变量bodyContent 

    }  

    public void setBodyContent(BodyContent b) {

       System.out.println("setBodycontent()...."+b.getString()+"++");

       this.bodyContent = b;  //bodyContent 赋值前,bodyContent是空的

       System.out.println("setBodycontent()...."+bodyContent.getString()+"++");

    }

    //初始化标记体

    public void doInitBody() throws JspException {

       System.out.println("doInitBody()....."+bodyContent.getString()+"++");

    }  

    public int doAfterBody() throws JspException {

       System.out.println("doAfterBody()...."+bodyContent.getString()+"++");

       return SKIP_BODY;  //停止包含

    }

    public int doEndTag() throws JspException {  //处理标签体内容,将标签体的内容加租倾斜

       System.out.println("doEndTag()..."+bodyContent.getString()+"++");

       String username = (String)pageContext.getSession().getAttribute(name);  //获得存在session的某属性的值,该属性值由标签属性提供获取。

       String str = bodyContent.getString();      

       if(username.equals(value)){  //如果该值与标签属性相等

           str = "<b><i>"+str+"</i></b>";   //加粗倾斜,不是的话就原样输出

       }      

       try {

           JspWriter out = pageContext.getOut();

           out.print(str);  //将加粗倾斜后的标签体输出到页面上

           this.bodyContent = null;

       catch (Exception e) {

           e.printStackTrace();

       } 

       return EVAL_PAGE;

    }

}

步骤二:在标记库描述符文件testbodytag.tld,添加tag标记:

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

<!DOCTYPE taglib

        PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"

        "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">    

<!--

解释:

    tld 文件中,映射了标记名和处理程序类;

    <tallib>元素,代表开始一个标记库的描述

    <tligversion>元素,代表标记库的版本

    <jspversion>元素,代表标记所支持的JSP 的版本

    <shortname>为标记库起别名,相当于注释,无实际用途

    <tag>元素,代表开始描述一个标记,其下子元素如下:

    <name>——为标记处理类起的标记名

    <tagclass>——指定标记处理类的全名(即带包的名字)

    <bodycontent>——标记体的类型,该示例中不需要标记体,所有设置为EMPTY,该值的其他取值在后续内容中讲解

    <tag>中的子元素

       <attribute>用于为标签声明属性,其子元素如下:

           <name>——用于指定属性名称

           <required>——用于声明该属性是否为必需的,本例中声明colorloop 两个属性都不是必需的。

 -->

<taglib>

    <tlibversion>1.0</tlibversion>

    <jspversion>1.1</jspversion>

    <shortname>test</shortname> <!-- 标签以<myhr:XXX />形式 -->

    <tag>

       <name>bodytag</name> <!-- 该标签为<myhr:MyHr /> -->

       <tagclass>tag.TestBodyTag</tagclass>

       <bodycontent>tagdependent</bodycontent>

       <attribute>

           <name>loop</name>

           <required>true</required>

       </attribute>

    </tag>

    <tag>

       <name>equal</name>

       <tagclass>tag.EqualTag</tagclass>

       <bodycontent>tagdependent</bodycontent>

       <attribute>

           <name>name</name>

           <required>true</required>

       </attribute>

       <attribute>

           <name>value</name>

           <required>true</required>

       </attribute>

    </tag>

</taglib

步骤三:在JSP 中使用该标记

<%@ page language="java"   pageEncoding="UTF-8"%>

<%@ taglib prefix="test" uri="/WEB-INF/test-tld/testbodytag.tld" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <title>测试自定义带标签体的标签</title>

  </head>

  <body>

    <% session.setAttribute("username","tom"); %>

    <test:equal name="username" value="tom">session中的username的属性值如果是tom,则这段文字加粗倾斜</test:equal>

    <br />

    <test:equal name="username" value="tom1">session中的username的属性值如果是tom,则这段文字加粗倾斜</test:equal>

  </body>

</html>

运行界面如下:

后台输出如下:

do starttag()....

setBodycontent()....++

setBodycontent()....++

doInitBody().....++

doAfterBody()....session中的username的属性值如果是tom,则这段文字加粗倾斜++

doEndTag()...session中的username的属性值如果是tom,则这段文字加粗倾斜++

do starttag()....

setBodycontent()....++

setBodycontent()....++

doInitBody().....++

doAfterBody()....session中的username的属性值如果是tom,则这段文字加粗倾斜++

doEndTag()...session中的username的属性值如果是tom,则这段文字加粗倾斜++

另外,附上各标签的方法的返回值综述:

 

六、标签中的子标记

一个标签中可以再包含其他的子标记,这种标签称为嵌套标记。创建嵌套标签时,标记处理类与普通标签相似,但在doStartTag()方法中必须返回EVAL_BODY_INCLUDE,JSP 容器才会处理嵌套的子标记。

         步骤一:编写顶级标记处理类

package tag;

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.tagext.BodyTagSupport;

public class NestTag extends BodyTagSupport{

    private String name = "";

    private String value = "";

    public void setName(String name) {

       this.name = name;

    }

    public void setValue(String value) {

       this.value = value;

    }

    public int doStartTag() throws JspException {

       String username = (String)pageContext.getSession().getAttribute(name);

       if(username.equals(value)){

           return EVAL_BODY_INCLUDE//自动将标签体包含到输出流(因为顶级标签的标签体是一子标签,还要进行该子标签的标签处理)

       }else{

           return SKIP_BODY//跳过标签体,不处理

       }

    }   

步骤二:在标记库描述符文件testbodytag.tld,添加tag标记:

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

<!DOCTYPE taglib

        PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"

        "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">    

<!--

解释:

    tld 文件中,映射了标记名和处理程序类;

    <tallib>元素,代表开始一个标记库的描述

    <tligversion>元素,代表标记库的版本

    <jspversion>元素,代表标记所支持的JSP 的版本

    <shortname>为标记库起别名,相当于注释,无实际用途

    <tag>元素,代表开始描述一个标记,其下子元素如下:

    <name>——为标记处理类起的标记名

    <tagclass>——指定标记处理类的全名(即带包的名字)

    <bodycontent>——标记体的类型,该示例中不需要标记体,所有设置为EMPTY,该值的其他取值在后续内容中讲解

    <tag>中的子元素

       <attribute>用于为标签声明属性,其子元素如下:

           <name>——用于指定属性名称

           <required>——用于声明该属性是否为必需的,本例中声明colorloop 两个属性都不是必需的。

 -->

<taglib>

    <tlibversion>1.0</tlibversion>

    <jspversion>1.1</jspversion>

    <shortname>test</shortname> <!-- 标签以<myhr:XXX />形式 -->

    <tag>

       <name>bodytag</name> <!-- 该标签为<myhr:MyHr /> -->

       <tagclass>tag.TestBodyTag</tagclass>

       <bodycontent>tagdependent</bodycontent>

       <attribute>

           <name>loop</name>

           <required>true</required>

       </attribute>

    </tag>

    <tag>

       <name>equal</name>

       <tagclass>tag.EqualTag</tagclass>

       <bodycontent>tagdependent</bodycontent>

       <attribute>

           <name>name</name>

           <required>true</required>

       </attribute>

       <attribute>

           <name>value</name>

           <required>true</required>

       </attribute>

    </tag>

    <tag>

       <name>nest</name>

       <tagclass>tag.NestTag</tagclass>

       <bodycontent>JSP</bodycontent>  <!-- 该声明标记体是其他标记,也可以是Jsp标准标记 -->

       <attribute>

           <name>name</name>

           <required>true</required>

       </attribute>

       <attribute>

           <name>value</name>

           <required>true</required>

       </attribute>

    </tag>

</taglib>

步骤三:在JSP 中使用该标记

<%@ page language="java"   pageEncoding="UTF-8"%>

<%@ taglib prefix="test" uri="/WEB-INF/test-tld/testbodytag.tld" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <title>测试嵌套的标签</title>

  </head>

  <body>

    <% session.setAttribute("username","tom"); %>     

    <test:nest name="username" value="tom">

        <test:bodytag loop="3">

           session中的用户名是tom<br/>

        </test:bodytag>

    </test:nest>

  </body>

</html>

运行界面如下:

 

©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值