:JSP自定义标签由浅到深详细讲解(全)

一、基本概念

1.标签(Tag):

  标签是一种XML元素,通过标签可以使JSP网页变得简洁并且易于维护,还可以方便地实现同一个JSP文件支持多种语言版本。由于标签是XML元素,所以它的名称和属性都是大小写敏感的

  2.标签库(Tag library):

  由一系列功能相似、逻辑上互相联系的标签构成的集合称为标签库。

  3.标签库描述文件(Tag Library Descriptor):

  标签库描述文件是一个XML文件,这个文件提供了标签库中类和JSP中对标签引用的映射关系。它是一个配置文件,和web.xml是类似的。

  4.标签处理类(Tag Handle Class):

  标签处理类是一个Java类,这个类继承了TagSupport或者扩展了SimpleTag接口,通过这个类可以实现自定义JSP标签的具体功能

  二、自定义JSP标签的格式:

  1.为了使到JSP容器能够使用标签库中的自定义行为,必须满足以下两个条件:

  1)从一个指定的标签库中识别出代表这种自定义行为的标签

  2)找到实现这些自定义行为的具体类

  第一个必需条件-找出一个自定义行为属于那个标签库-是由标签指令的前缀(Taglib Directive's Prefix)属性完成,所以在同一个页面中使用相同前缀的元素都属于这个标签库。每个标签库都定义了一个默认的前缀,用在标签库的文档中或者页面中插入自定义标签。所以,你可以使用除了诸如jsp,jspx,java,servlet,sun,sunw(它们都是在JSP白皮书中指定的保留字)之类的前缀。  

  uri属性满足了以上的第二个要求。为每个自定义行为找到对应的类。这个uri包含了一个字符串,容器用它来定位TLD文件。在TLD文件中可以找到标签库中所有标签处理类的名称

  2. 当web应用程序启动时,容器从WEB-INF文件夹的目录结构的META-INF搜索所有以.tld结尾的文件。也就是说它们会定位所有的TLD文件。对于每个TLD文件,容器会先获取标签库的URI,然后为每个TLD文件和对应的URI创建映射关系。

  在JSP页面中,我们仅需通过使用带有URI属性值的标签库指令来和具体的标签库匹配

  三、自定义JSP标签的处理过程:

  1.在JSP中引入标签库:  

  2.在JSP中使用标签库标签

  3.Web容器根据第二个步骤中的prefix,获得第一个步骤中声明的taglib的uri属性值

  4.Web容器根据uri属性在web.xml找到对应的元素 5.从元素中获得对应的元素的值 6.Web容器根据元素的值从WEB-INF/目录下找到对应的.tld文件 7.从.tld文件中找到与tagname对应的元素 8.凑元素中获得对应的元素的值 9.Web容器根据元素的值创建相应的tag handle class的实例 10. Web容器调用这个实例的doStartTag/doEndTag方法完成相应的处理

  四、创建和使用一个Tag Library的基本步骤:

  1.创建标签的处理类(Tag Handler Class)

  2.创建标签库描述文件(Tag Library Descrptor File)

  3.在web.xml文件中配置元素 4.在JSP文件中引人标签库

  五、TagSupport类简介:

  1.处理标签的类必须扩展javax.servlet.jsp.TagSupport.

  2.TagSupport类的主要属性:

  A.parent属性:代表嵌套了当前标签的上层标签的处理类

  B.pageContex属性:代表Web应用中的javax.servlet.jsp.PageContext对象

  3.JSP容器在调用doStartTag或者doEndTag方法前,会先调用setPageContext和setParent方法,设置pageContext和parent。因此在标签处理类中可以直接访问pageContext变量

  4.在TagSupport的构造方法中不能访问pageContext成员变量,因为此时JSP容器还没有调用

  setPageContext方法对pageContext进行初始化

  六、TagSupport处理标签的方法:

  1.TagSupport类提供了两个处理标签的方法:

       public int doStartTag() throws JspException

       public int doEndTag() throws JspException

  2.doStartTag:但JSP容器遇到自定义标签的起始标志,就会调用doStartTag()方法。

     doStartTag()方法返回一个整数值,用来决定程序的后续流程。

  A.Tag.SKIP_BODY:表示?>…之间的内容被忽略

  B.Tag.EVAL_BODY_INCLUDE:表示标签之间的内容被正常执行

  3.doEndTag:但JSP容器遇到自定义标签的结束标志,就会调用doEndTag()方法。doEndTag()方法也返回一个整数值,用来决定程序后续流程。

  A.Tag.SKIP_PAGE:表示立刻停止执行网页,网页上未处理的静态内容和JSP程序均被忽略任何已有的输出内容立刻返回到客户的浏览器上。

  B.Tag_EVAL_PAGE:表示按照正常的流程继续执行JSP网页

  七、用户自定义的标签属性:

  如果在标签中还包含了自定义的属性,那么在标签处理类中应该将这个属性作为成员变量,并且分别提供设置和读取属性的方法。

  八、创建标签处理类的步骤:

  1.创建包含JSP网页静态文本的文件(即是要替换自定义JSP标签的文本)

  2.在Web应用启动时装载静态文本

  3.创建标签处理类

  九、如何创建包含JSP网页静态文本的文件:

  1.使用java.util.Properties类来存放要替换网页中自定义JSP标签的静态文本

  2.Properties类代表了一系列属性的集合,其实例既可以被保存到流中,也可以从流中加载。这些文本以key/value的形式存放在WEB-INF目录下,例如key=value,在属性列表中这些key/value都是String类型的

  十、Properties类的常用API:

  1.setProperty(String key, String value):调用Hashtable类的put方法添加属性

  2.getProperty(String key):获取属性列表中key对应的属性值

  3.load(InputStream in):从输入流对象InputStream中读取属性列表(Properties list)

  4.store(OutputStream out,String coMMent):使用适当的格式将属性列表的属性对写入输出流对象中,默认使用ISO-88590-1编码格式,以行的方式处理输入。属性的key/value之间以”=、:”配对,以回车、换行分隔key/value配对

十一、ServletContext类的常用API

1、getContext(String uripath):返回服务器中uripath所代表的ServletContext对象;

2、getInitParameter(String name):返回ServletConfig对象中name参数的值;

3、getMineType(String file):返回file参数代表的文件的MIME类型;

4、getRequestDispatcher(String path):返回path代表的RequestDispacher对象;

5、getResourceAsStream(String path):以输入流的形式返回path对应的资源,在输入留中对象可以为任意形式的数据,path参数必须以“/”开始且相对于Context Root。

十二、如何使用ServletContxt读取并保存属性文件

1、创建java.util.Properties类对象;

2、获取ServletContext对象;

3、将属性文件以输入流的形式读入到某个输入流对象中;

4、将输入流对象加载到Properties对象中;

5、将Properties对象保存到ServletContext对象中。

十三、如何在Web应用启动时装载静态文本

1、创建继承了HttpServlet类的子类,在web.xml中配置这Servlet时设置load-on-startup属性:

someclass
somepackage.SomeClass1

2、在这个Servlet的init()方法中创建java.util.Properties类

3、获取当前Web应用的ServletContext对象

4、将WEB-INF目录下的属性文件读入到输入流InputStream中:

 

InputStream in = context.getResourceAsString("WEB-INF/someproperties.properties");

5、将输入流加载到属性对象中

ps.load(in);

6、将属性对象保存到上

 

context.setAttribute("attributeName",ps);

十四、如何创建标签处理类

1、引入必需的资源

 

import javax.servlet.jsp.*; import javax.servlet.http.*; import java.util.*; import java.io.*;

2、继承TagSupport类并覆盖doStartTag()/doEndTag()方法

3、从ServletContext对象中获取java.util.Properties对象

4、从Properties对象中获取key对应的属性值

5、对获取的属性进行相应的处理并输出结果

十五、创建标签库描述文件(Tag Library Descriptor)

1、标签库描述文件,简称TLD,采用XML文件格式,定义了用户的标签库。TLD文件中的元素可以分成3类:

A.标签库元素
B.标签元素
C.标签属性元素

2、标签库元素用来设定标签库的相关信息,它的常用属性有:

A.shortname:指定Tag Library默认的前缀名(prefix);

B.uri:设定Tag Library的惟一访问表示符。

3、标签元素用来定义一个标签,它的常见属性有:

A.name:设定Tag的名字;

B.tagclass:设定Tag的处理类;

C.bodycontent:设定标签的主体(body)内容。

1)empty:表示标签中没有body;
2)JSP:表示标签的body中可以加入JSP程序代码;
3)tagdependent:表示标签中的内容由标签自己去处理。

