分享

java自定义标签库的开发

 springcxc 2011-11-16

第14章 自定义标签库的开发 

14.1 自定义标签介绍
14.2 HelloWorld标签的开发
14.3 开发带Body的标签库
14.4
多个标签的嵌套
14.5 开发迭代的标签库
14.6 SimpleTag开发

14.1 标签语言的介绍 本章开头 下一节

JSP标签库(也称自定义库)可看成是一套产生基于XML脚本的方法,它经由JavaBeans来支持。在概念上说,标签库是非常简单和可以重用的代码构造。

 自定义标签有着丰富的特点,它们可以:

1.可以通过调用页面传递的属性进行自定义;
2.可以访问对于JSP页面可能的所有对象;
3.可以修改由调用页面产生的响应。
4.可以相互间通信。你可以创建并初始化一个JavaBean组件,创建一个变量引用标签中的bean,接着在其它的标签中引用该bean.
5.可以在一个标签中嵌套另一个,可以在JSP页面中进行复杂的交互。

 下面的代码声明在网页中使用新的标签,这个标签以hello为前缀,访问的路径为/demotag。

<%@ taglib uri="/demotag" prefix="hello" %>

  自定义标签为在JSP项目中创建易于重用的代码打开了一扇大门。你所需要的只是标签库和它的文档说明。

  通过实现接口或者继承现有的类,我们就可以开发自定义的标签。
常用的接口有:

TagSupport类

  该类是IterationTag的缺省实现。除了实现原有方法外,本身还增加了一些有用的其他方法和成员变量。下表列出其中重要的几个:

名称  描述 
重写的方法和他们的返回值   
void doStartTag()  继承自Tag。返回值SKIP_BODY。 
void doAfterBody()  继承自IterationTag。返回值SKIP_BODY。 
void doEndTag()  继承自Tag。返回值EVAL_PAGE。 
处理嵌套标签的有用的方法   
void setParent(Tag)  接受和维护一个父标签的引用。 
Tag getParent() 返回父标签的引用。 
Tag findAncestorWithClass(Tag,Class)  静态方法。寻找最近的指定类的标签。 
标签属性操作   
void setValue(String,Object)  设置属性。属性名是字符串,值可以是任何对象。 
Object getValue(String)  返回给定属性名的属性的值。 
Enumeration getValues()  返回一个所有值的枚举。 
void removeValue(String)  删除给定的属性。 
受保护的实例变量   
PageContext pageContext  一个保存着PageContext对象的变量。 
 
BodyTagSupport类

 该类同时继承了TagSupport类,并实现BodyTag接口。除了前表所示方法,该类还提供了一些其它方法便于使用。
 

名称  描述 
重写的方法和他们的返回值   
void doStartTag()  继承自Tag。返回值EVAL_BODY_BUFFERED。 
void doAfterBody()  继承自IterationTag。返回值SKIP_BODY。 
void doEndTag()  继承自Tag。返回值EVAL_PAGE。 
用以处理缓冲的方法   
void setBodyContent(BodyContent)  接受和维护一个BodyContent对象(缓冲对象)的引用。 
BodyContent getBodyContent()  返回BodyContent对象的引用。 
JspWriter getPreviousOut()  返回JspWriter对象,BodyContent就是对他的简单包裹。 

实现Tag接口

  所有的标签处理器都需要间接或直接的实现这个接口。

  下面列出Tag接口定义的方法和常量:

方法名  描述 
int doStartTag()   当碰到标签起始标记时执行。(<XXX:XXX>) 
int doEndTag()  当碰到标签结束标记时执行。(</XXX:XXX>) 
Tag getParent()  获得一个父标签对象 
void release()  从内存中释放该标签对象 
void setPageContext(PageContext)  设置当前页上下文(page context) 
void setParent(Tag)  对父标签对象进行设置 
 

 

常量  描述 
EVAL_BODY_INCLUDE  doStartTag()的返回值。指出jsp引擎计算标记体并输出
SKIP_BODY  doStartTag()的返回值。指出jsp引擎跳过标记体且不输出 
EVAL_PAGE  doEndTag()的返回值。指出jsp引擎计算页面剩余部分并输出 
SKIP_PAGE  doEndTag()的返回值。指出jsp引擎跳过页面剩余部分且不输出 