4、标签属性元素用来定义标签的属性,它的常见属性有:

A.name:属性名称;
B.required:属性是否必需的,默认为false;
C.rtexprvalue:属性值是否可以为request-time表达式,也就是类似于< %=…% >的表达式。

十六、在Web应用中使用标签

1、如果Web应用中用到了自定义JSP标签,则必须在web.xml文件中加入元素,它用于声明所引用的标签所在的标签库

/sometaglib
/WEB-INF/someTLD.tld

2、设定Tag Library的惟一标示符,在Web应用中将根据它来引用Tag Libray;

3、指定和Tag Library对应的TLD文件的位置;

4、在JSP文件中需要加入<!-- taglib% >指令来声明对标签库的引用。例如: </p> <p><TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=2 width=400 align=center borderColorLight=black border=1> <TBODY> <TR> <TD class=code bgColor=#e6e6e6><PRE><% @ taglib prefix = &ldquo;somePrefix&rdquo; uri = "/someuri"-->

 

 

5、prefix表示在JSP网页中引用这个标签库的标签时的前缀,uri用来指定Tag Library的标识符,它必须和web.xml中的属性保持一致。

 

----------------------------------------------------end-------------------------------

 

JSP自定义标签开发入门实例

 

1.引言
本文将介绍JSP标签的一些基本概念以及如何开发及使用自定义标签。带领大家迈上Java Web开发的又一新台阶.

2.什么是自定义标签
2.1.用户自定义的Java语言元素,实质是运行一个或者两个接口的JavaBean.
2.2.可以非常紧密的和JSP的表示逻辑联系在一起,又具有和普通JavaBean相同的业务逻辑处理能力.
2.3.当一个JSP页面转变为servlet时,其间的用户自定义标签转化为操作一个称为标签hander的对象.
2.4.可操默认对象,处理表单数据,访问数据库以及其他企业级服务.

3.自定义标签的特点
3.1.通过调用页面实现传递定制.
3.2.访问所有对JSP页面可能的对象.
3.3.修改调用页面生成的响应.
3.4.自定义标签之间可以互相通信.
3.5.在同一个JSP页面中对标签嵌套可以实现复杂交互.

4.例子:开发一个简单的JSP标签完整案例
4.1.创建标签描述符文件
在WEB-INF文件下创建*.tld标签描述符文件:如
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>eRedLab JSPTag Library</shortname>
<uri>/testTag</uri>
<info>自定义标签测试</info>
<tag>
      <name>hello</name>
      <tagclass>com.eredlab.taglib.test.TestTld</tagclass>
      <bodycontent>empty</bodycontent>
      <info>自定义标签测试</info>
      <attribute>
       <name>begin</name>
       <required>true</required>
      </attribute>
      <attribute>
       <name>end</name>
       <required>true</required>
      </attribute>
</tag>
</taglib>

4.2.创建标签处理器
/**
* @desc 自定义标签测试类 实现一个简单的Hello World标签
* @author      熊春
* @version eRedLab 2007-9-10
*/
public class TestTld extends TagSupport{
//标签属性begin
private String begin = null;
//标签属性end
private String end = null;
//构造函数
public TestTld(){
  
}

/* 标签初始方法 */
public int doStartTag() throws JspTagException{
      return super.EVAL_BODY_INCLUDE;
}

/* 标签结束方法 */
public int doEndTag() throws JspTagException{
      JspWriter out = pageContext.getOut();
      String sum = begin + end;
      try{
       //标签的返回值
       out.println(sum);
      }catch(IOException e){
       e.printStackTrace();
      }
      return super.SKIP_BODY;
}

/* 释放资源 */
public void release(){
      super.release();
}
/********************************************
            属性get()、set()方法
      *******************************************/
}

5.使用自定义JSP标签
5.1.在Web.XML中加载标签描述符文件.
<!-- 加载标签描述符文件 -->
<taglib>
        <taglib-uri>/WEB-INF/test.tld</taglib-uri>
        <taglib-location>/WEB-INF/test.tld</taglib-location>
</taglib>
5.2.在JSP中使用此标签
<%@ taglib uri="/testTag" prefix="mytag"%>
<mytag:hello end="熊春!" begin="自定义标签输出流:Hello,"/>
<mytag:hello end="World!" begin="Hi,"/>
WEB页面输出结果如下:
自定义标签输出流:Hello,熊春! Hi,World!
附图1:JSP页面编写及代码辅助


附图2.Web页面输出效果


 ------------------------------------------------end-------------------------------------------------------------------

 

jsp自定义标签(taglib)编写的原理和实现
 

 

一个tag就是一个普通的java类,它惟一特别之处是它必须继承TagSupport或者 BodyTagSupport类。这两个类提供了一些方法,负责jsp页面和你编写的类之间的交互,例如输入,输出。而这两个类是由jsp容器提供的,无 须开发人员自己实现。换句话说,你只需把实现了业务逻辑的类继承TagSupport或者BodyTagSupport,再做一些特别的工作,你的类就是 一个Tag。并且它自己负责和jsp 页面的交互,不用你多操心。

“特别的工作”通常有以下几个步骤:

[1]提供属性的set方法,此后这个属性就可以在jsp页面设置。以jstl标签为例 c:out value=""/,这个value就是jsp数据到tag之间的入口。所以tag里面必须有一个setValue方法,具体的属性可以不叫value。 例如setValue(String data){this.data = data;}
这个“value”的名称是在tld里以attribute元素存在的。
取什么名字都可以,只需tag里提供相应的set方法即可。