setPageContext()方法
setPageContext()方法是一个定制标签声明周期内第一个要被调用的方法。完整写法是:
public void setPageContext(PageContext);
jsp引擎会将jsp页转换时隐含创建的pageContext对象,作为参数,调用setPageContext方法。
通常的做法会将这个参数保存为本标记处理器的参数。

setParent()和getParent()方法
当标签嵌套使用时,外层的标签被成为父标签,内部的被称为子标签。完整的写法是:
public void setParent(Tag);
public Tag getParent();
其中setParent方法对父标签对象进行设置。而getParent方法用以获得父标签对象。

setter方法
当定制标签中包含属性时,在标签处理器中有和javaBean相同的设置机制。即每一个属性XXX,都有对应的setXXX()方法。
这些方法的调用是在setPageContext()和setParent()之后,doStartTag()之前。(就是说所有的属性-即实例变量-必须完全赋值,因为随后的方法可能会调用到它们)

doStartTag()方法
该方法标志着真正的标签处理开始。当前三阶段的方法执行完后,jsp引擎就会调用doStartTag()方法了。完整写法是:
public int doStartTag() throws JspException;
该方法给了标签处理器一个初始化计算和校验属性值合法性的机会。如果初始化失败或属性值不合法,则抛出JspException异常,或其子类,如JspTagException。
初始化计算过后,该方法将决定是否继续对标签体进行计算。作为结果,返回一个整数常量(EVAL_BODY_INCLUDE或SKIP_BODY),用以指示是否跳过标签体的执行。除此之外不返回任何其它值。

doEndTag()方法
执行完doStartTag()方法后,就该执行doEndTag()了。完整写法是:
public int doEndTag() throws JspException;
该方法标志着真正的标签处理结束。同样该方法将决定是否继续执行jsp文件中该标签之后的内容。它也会返回一个整数常量(EVAL_PAGE或SKIP_PAGE),用以指示页面后续内容是否跳过。注意此处的范围是页,并不是转换单位。所以计算不计算全都是针对该页而言。

release()方法
最后,jsp引擎将调用release方法,当标签处理结束,标签处理器对象不再使用时。完整写法是:
public void release();
注意。一个页面内同时有多个相同标签时,jsp引擎会只会为该标签创建一个对象。只有等该页内相同标签全部处理完了。jsp引擎才会调用release()方法,将该标签对象从内存清理掉。

  自定义标签的开发包括两个部分的开发:
(1)开发标签的处理程序(java类)
(2)标签描述文件(.tld文件)

  自定义标签的种类有许多,可以根据实际项目的需要进行编写。但为了不重复的开发,jsp标准推出JSTL(标准标签库)。

  在JSP应用程序中添加自定义标签的能力可以使工作重点放到以文档为中心的开发方式上。可以使 Java 代码不出现在 JSP 页中,从而使这些页面更容易维护。

  在创建自定义标签之前,需要创建一个 标签处理程序。标签处理程序是一个执行自定义标签操作的 Java 对象(Java类)。在使用自定义标签时,要导入一个 标签库 —— 即一组标签/标签处理程序对,这样页面编译时才能处理你的自定义标签。通过在 Web 部署描述符(web.xml)中声明库导入它,然后用指令taglib将它导入 JSP 页。

  如果JSP容器在编译JSP文件时遇到了自定义标签,那么它就检查 标签库描述符(tag library descriptor)(TLD) 文件以查询相应的标签处理程序。TLD 文件对于自定义标签处理程序,就像 Web 部署描述符对于 servlet 一样。

  对正文进行操作 —— 即对在开始和结束标签之间的内容进行操作的 —— 标签必须实现 BodyTag 接口。我们将称这些标签为正文标签。我们将不对其正文操作的标签称为简单标签。简单标签可以实现Tag接口,尽管不要求它们这样做。要记住不对其正文操作的标签仍然有正文,只不过,它的标签处理程序不能读取这个正文。
要构建简单标签,我们需要完成以下步骤:

1. 创建实现了Tag接口(准确地说是 javax.servlet.jsp.tagext.Tag)的标签处理程序类。
2. 创建一个 TLD 文件。
3. 在标签处理程序 Java 类中创建属性。
4. 在 TLD 文件中定义与标签处理程序 Java 类中定义的属性对应的属性。
5. 在 TLD 文件中声明 scriptlet 变量。
6. 实现 doStartTag() 方法。在标签处理程序类中,根据属性将值设置到 scriptlet 变量中。

  在jsp1.2时代已经有标记库了, 并且功能强大,但标记库的编程和调用都比较复杂,导致真正使用到WEB开发中的还是不多。JSP2.0推出的简单标记库扩展解决了以上的问题。简单标记库相对JSP1.2中的标记库来说,优点在于对后台程序员来说,结构更简单,实现接口更少,可以轻松实现后台程序。

  JSP 2.0中加入了新的创建自制标记的API:javax.servlet.jsp.tagext.SimpleTag,该API定义了用来实现简单标记的接口。和JSP 1.2中的已有接口不同的是,SimpleTag接口不使用doStartTag()和doEndTag()方法,而提供了一个简单的doTag()方法。这个方法在调用该标记时只被使用一次。而需要在一个自制标记中实现的所有逻辑过程、循环和对标记体的评估等都在这个方法中实现。从这个方面来讲,SimpleTag可以和IterationTag达到同等的作用。但SimpleTag的方法和处理周期要简单得多。在SimpleTag中还有用来设置JSP内容的setJspBody()和getJspBody()方法。Web容器会使用setJspBody()方法定义一个代表JSP内容的JspFragment对象。实现SimpleTag标记的程序可以在doTag方法中根据需要多次调用getJspBody().invoke()方法以处理JSP内容。

自定义标签的分类:
(1)不带主体和属性的简单标签:如< mytag:helloworld/>
(2)不带主体但有属性的标签:如<imytag:checkinput dbname = “<myBean.getDBName()>”/>
(3)带标签体和属性的标签:在自定义标签的起始和结束标签之间的部分为标签体(Body)。Body的内容可以是JSP中的标准标签,也可以是HTML、脚本语言或其他的自定义标签。
<mytag:checkinput dbname ="<myBean.getDBName()>">
  <mytag:log message="Table Name">
<mytag:checkinput />
(4使用脚本变量的标签:
定义了id和type属性的标签可以被标签后面的Scriptlet使用。
<mytag:connection id = "sqlDB" type ="DataSource" name ="SQL_Server">
<%sqlDB.getConnection(); %>
 

14.2 HelloWorld标签的开发 上一节 下一节 本章开头

  传统的标签必须实现javax.servlet.jsp.tagext.Tag接口,在Tag接口中,主要定义的是和标签生命周期相关的方法,比如:doStartTag(),doEndTag()等。在Tag中,可以通过PageContext对象来访问JSP页面的上下文。结合标签的生命周期标签的处理过程:

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

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

 3设置标签的属性,这个属性在标签库描述文件中定义,如果没有定义属性,就不用调用此类方法。

 4调用doStartTag方法,这个方法可以返回EVAL_BODY_INCLUDE和SKIP_BODY,当返回EVAL_BODY_INCLUDE时,就计算标签的Body,如果返回SKIP_BODY,就不计算标签的Body。

 5调用doEndTag方法,这个方法可以返回EVAL_PAGE或者SKIP_PAGE,当返回EVAL_PAGE时,容器将在标签结束时继续计算JSP页面其他的部分;如果返回SKIP_PAGE,容器将在标签结束时停止计算JSP页面其他的部分。

 6调用release方法释放标签程序占用的任何资源。

  开发标签时可以有两种选择,已从是实现原始的接口,另一种是从TagSupport类继承。

14.2.1 实现Tag接口

  按照下面的步骤进行:

 1)开发标签实现类

 2)编写标签描述文件,tld为扩展名。

 3)在Web.xml中映射标签库的使用。

 4)在JSP网页中调用标签。

14.2.1.1开发实现类

  教材例程14-1,HelloTag_Interface.java文件。

package com.jspdev.ch14;

 

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.*;

import java.util.Hashtable;

import java.io.Writer;

import java.io.IOException;

import java.util.Date;      

 

/**

 *演示怎么实现Tag接口的方式来开发标签程序

 */