[2]处理 doStartTag 或 doEndTag 。这两个方法是 TagSupport提供的。 还是以c:out value=""/为例,当jsp解析这个标签的时候,在“<”处触发 doStartTag 事件,在“>”时触发 doEndTag 事件。通常在 doStartTag 里进行初始化,流程选择操作,在 doEndTag 里后续页面输出控制。
[3]编写tld文件,就是把编写的tag组件的信息以xml形式告诉容器,它才好进一定步骤解释tag组件
[4]在jsp页面导入tld。这样,你的jsp页面就可以使用自己的tag组件了。

通常你会发现自己绝大多数活动都集中在 doStartTag 或 doEndTag方法里,如果在服务器端处理标签中的正文或则是嵌套标签时的话,还是过问一下doAfterBody。
一个简单的例子:OutputTag
Java代码
  1. package test;   
  2. import javax.servlet.jsp.JspException;   
  3. import javax.servlet.jsp.JspWriter;   
  4. import javax.servlet.jsp.tagext.TagSupport;   
  5.   
  6. publicclass OutputTag extends TagSupport {   
  7. private String name=null;   
  8. publicvoid setName(String name) {   
  9. this.name = name;   
  10. }   
  11. publicint doEndTag() throws JspException   
  12. {   
  13. try {   
  14. JspWriter out = pageContext.getOut();   
  15. out.print("Hello! " + name);   
  16.   } catch (Exception e) { thrownew JspException(e); }   
  17. return EVAL_PAGE;   
  18. }   
  19. }   
Java代码
  1. package test;  import javax.servlet.jsp.JspException;  import javax.servlet.jsp.JspWriter;  import javax.servlet.jsp.tagext.TagSupport;   public class OutputTag extends TagSupport {  private String name=null;  public void setName(String name) {  this.name = name;  }  public int doEndTag() throws JspException  {  try {  JspWriter out = pageContext.getOut();  out.print("Hello! " + name);    } catch (Exception e) { throw new JspException(e); }  return EVAL_PAGE;  }  }  


简要说明:
1 如何输出到jsp页面:调用JspWriter JspWriter out = pageContext.getOut();out.print......记住这个方法就可以了。
2 输出后如何作处理,函数会返回几个值之一。EVAL_PAGE 表示tag已处理完毕,返回jsp页面。还有几个值,例如 EVAL_BODY_AGAIN 和EVAL_BODY_INCLUDE等 跟流程控制有关.

编写tld
Java代码
  1. <?xml version="1.0" encoding="ISO-8859-1" ?>   
  2. <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN""http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">   
  3. <taglib>   
  4. <tlib-version>1.0</tlib-version>   
  5. <jsp-version>1.2</jsp-version>   
  6. <short-name>test</short-name>   
  7. <!--OutputTag-->   
  8. <tag>   
  9. <name>out</name>   
  10. <tag-class>test.OutputTag</tag-class>   
  11. <body-content>empty</body-content>   
  12. <attribute>   
  13. <name>name</name>   
  14. <required>false</required>   
  15. <rtexprvalue>false</rtexprvalue>   
  16. </attribute>   
  17. </tag>   
  18. </taglib>   
Java代码
  1. <?xml version="1.0" encoding="ISO-8859-1" ?>  <!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>test</short-name>  <!--OutputTag-->  <tag>  <name>out</name>  <tag-class>test.OutputTag</tag-class>  <body-content>empty</body-content>  <attribute>  <name>name</name>  <required>false</required>  <rtexprvalue>false</rtexprvalue>  </attribute>  </tag>  </taglib>  



在WEB-INF下新建tlds文件夹,把这个文件取名为test.tld,放到tlds文件夹下。引用时的路径应该这样:WEB-INF\tlds\test.tld

关于tld的简单说明:
short-name:taglib的名称,也称为前缀。比如“c:out value=""/” 里的“c”
name:tag的名字。例如“c:out value=""/” 里的"out”,我们的类也取名为out,由于有前缀作区分,不会同其他库的同名tag组件混淆
tag-class:完整的tag组件路径,记着带包名
body-content:指tag之间的内容。例如c:out value="" ...... /c 起始和关闭标签之间就是body-content。由于没有处理body-content ,所以上面设为empty,如果是嵌套标签,或则是要在服务器端处理标签体的话,就是jsp了
“attribute”里的name:属性名字。例如c:out value=""/里的value。名字可任意取,只要类里提供相应的set方法即可。
required:是否必填属性。
rtexprvalue:是否支持运行时表达式取值就是是否可以<%=%>或则是${}方式传值。
这是tag的强大功能。
编写jsp页面

Java代码
  1. <%@ page language="java"%>   
  2. <%@ taglib uri="/WEB-INF/tlds/test.tld" prefix="test"%>   
  3. <html>   
  4. <body>   
  5. Test Tag: <test:out name="TEST"/>   
  6. </body>   
  7. </html>   
Java代码
  1. <%@ page language="java"%>  <%@ taglib uri="/WEB-INF/tlds/test.tld" prefix="test"%>  <html>  <body>  Test Tag: <test:out name="TEST"/>  </body>  </html>  