public class HelloTag_Interface implements javax.servlet.jsp.tagext.Tag

{

     private PageContext pageContext;

     private Tag parent;

     public HelloTag_Interface()

     { 

       super();

     }

    

    /**

      *设置标签的页面的上下文

      */

     public void setPageContext(final javax.servlet.jsp.PageContext pageContext)

     {

           this.pageContext=pageContext; 

     }

    

    /**

      *设置上一级标签

      */

     public void setParent(final javax.servlet.jsp.tagext.Tag parent)

     {  

          this.parent=parent;  

     }

    

     /**

      *开始标签时的操作

      */

     public int doStartTag() throws javax.servlet.jsp.JspTagException 

     {  

          return SKIP_BODY;  //返回SKIP_BODY,表示不计算标签体

     }

    

     /**

      *结束标签时的操作

      */

     public int doEndTag() throws javax.servlet.jsp.JspTagException 

     {

           try

           {  

                pageContext.getOut().write("Hello World!你好,世界!");

           }                 

          catch(java.io.IOException e)

          {

               throw new JspTagException("IO Error: " + e.getMessage());

          } 

          return EVAL_PAGE;

      }

    

     /**

      *release用于释放标签程序占用的资源,比如使用了数据库,那么应该关闭这个连接。

      */

     public void release() {}   

   

   

     public javax.servlet.jsp.tagext.Tag getParent()  

     {   

        return parent;

     }

}

14.2.1.2编写标签库描述

教材例程14-2,mytag.tld文件。

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

 

<taglib xmlns="http://java./xml/ns/j2ee"

    xmlns:xsi="http://www./2001/XMLSchema-instance"

    xsi:schemaLocation="http://java./xml/ns/j2ee web-jsptaglibrary_2_0.xsd"

    version="2.0">

    <description>A tag library exercising SimpleTag handlers.</description>

    <tlib-version>1.0</tlib-version>

 

  <short-name>examples</short-name>

  <uri>/demotag</uri>

  <description>

    A simple tab library for the examples

  </description>

 

 <tag>

    <description>Outputs Hello, World,从实现Tag接口起开发</description>

        <name>hello_int</name>

    <tag-class>com.jspdev.ch14.HelloTag_Interface</tag-class>

    <body-content>empty</body-content>

 </tag>

 

</taglib>

14.2.1.3 在Web.xml中映射标签库的使用。

<web-app>

...

<taglib>
<taglib-uri>/demotag</taglib-uri>
<taglib-location>/WEB-INF/tlds/mytag.tld</taglib-location>
</taglib>

...
</web-app>

14.2.1.4 在JSP网页中调用标签

  教材例程14-4hellotag_interface.jsp文件。

<%@ taglib uri="/demotag" prefix="hello" %>
<%@ page contentType="text/html; charset=gb2312" language="java" %>
<html>
<head>
<title>first cumstomed tag</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>

<body>
<p>以下的内容从Taglib中显示:</p>
<p><i><hello:hello_int/></i></p>
</body>
</html>

  运行结果如下图所示。

14.2.2 从TagSupport继承

  只需要覆盖TagSupport类的doStartTag和doEndTag两个方法即可,开发比较容易。

教材例程14-5,HelloTag.java文件。

package com.jspdev.ch14;

 

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.*;

import java.util.Hashtable;

import java.io.Writer;

import java.io.IOException;

import java.util.Date;       

 

/**

 *演示从TagSupport继承来开发标签

 */

public class HelloTag extends TagSupport

{

    /**

     *覆盖doStartTag方法

     */

    public int doStartTag() throws JspTagException {

    return EVAL_BODY_INCLUDE;

    }

   

    /**

     *覆盖doEndTag方法

     */

    public int doEndTag()throws JspTagException

    {

        String dateString =new Date().toString();

        try

        {

            pageContext.getOut().write("Hello World hellking.<br>现在的时间是:"+dateString);

           

        }

        catch(IOException ex)

        {

            throw new JspTagException("Fatal error:hello tag conld not write to JSP out");

        }

        return EVAL_PAGE;

    }

}

教材例程14-6,mytag.tld文件,同上例,加一段映射即可。

...

 

  <tag>

    <name>hello</name>

    <tag-class>com.jspdev.ch14.HelloTag</tag-class>

    <body-content>empty</body-content>

    <description>

    Simple hello world examples.

    Takes no attribute,and simply generates HTML

    </description>

  </tag>

 

...

教材例程14-7,helloworld_tag.jsp文件。

<%@ taglib uri="/demotag" prefix="hello" %>
<%@ page contentType="text/html; charset=gb2312" language="java" %>
<html>
<head>
<title>first cumstomed tag</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>

<body>

<p>以下的内容从Taglib中显示:</p>
<p><i><hello:hello/></i></p>
</body>
</html>

运行结果如下图所示。

14.3 开发带Body的标签库 上一节 下一节 本章开头

  带有Body的Tag必须实现javax.servlet.jsp.tagext.BodyTag接口,BodyTag接口中定义了一些处理标签体的方法。

  通过实现BodyTag接口,就可以方便的操作标签体,比如可以让标签体迭代多次等。BodyTag的处理过程:

 1)当容器创建一个新的标签实例后,通过setPageContext来设置标签的页面上下文。
 2)使用setParent方法设置这个标签的上一级标签。
 3)设置标签的属性。
 4)调用doStartTag方法,这个方法可以返回EVAL_BODY_INCLUDE和SKIP_BODY,当返回EVAL_BODY_INCLUDE时,就计算标签的Body,如果返回SKIP_BODY,就不计算标签的Body。
 5)调用setBodyContent设置当前的BodyContent。
 6)调用doInitBody,如果在计算BodyContent时需要进行一些初始化,就在这个方法中进行。
 7)每次计算完BodyTag后调用doAfterBody,如果返回EVAL_BODY_TAG,表示继续计算一次BodyTag,直接返回SKIP_BODY才继续执行doEndTag方法。
 8)调用doEndTag方法,这个方法可以返回EVAL_PAGE或者SKIP_PAGE,当返回EVAL_PAGE时,容器将在标签结束时继续计算JSP页面其他的部分;如果返回SKIP_PAGE,容器将在标签结束时停止计算JSP页面其他的部分。
 9)调用release()方法释放标签程序占用的任何资源。

教材例程14-8,BodyTagExample.java文件。

package com.jspdev.ch14;

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.*;

import java.util.Hashtable;

import java.io.Writer;

import java.io.IOException;

 

public class BodyTagExample extends BodyTagSupport

{

       int counts;//counts为迭代的次数。

       public BodyTagExample()

       {

              super();

       }

      

       /**

        *设置counts属性。这个方法由容器自动调用。

        */

       public void setCounts(int c)

       {

              this.counts=c;

       }

      

       /**

        *覆盖doStartTag方法

        */

        public int doStartTag() throws JspTagException 

        {  

            System.out.println("doStartTag");

            if(counts>0)

            {

                return EVAL_BODY_TAG;

            }

            else

            {

                 return SKIP_BODY;

            }

    }

   

    /**

     *覆盖doAfterBody方法

     */

    public int doAfterBody() throws JspTagException

    {

        System.out.println("doAfterBody"+counts);

        if(counts>1)

        {

               counts--;

               return EVAL_BODY_TAG;

         } 

         else

         {

            return SKIP_BODY;

         }

    }

   

   /**

     *覆盖doEndTag方法

     */

    public int doEndTag() throws JspTagException

    {

         System.out.println("doEndTag");

        try

        { 

             if(bodyContent != null) 

             {

                  bodyContent.writeOut(bodyContent.getEnclosingWriter());

             }

        }

        catch(java.io.IOException e)

        {

               throw new JspTagException("IO Error: " + e.getMessage()); 

        }  

        return EVAL_PAGE; 

    }

   

     public void doInitBody() throws JspTagException{

      System.out.println("doInitBody");

     }

     public void setBodyContent(BodyContent bodyContent)

     {  

          System.out.println("setBodyContent");

          this.bodyContent=bodyContent;

     }

}

教材例程14-8,同mytag.tld文件,加上下述一段即可。

  <tag> 

        <name>loop</name>

       <tag-class>com.jspdev.ch14.BodyTagExample</tag-class>

       <body-content>jsp</body-content>

        <attribute>

             <name>counts</name>

             <required>true</required>

             <rtexprvalue>true</rtexprvalue>

      </attribute>

    </tag>