启动服务器,如果一切按照上面步骤的话,就能看到 Test Tag: Hello! TEST 字样。最简单的tag就这么出来了。并不难,是不是?
------------------------------------------------------------------
Tag系列的Interface里定义的静态int,通过他们也能一窥tag组键的执行流程,这几个静态值分别是:
SKIP_BODY : 跳过了开始和结束标签之间的代码,一般是在doStartTag中使用
EVAL_BODY_INCLUDE :处理嵌套的标签,一般是在doStartTag中使用,由负责处理标签正文的tag接口提供
EVAL_BODY_BUFFERED :对包含的内容进行解析 一般是在doStartTag中使用,由负责处理标签正文的bodyTag接口提供,目的是通知jsp容器作好读取正文的工作(创建一个body- content包装正文和获取存放操作结果的out对象,便于以后的操作和输出).
EVAL_BODY_AGAIN:处理标签正文,嵌套标签的iteratorTag接口的使用
SKIP_PAGE : 忽略剩下的页面,一般是在doEndTag中使用
EVAL_PAGE : 继续执行下面的页, 一般是在doEndTag中使用

 

 --------------------------------------------end-----------------------------------------------

 

<!--正文-->

<!--判断阅读权限--><!--判断是否已经扣点-->

 一、JSP自定义标签简介

  标签是一种XML元素,通过标签可以使JSP网页变得简洁并且易于维护,还可以方便地实现同一个JSP文件支持多种语言版本。由于标签是XML元素,所以它的名称和属性都是大小写敏感的

  标准JSP标签是用来调用JavaBean组件的操作,处理定向请求以简化JSP页面开发与维护。JSP技术提供了一种封装其它动态类型的机制——自定义标签,它扩展了JSP语言。自定义标签通常发布在标签库中,该库定义了一个自定义标签集并包含实现标签的对象。

  自定义标签是用户定义的JSP语言元素。当JSP页面包含一个自定义标签时被转化为servlet,标签转化为对称为tag handler的对象的操作。接着当servlet执行时Web container调用那些操作。

  二、两种标签

  可以定义两种类型的标签:

javax.servlet.jsp.tagext.Tag
javax.servlet.jsp.tagext.BodyTag

  有标签体的标签必须实现 BodyTag 接口。

<jsptag:map scope=“session” name=“tagMap”>
body
</jsptag:map>

  也可能没有标签体:

<jsptag:map/>

  无标签体的简单标签可以实现 Tag 接口。

  三、标签处理程序

  int doStartTag() throws JspException---处理开始标签

  int doEndTag() throws JspException---处理结束标签

  Tag getParent()/void setParent(Tag t)---获得/设置标签的父标签

  void setPageContext(PageContext pc)--- pageContext 属性的 setter 方法

  void release() 释放获得的所有资源

 doStartTag()和doEndTag()方法的返回值说明:

  SKIP_BODY      表示不用处理标签体,直接调用doEndTag()方法。

  SKIP_PAGE      忽略标签后面的jsp(SUN企业级应用的首选)内容。

  EVAL_PAGE      处理标签后,继续处理jsp(SUN企业级应用的首选)后面的内容。

  EVAL_BODY_BUFFERED 表示需要处理标签体,且需要重新创建一个缓冲(调用setBodyContent方法)。

  EVAL_BODY_INCLUDE  表示在现有的输出流对象中处理标签体,但绕过setBodyContent()和doInitBody()方法

  EVAL_BODY_AGAIN     对标签体循环处理。(存在于javax.servlet.jsp.tagext.IterationTag接口中)

  实现javax.servlet.jsp.tagext.Tag接口

  扩展javax.servlet.jsp.tagext.TagSupport类

  TagSupport 类定义了 get/setParent() 和 setPageContext(),这与所有标签处理程序几乎相同。

  get/setParent() 方法允许标签嵌套。

  TagSupport 类还定义了一个可以被子类使用的 pageContext 实例变量 (protected PageContext pageContext),这个变量是由 setPageContext() 方法设置的。

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

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

  在运行时,JSP 页生成的 servlet 得到对应于这一页面所使用的标签的标签处理程序的一个实例。生成的 servlet 用传递给它的属性初始化标签处理程序。

  标签处理程序实现了 生存周期 方法。生成的 servlet 用这些方法通知标签处理程序应当启动、停止或者重复自定义标签操作。生成的 servlet 调用这些生存周期方法执行标签的功能。

  四、TLD 文件

  TLD 文件的根元素是 taglib。taglib 描述了一个 标签库 —— 即一组标签/标签处理程序对。

  因为我们使用的是 JSP 版本 1.2,所以在这个例子中需要 tlib-version 和 short-name 元素。

  tlib-version 元素对应于标签库版本。

  jsp-version 对应于标签库所依赖的 JSP 技术的版本。

  short-name 元素定义了 IDE 和其他开发工具可以使用的标签库的简单名。

  taglib 元素包含许多 tag 元素,标签库中每一个标签有一个 tag 元素。

  在JSP中导入TLD文件:

<%@ taglib uri="firstTag" prefix="my"%>

  五、编写自定义迭代标签和el表达式调用类的静态方法实例

  循环标签体类:ForEach.java

 1import java.util.Collection;
 2import java.util.Iterator;
 3
 4import javax.servlet.jsp.JspException;
 5import javax.servlet.jsp.tagext.BodyContent;
 6import javax.servlet.jsp.tagext.BodyTagSupport;
 7
 8public class ForEach  extends BodyTagSupport
 9{
10  private String id;
11  private String collection;
12  private Iterator iter;
13 
14  public void setCollection(String collection)
15  {
16    this.collection = collection;
17  }
18  public void setId(String id)
19  {
20    this.id = id;
21  }
22 
23  //遇到开始标签执行
24  public int doStartTag() throws JspException
25  {
26    Collection coll = (Collection) pageContext.findAttribute(collection);
27    // 表示如果未找到指定集合,则不用处理标签体,直接调用doEndTag()方法。
28    if(coll==null||coll.isEmpty()) return SKIP_BODY;
29   
30    iter = coll.iterator();
31    pageContext.setAttribute(id, iter.next());
32    // 表示在现有的输出流对象中处理标签体,但绕过setBodyContent()和doInitBody()方法
33    // 这里一定要返回EVAL_BODY_INCLUDE,否则标签体的内容不会在网页上输出显示
34    return EVAL_BODY_INCLUDE;
35  }
36 
37  //在doInitBody方法之前执行,在这里被绕过不执行
38  @Override
39  public void setBodyContent(BodyContent arg0)
40  {
41    System.out.println("setBodyContent");
42    super.setBodyContent(arg0);
43  }
44  //此方法被绕过不会被执行
45  @Override
46  public void doInitBody() throws JspException
47  {
48    System.out.println("doInitBody");
49    super.doInitBody();
50  }
51 
52  //遇到标签体执行
53  public int doAfterBody() throws JspException
54  {
55    if(iter.hasNext())
56    {
57      pageContext.setAttribute(id, iter.next());
58      return EVAL_BODY_AGAIN;// 如果集合中还有对像,则循环执行标签体
59    }
60    return SKIP_BODY;//迭代完集合后,跳过标签体,调用doEndTag()方法。
61  }
62 
63  //遇到结束标签执行
64  public int doEndTag() throws JspException
65  {
66    System.out.println("doEndTag");
67    return EVAL_PAGE;
68  }
69
70}

 获取VO属性类:GetProperty.java

 1import java.lang.reflect.Method;
 2
 3import javax.servlet.jsp.JspException;
 4import javax.servlet.jsp.tagext.BodyTagSupport;
 5
 6public class GetProperty extends BodyTagSupport
 7{
 8
 9  private String name;
10  private String property;
11
12  public void setName(String name)
13  {
14    this.name = name;
15  }
16
17  public void setProperty(String property)
18  {
19    this.property = property;
20  }
21
22  @SuppressWarnings("unchecked")
23  public int doStartTag() throws JspException
24  {
25    try
26    {
27      Object obj = pageContext.findAttribute(name);
28     
29      if (obj == null) return SKIP_BODY;
30     
31      Class c = obj.getClass();
32      //构造GET方法名字 get+属性名(属性名第一个字母大写)
33      String getMethodName = "get" + property.substring(0, 1).toUpperCase()
34                              + property.substring(1, property.length());
35      Method getMethod = c.getMethod(getMethodName, new Class[]{});
36     
37      pageContext.getOut().print(getMethod.invoke(obj));
38      System.out.print(property + ":" + getMethod.invoke(obj) + "t");
39    } catch (Exception e)
40    {
41      e.printStackTrace();
42    }
43    return SKIP_BODY;
44  }
45
46  public int doEndTag() throws JspException
47  {
48    return EVAL_PAGE;
49  }
50}
51
52表达式直接访问此类中静态的方法:ELFunction.java
53public class ELFunction
54{
55 public static int add( int i,int j )
56 {
57  return i+j;
58 }
59}

  写一个测试用的VO类:UserVo.java

 1public class UserVo
 2{
 3  private String name;
 4  private String password;
 5 
 6  public String getName()
 7  {
 8    return name;
 9  }
10  public void setName(String name)
11  {
12    this.name = name;
13  }
14  public String getPassword()
15  {
16    return password;
17  }
18  public void setPassword(String password)
19  {
20    this.password = password;
21  }
22}

  建好TLD文件tag.tld,放在WEB-INF目录下

 1<?xml version="1.0" encoding="utf-8"?>
 2<taglib version="2.0"
 3 xmlns="http://java.sun.com/xml/ns/j2ee"
 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5 xmlns:shcemalocation="http://java.sun.com/xml/ns/j2ee
 6 http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 7
 8 <description>自定义标签</description>
 9 <display-name>JSTL core</display-name>
10 <tlib-version>1.1</tlib-version>
11 <short-name>firstLabel</short-name>
12 <uri>http://java.sun.com/jsp/jstl/core</uri>
13
14 <!-- 创建自定义 迭代标签 -->
15 <tag>
16  <name>forEach</name>
17  <tag-class>exercise.taglib.ForEach</tag-class>
18  <!-- 如果没有标签体,设置empty , 如果有标签休必须设置JSP-->
19  <body-content>JSP</body-content>
20  <attribute>
21   <name>id</name>
22   <required>true</required><!-- 标识属性是否是必须的 -->
23   <rtexprvalue>true</rtexprvalue><!-- 标识属性值是否可以用表达式语言 -->
24  </attribute>
25  <attribute>
26   <name>collection</name>
27   <required>true</required>
28   <rtexprvalue>true</rtexprvalue>
29  </attribute>
30 </tag>
31
32 <!-- 创建自定义获得属性标签 -->
33 <tag>
34  <name>getProperty</name>
35  <tag-class>exercise.taglib.GetProperty</tag-class>
36  <body-content>empty</body-content>
37  <attribute>
38   <name>name</name>
39   <required>true</required>
40   <rtexprvalue>true</rtexprvalue>
41  </attribute>
42  <attribute>
43   <name>property</name>
44   <required>true</required>
45   <rtexprvalue>true</rtexprvalue>
46  </attribute>
47 </tag>
48
49 <!-- 配置一个表达式调用 的函数 -->
50    <function>
51     <name>add</name><!-- 配置一个标签,在JSP页面通过引用前缀调用 -->
52     <function-class>exercise.taglib.ELFunction</function-class><!-- 实现类 -->
53     <function-signature>int add(int,int)</function-signature><!-- 静态的方法:包括返回类型,方法名,入参的类型 -->
54    </function>
55</taglib>

 

J2EE复习(六)JSP自定义标签

<!--基本属性-->

 一、JSP自定义标签简介

<!--正文-->

<!--判断阅读权限--><!--判断是否已经扣点-->

  在web.xml文件中配置自定义标签

1<jsp-config>
2 <taglib>
3  <taglib-uri>firstTag</taglib-uri>
4  <taglib-location>/WEB-INF/tag.tld</taglib-location>
5 </taglib>
6</jsp-config>

  在jsp文件中使用标签:tag.jsp

 1<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
 2<%@ taglib uri="firstTag" prefix="my"%>
 3
 4<jsp:useBean id="userVo1" class="exercise.vo.UserVo" scope="request">
 5  <jsp:setProperty name="userVo1" property="name" value="Hackiller"/>
 6  <jsp:setProperty name="userVo1" property="password" value="123"/>
 7</jsp:useBean>
 8
 9<jsp:useBean id="userVo2" class="exercise.vo.UserVo" scope="request">
10  <jsp:setProperty name="userVo2" property="name" value="YangYang"/>
11  <jsp:setProperty name="userVo2" property="password" value="456"/>
12</jsp:useBean>
13
14<%
15 List list = new ArrayList();
16 list.add(userVo1);
17 list.add(userVo2);
18 pageContext.setAttribute("voList",list);
19%>
20
21<html>
22  <head>
23    <title>My JSP 'tag.jsp' starting page</title>
24  </head>
25 
26  <body>
27    <h2 align="center">This is my JSP page:测试taglib.</h2>
28    <hr>
29   
30   <h2>自定义迭代标签:</h2>
31    <table>
32     <tr><td>姓名</td><td>密码</td></tr>
33     <my:forEach collection="voList" id="uservo">
34      <tr>
35       <td><my:getProperty name="uservo" property="name"/></td>
36       <td><my:getProperty name="uservo" property="password"/></td>
37      </tr>
38     </my:forEach>
39    </table>
40    <hr>
41   
42    <h2>表达式调用类的静态方法:</h2>
43    2+5=${my:add(2,5)}
44  </body>
45</html>

--------------------------------------------------------------end----------------------

JSP自定义标签

今天要实现的功能是useBean标签。下表是它的一些属性和用途。(我只选了个比较重要的属性,并没有实现所有属性)

 