教材例程14-10,bodytag.jsp文件,调用上述标签。

<%@ taglib uri="/demotag" prefix="bodytag" %>
<html>
<head>
<title>body tag</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body>
<HR>
<bodytag:loop counts="5">
现在的时间是: <%=new java.util.Date()%><BR>
</bodytag:loop>
<HR>
</BODY>
</HTML>

运行结果如下图所示。

14.4 多个标签的嵌套 上一节 下一节 本章开头

  类似于循环的嵌套和开关语句,在实际开发中,往往需要多个标签嵌套在一起完成特定的任务。教材中例举的例子如下:

<mt:switch value="test">
  <mt:case value="test1">
    my value is test1
  </mt:case>
  <mt:case value="test">
    my value is test
  </mt:case>
</mt:switch>

  上面的标签中,<mt:switch>为父标签,<mt:case>为子标签,一个父标签可以嵌套多个子标签和HTML、Scriptlets等。

教材例程14-11,IfTag.java文件。

package com.jspdev.ch14;

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.*;

import java.util.Hashtable;

import java.io.Writer;

import java.io.IOException;

 

/**

 *if Tag

 *usage:<tag:if value=true>

 *      ...

 *      </tag:if>

 */

public class IfTag extends BodyTagSupport

{

       private boolean value;

       /**

        *设置属性的值。

        */

       public void setValue(boolean value)

       {

              this.value=value;

       }

      

       /**

        *doStartTag方法,如果valuetrue,那么

        *就计算tagbody的值,否则不计算body的值。

        */

       public int doStartTag() throws JspTagException

       {

              if(value)

        {

            System.out.println("value is true");

           return EVAL_BODY_INCLUDE;

         } 

         else

         {

           System.out.println("value is false");

            return SKIP_BODY;

         }

      }

        

    

    /**

     *覆盖doEndTag方法

     */

    public int doEndTag() throws JspTagException

    {

        try

        { 

             if(bodyContent != null) 

             {

                  bodyContent.writeOut(bodyContent.getEnclosingWriter());

             }

        }

        catch(java.io.IOException e)

        {

               throw new JspTagException("IO Error: " + e.getMessage()); 

        }  

        return EVAL_PAGE; 

    }

     

}

教材例程14-12,OutTag.java文件。IfTag中嵌套了一个子标签,子标签的Java文件为OutTag.java。

package com.jspdev.ch14;

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.*;

import java.util.Hashtable;

import java.io.Writer;

import java.io.IOException;

 

public class OutTag extends TagSupport

{

       private Object value;     

      

    /**

     *覆盖doStartTag方法

     */

   public void setValue(Object value)

   {

      this.value=value;

   }

  

    public int doStartTag() throws JspTagException {

       return EVAL_BODY_INCLUDE;

    }

   

    /**

     *覆盖doEndTag方法

     */

       public int doEndTag()throws JspTagException

       {

 

              try

              {

                     System.out.println(value);

                     pageContext.getOut().write(value.toString());

                    

              }

              catch(IOException ex)

              {

                     throw new JspTagException("Fatal error:hello tag conld not write to JSP out");

              }

              return EVAL_PAGE;

       }

     

}

教材例程14-13,同mytag.tld文件,加上下述一段即可。

   <tag>

        <name>if</name>

       <tag-class>com.jspdev.ch14.IfTag</tag-class>

       <body-content>jsp</body-content>

        <attribute>

             <name>value</name>

             <required>true</required>

             <rtexprvalue>true</rtexprvalue>

      </attribute>

   </tag>

   <tag>

        <name>out</name>

       <tag-class>com.jspdev.ch14.OutTag</tag-class>

       <body-content>jsp</body-content>

        <attribute>

             <name>value</name>

             <required>true</required>

             <rtexprvalue>true</rtexprvalue>

      </attribute>

   </tag>

教材例程14-14,cortag.jsp文件,调用上述标签。