属性 用途
id 给将要应用bean的变量一个名字,如果发现有相同id和scope的bean对象,则应用此对象而不会产生一个新的例示。
class 指明了bean的整个包名。
scope 表明了此bean的作用范围,共有四个值:page, request, session, 和 application,缺省的是page属性,表明此bean只能应用于当前页(保存在当前页的PageContext 中);request属性表明此bean只能应用于当前的用户请求中(保存在ServletRequest对象中);session属性表明此bean能应用于当前HttpSession生命周期内的所有页面;application属性值则表明此bean能应用于共享ServletContext的所有页面。需要注意的是,当没有具有相同的id和scope对象时,一个jsp:useBean 实体只能作用于一个新的例示中,反之,则作用于以前的对象,这时,在jsp:useBean标签之间的任何jsp:setParameter和其它实体都将被忽略。
type 说明将要索引对象的变量类型,它必须与类名及父类名相匹配。记住,这个变量的名字是由id属性值代替的。
beanName 给定此bean的名字,可以将其提供给bean的例示方法,只提供beanName和type而忽略class属性的情况是允许的。
下面是标签处理方法类:UseBean.java:
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.lang.reflect.*;
//
public class UseBean extends TagSupport{ //继承自TagSupport类
      private String scope;
       private String type;
       public UseBean(){super();}
       /**
        *设置属性存取方法,这个方法由容器自动调用。setId()和getId()由系统自动实现
        */
       public void setScope(String s) {
           this.scope = s;
      }    
       public String getScope(){return this.scope;}
       public void setType(String type){
              this.type=type;
       }
       public String getType(){return this.type;}
       /**
        *覆盖doStartTag方法
        */
        public int doStartTag() throws JspTagException 
        {  
            Object o = null;
           // find the bean in the specified scope
           if (scope.equals("page")) {

                     o = pageContext.getAttribute(getId(),PageContext.PAGE_SCOPE);

              } else if (scope.equals("request")) {

                     o = pageContext.getAttribute(getId(), PageContext.REQUEST_SCOPE);

              } else if (scope.equals("session")) {

                     o = pageContext.getAttribute(getId(), PageContext.SESSION_SCOPE);

              } else if (scope.equals("application")) {

                     o = pageContext.getAttribute(getId(), PageContext.APPLICATION_SCOPE);

           }
              if(o==null)
              {
                     System.out.println("o is null!");
                     try{
                            Class u=Class.forName(type);
                            o=u.newInstance();//无参构造方法
                            System.out.println("create success!");
                     }
                     catch(Exception e){

                            throw new JspTagException("error to created a "+getId()+" object!");

                     }
              }
              pageContext.setAttribute(getId(), o); //保存实例对象到上下文对象中
           return EVAL_BODY_INCLUDE; //返回类型
       }
}
现在我们已经把对象实例放到pageContext里了,是不是这样就可以在JSP页面中直接引用了?当然不是了,直接将JAVA对象放进pageContext中与在脚本中直接引用是不同的。差别在于JSP容器要负责取得这个对象,以脚本变量的形式提供给页面。即JSP容器负责来维护脚本变量与pageContext中相应对象的状态。有两种方法可以为自定义标签来声明脚本变量。
一种是声明variable,一种是通过TagExtraInfo类声明变量。前者是JDK1.2后的方法,优点是比较方便。后者因为要再写一个类文件,所以显得麻烦些,但更灵活,出于兼容性与功能上的考虑,建议还是采用后者。(关于此类的详细说明,请参考PPT文档)
 import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
 public class UseBeanTag extends TagExtraInfo {
    public VariableInfo[] getVariableInfo(TagData data) {
        return new VariableInfo[] {
      new VariableInfo(
            data.getId(),
           data.getAttributeString("type"),
            true,
            VariableInfo.AT_BEGIN)
        };
  }
}
 
现在,定义一个useBean标签的工作已进行大半,下面该定义标签库描述(TLD)文件了,该文件是一个XML文档,主要定义标签的属性、处理类和扩展信息类的声明。主要声明部分如下:(tag.tld)
……………………(省去标头部分)
<!-- useBEAN 标签-->
 <tag>
<name>useBEAN</name>
<!—声明标签处理类-->
    <tag-class>cn.dever.tag.UseBean</tag-class>
<!—声明标签扩展信息类-->
    <tei-class>cn.dever.taginfo.UseBeanTag</tei-class>
    <!—主体内容类型-->
    <body-content>jsp</body-content>
<!—属性设置-->
   <attribute>
        <name>scope</name>
<!—是否必选-->
        <required>true</required>
<!—是否可以使用JSP表达式-->
        <rtexprvalue>true</rtexprvalue>
      </attribute>
   
      <attribute>
        <name>id</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
      </attribute>
   
      <attribute>
        <name>type</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
      </attribute>
 </tag>
其实这个标签库描述文件应该是最先建立的,因为我们主要是为了说明实现的方法,所以标签描述放在后边了。接下就是将刚才做的这些东西部署到我们的应用中去。在目标JSP页面中引用一下就OK了。
<%@ taglib uri="/WEB-INF/tag.tld" prefix="dever" %>
<dever:useBEAN id="test" type="cn.dever.common.User" scope="page" /


你可能感兴趣的:(jsp自定义标签)