<%@ taglib uri="/demotag" prefix="mt" %>
<html>
<head>
<title>vcorwork tag</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body>
<HR>
协作标签<br>
<%
boolean test=true;
String outValue="HelloWorld!";
%>
<mt:if value="<%=test%>">
<mt:out value="<%=outValue%>">
这是mt:out...>打印出的内容。
</mt:out>
</mt:if>
<HR>
<mt:if value="false">
<mt:out value="<%=outValue%>">
这些内容会显示在客户端。
</mt:out>
</mt:if>
<br>
</BODY>
</HTML>

  运行结果如下图:

14.5 开发迭代的标签库 上一节 下一节 本章开头

  在没有迭代标签的时候,要循环输出内容到网页,一般采用while语句进行循环,如:

 while(rst.next())
 {
    out.println("bookName:"+rst.getString("bookName"));
    out.println("<br>");
 }

  上述循环结构可以用迭代标签替代。

  如果要实现内容的迭代输出,需要开发两个类,一个类实现BodyTagSupport接口,另一个类扩展TagExtraInfo类。TagExtraInfo旨在提供标签运行时的信息。

教材例程14-15,IterateTag.java文件 ,实现BodyTagSupport类的接口

package com.jspdev.ch14;

import javax.servlet.jsp.*;

import javax.servlet.jsp.tagext.*;

import java.util.*;

 

public class IterateTag extends BodyTagSupport

{

       /**

        *Tag的属性

        */

       private String name;

       //it为要迭代的对象

       private Iterator it;

       //type表示it中对象的类型

       private String type;

 

       /**

        *设置属性collection

        */

       public void setCollection(Collection collection)

       {

              if(collection.size()>0)

              it=collection.iterator();

       }

       public void setName(String name)

       {

              this.name=name;

       }

       public void setType(String type)

       {

              this.type=type;

       }

       /**

        *如果it属性为null,那么忽略计算tagbody

        */

       public int doStartTag()throws JspTagException

       {

              if(it==null)

                     return SKIP_BODY;

              else

                     return continueNext(it);

       }

      

       public int doAfterBody()throws JspTagException

       {

              return continueNext(it);

       }

      

       public int doEndTag()throws JspTagException

       {

              try

              {

                     if(bodyContent!=null)

                     bodyContent.writeOut(bodyContent.getEnclosingWriter());

              }

              catch(java.io.IOException e)

              {

              }

             

              return EVAL_PAGE;

       }

       /**

        *保护方法,用于把it.next()设置为pagecontext的属性

        */

       protected int continueNext(Iterator it)throws JspTagException

       {

              if(it.hasNext())

              {

                     pageContext.setAttribute(name,it.next(),PageContext.PAGE_SCOPE);

                     return EVAL_BODY_TAG;

              }

              else

              {

                     return SKIP_BODY;

              }

       }

}

教材例程14-16,IterateTEI.java文件,为表示信息的标签类。

package com.jspdev.ch14;

import javax.servlet.jsp.tagext.*;

//TagExtraInfo用于提供一些在标签翻译时相关的信息。

public class IterateTEI extends TagExtraInfo

{

       public IterateTEI()

       {

              super();

       }

      

       public VariableInfo[] getVariableInfo(TagData data)

       {

              return new VariableInfo[]

              {

                     new VariableInfo(

                            data.getAttributeString("name"),

                            data.getAttributeString("type"),

                            true,

                            VariableInfo.NESTED

                     ),

              };

       }

}

  其中AT_BEGIN, NESTED, AT_END是标签扩展信息类(TEI)的VariableInfo中定义,如果设置为AT_BEGIN,变量在当前动作元素的开始标记之后就对调用者可见。如果此属性设置为AT_END,那么变量则在结束标记之后可见。NESTED 说明它仅在开始和结束标记之间可见。

教材例程14-17,同mytag.tld文件,加上下述一段即可。

   <tag>

      <name>iterate</name>

      <tag-class>com.jspdev.ch14.IterateTag</tag-class>

      <tei-class>com.jspdev.ch14.IterateTEI</tei-class>

      <body-content>jsp</body-content>

      <attribute>

             <name>collection</name>

             <required>true</required>

             <rtexprvalue>true</rtexprvalue>

      </attribute>

      <attribute>

             <name>name</name>

             <required>true</required>

      </attribute>

      <attribute>

             <name>type</name>

             <required>true</required>

      </attribute>

  </tag>

教材例程14-18,iterator.jsp文件,调用上述标签。

<%@ taglib uri="/demotag" prefix="mt"%>

<%

       com.jspdev.ch14.Company comp=new com.jspdev.ch14.Company();

       comp.setName("huayuan");

       com.jspdev.ch14.Contact contact1=new com.jspdev.ch14.Contact();

       contact1.setName("bar ,foo");

       contact1.setEmail("dd@tsinghua.eud.cn");

       contact1.setPhone("2975349875");

       contact1.setComment("java programe");

      

       com.jspdev.ch14.Contact contact2=new com.jspdev.ch14.Contact();

       contact2.setName("bar ,foo");

       contact2.setEmail("dd@tsinghua.eud.cn");

       contact2.setPhone("2975349875");

       contact2.setComment("java programe");

      

       com.jspdev.ch14.Contact contact3=new com.jspdev.ch14.Contact();

       contact3.setName("bar ,foodf");

       contact3.setEmail("dd@tsinghua.euddfdf.cn");

       contact3.setPhone("2975349875dd");

       contact3.setComment("java progrdfame");

      

       comp.addContact(contact1);

       comp.addContact(contact2); 

       comp.addContact(contact3);

       request.setAttribute("company",comp);

%>

<html>

<head>

<title>迭代标签演示</title>

</head>

<body>

<jsp:useBean id="company" scope="request" type="com.jspdev.ch14.Company"/>

 

<font size=+2>我的一些和<b>

<jsp:getProperty name="company" property="name"/>

公司联系</b>

</font>

<hr>

<table border=1>

<tr>

<td>姓名</td>

<td>电话</td>

<td>email</td>

<td>备注</td>

</tr>

<mt:iterate name="contact" collection="<%=company.getContacts()%>" type="com.jspdev.ch14.Contact">

<tr>

       <td>

       <jsp:getProperty name="contact" property="name"/>

       </td>

       <td>

       <jsp:getProperty name="contact" property="phone"/>

       </td>

       <td>

       <jsp:getProperty name="contact" property="email"/>

       <td>

       <jsp:getProperty name="contact" property="comment"/>

       </td>

</tr>

</mt:iterate>

</table>

<hr>

</body>

</html>

  运行结果如下图:

14.6 SimpleTag开发 上一节 本章开头

  SimpleTag有自己的生命周期,最主要就是doTag方法。

  1) 每次遇到标签,容器构造一个SimpleTag的实例,这个构造方法没有参数。和红典的标签一样,SimpleTag不能缓冲,故不能重用,每次都需要构造新的实例。
  2) setJspContext()、setParent(): 只有这个标签在另一个标签之内时,才调用setParent()方法;
  3) 设置属性:调用每个属性的setter方法;
  4) setJspBody();
  5) doTag(): 所有标签的逻辑、迭代和Body计算,都在这个方法中;
  6) return,当doTag方法返回时,所有的参数被锁定。
 

教材例程14-19,HelloWorldSimpleTag.java文件。

package com.jspdev.ch14;

 

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.tagext.SimpleTagSupport;

import java.io.IOException;

 

public class HelloWorldSimpleTag extends SimpleTagSupport {

   

    public void doTag() throws JspException, IOException {

       getJspContext().getOut().write( "<table border=1><tr bgcolor=9944cc><td>simpeltag测试</tr></td><tr tr=cc44cc><td>helloWorld!</td></tr></table>" );

    }

}

教材例程14-20,同mytag.tld文件,加上下述一段即可。

  <tag>

       <description>Outputs Hello, World</description>

        <name>helloWorld</name>

       <tag-class>com.jspdev.ch14.HelloWorldSimpleTag</tag-class>

       <body-content>empty</body-content>

  </tag>

教材例程14-21,simple_tag.jsp文件,调用上述标签。

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

<%@ taglib uri="/demotag" prefix="mt"%>

<html>

  <head>

    <title>JSP 2.0 Examples - 简单的标签</title>

  </head>

  <body>

    <h1>JSP 2.0 Examples - 简单的标签</h1>

    <hr>

    <p>这里是一个非常简单的标签.</p>

    <br>

    <b><u>Result:</u></b>

    <mt:helloWorld/>

  </body>

</html>

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多