10JSP自定义标签

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


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


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


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


2自定义JSP标签的处理过程:
JSP文件中引入标签库:
<% @ taglib prefix="taglibprefix" uri="tagliburi"%>
JSP页面中通过taglibprefix来使用标签库标签。uri的取值为web.xml中/myTag的值。


Web容器根据JSP页面中的"taglibprefix",获得声明中的taglib的uri属性值
Web容器根据uri属性在web.xml找到对应的元素
   
       /myTag
       /WEB-INF/myTag.tld
 

对应tld文件中标签库中的的值,指出tld文件的位置。
Web容器根据元素的值从WEB-INF/目录下找到对应的.tld文件 
从.tld文件中找到与tagname对应的元素 
从元素中获得对应的元素的值 
Web容器根据元素的值创建相应的tag handle class的实例 
Web容器调用这个实例的doStartTag/doEndTag方法完成相应的处理


3两种标签:
javax.servlet.jsp.tagext.Tag 
javax.servlet.jsp.tagext.BodyTag
有标签体的标签必须实现 BodyTag 接口。

body



也可能没有标签体:

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




4创建和使用一个Tag Library的基本步骤:
创建标签的处理类(Tag Handler Class)
创建标签库描述文件(Tag Library Descriptor File)
在web.xml文件中配置元素。
在JSP文件中引入标签库。


如何创建标签库描述文件(Tag Library Descriptor File)
标签库描述文件,简称TLD,采用XML文件格式,定义了用户的标签库。TLD文件中的元素可以分成3类:
标签库元素,标签元素,标签属性元素。


标签库元素用来设定标签库的相关信息,它的常用属性有:
shortname: 指定Tag Library默认的前缀名(prefix)
uri: 设定Tag Library的惟一访问标识符


标签元素用来定义一个标签,包含在标签库元素中。它的常见属性有:
name: 设定Tag的名字
tagclass: 设定Tag的处理类
bodycontent: 设定标签的主体(body)内容,bodycontent的取值有:
tagdependent:标签体内容 直接被写入BodyContent,由自定义标签类来进行处理,而不被JSP容器解释。如下: 
 
select name,age from users 
 


JSP:接受所有JSP语法,如定制的或内部的tag、scripts、静态HTML、脚本元素、JSP指令和动作。如:
 
    <%=request.getProtocol()%> 
 


empty:空标记,即起始标记和结束标记之间没有内容。 
下面几种写法都是有效的, 
 
 
 


scriptless: 接受文本、EL和JSP动作


标签属性元素用来定义标签的属性,包含在标签元素中。它的常见属性有:
name:属性名称
required:属性是否必需的,默认为false
rtexprvalue:属性值是否可以为request-time表达式,也就是类似于<%=…% >的表达式。
rtexprvalue设置为true,表示标签体支持运行时的表达式取值,如果为false则表示标签体为一个静态文本,默认情况下设置为true。


如果标签元素中设置了属性,则在标签处理类里提供该属性相应的set方法。




例如:WEB-INF\tlds\test.tld

version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">

Dgzz Tags
6
 test          //标签库名,也称为前缀。比如“” 里的“c”
  /WEB-INF/tlds/test            //在jsp页面上引用的路径
                                 //标签
  out                      //定义标签的名  例如““里的"out”,
  gdufs.tags.OutputTag  //指出标签处理程序类 记着带包名
  empty   //如果没有标签体,设置empty , 如果有标签体必须设置JSP 
 
   
  name//属性名字。例如里的attrName。名字可任意取,只要标签处理类里提供相应的set方法即可。
   false        //是否必填属性
   false  //是否支持运行时表达式取值就是是否可以是${}方式传值。"
 
 



5如何创建标签处理类:
引入必需的资源。
继承TagSupport类并覆盖doStartTag()/doEndTag()方法(TagSupport类实现了Tag接口)。


TagSupport类简介:
处理标签的类必须扩展javax.servlet.jsp.TagSupport
TagSupport类的主要属性:
parent属性:代表嵌套了当前标签的上层标签的处理类。


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


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


在TagSupport的构造方法中不能访问pageContext成员变量,因为此时JSP容器还没有调用setPageContext方法对pageContext进行初始化。


TagSupport处理标签的方法:
public int doStartTag() throws JspException 
public int doEndTag() throws JspException 
doStartTag:当JSP容器遇到自定义标签的起始标志,就会调用doStartTag()方法。doStartTag()方法返回一个整数值,用来决定程序的后续流程。
Tag.SKIP_BODY:跳过了开始和结束标签之间的代码
Tag.EVAL_BODY_INCLUDE:表示标签之间的内容被正常执行


doEndTag:但JSP容器遇到自定义标签的结束标志,就会调用doEndTag()方法。doEndTag()方法也返回一个整数值,用来决定程序后续流程。
Tag.SKIP_PAGE:表示立刻停止执行网页,网页上未处理的静态内容和JSP程序均被忽略任何已有的输出内容立刻返回到客户的浏览器上。
Tag.EVAL_PAGE:表示按照正常的流程继续执行JSP网页。
例如:
  public int doEndTag() throws JspException 
    { 
    try { 


     .......
 
     } catch (Exception e) { throw new JspException(e); } 
    return EVAL_PAGE; //EVAL_PAGE 表示tag已处理完毕,返回jsp页面
    } 
 
6下面是一个自定义标签的简单示例:
首先我们创建一个标签处理类继承自TagSupport :
package action;
import javax.servlet.jsp.JspException; 
import javax.servlet.jsp.JspWriter; 
import javax.servlet.jsp.tagext.TagSupport; 
public class MyTLD extends TagSupport { 
private String name=null;     //对应tld中属性,
public void setName(String name) { 
this.name = name; 

public int doEndTag() throws JspException 

try { 
JspWriter out = pageContext.getOut();  //如何输出到jsp页面
  out.print("Hello! " + name); 
 } catch (Exception e) { throw new JspException(e); } 
return EVAL_PAGE; //EVAL_PAGE 表示tag已处理完毕,返回jsp页面

}


然后我们再创建标签库描述文件(WEB-INF/tlds/mytld.tld)


version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">

Dgzz Tags
6

 test

  /testTLD



 

  out

  action.MyTLD
  empty

   
  name
   false
   false
 
 



然后web.xml中进行配置:


/WEB-INF/tlds/mytld.tld
/testTLD




最后在JSP中引入标签库并使用:
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix ="t" uri = "/testTLD" %>


/*使用自定义标签库/testTLD中的out标签,并给标签的name属性赋值*/
Test Tag:  


注意我们也可以不再web.xml进行配置,那么我们在JSP页面必须给出uri关于tld的文件完整路径如:
<%@ taglib prefix ="t" uri = "/WEB-INF/tlds/mytld.tld" %>


7带标签体的标签
要开发带标签体的标签,可实现BodyTag接口,也可从BodyTag接口的实现类BodyTagSupport继承,为简化开发,推荐从BodyTagSupport类继承开发。
编写标签对应的实现类时,需要重载BodyTagSupport类几个方法:doStartTag(), setBodyContent(), doInitBody(), doAfterBody(), doEndTag(),他们执行顺序如下:    
doStartTag()→doInitBody()→setBodyContent()→doAfterBody()→doEndTag()。


doStartTag,返回SKIP_BODY 、EVAL_BODY_INCLUDE、EVAL_BODY_AGAIN/EVAL_BODY_BUFFERED 
doInitBody,做标签一些初始化工作,无返回值。
setBodyContent方法,在doInitBody之后执行,使用setBodyContent得到JSP页面中标签体之间内容。
doAfterBody方法,最终必须返回SKIP_BODY ,否则可能导致OutOfMemoryError。
doEndTag方法,返回SKIP_PAGE/EVAL_PAGE。
注意其中的 doInitBody/setBodyContent 方法在自定义标签实现了 BodyTag 接口或继承BodyTagSupport才可以使用 。


doStartTag()方法可返回EVAL_BODY_INCLUDE或SKIP_BODY,如果返回EVAL_BODY_ INCLUDE则继续执行;如果返回SKIP_BODY则接下来的doInitBody(),setBodyContent(), doAfterBody()三个方法不会被执行,而直接执行doEndTag()方法。
setBodyContent()方法用于设置标签体内容,如果在此之前要作一些初始化工作,则在doInitBody()方法中完成。
标签体内容执行完后,会调用doAfterBody()方法,此方法可返回EVAL_BODY_TAG, SKIP_BODY, EVAL_PAGE或SKIP_PAGE。如果返回EVAL_BODY_TAG则会再次设置标签体内容,直到返回SKIP_BODY;如果返回EVAL_PAGE则标签体执行完后会继续执行JSP页面中接下来的部分;如果返回SKIP_PAGE,则JSP页面的后续内容将不再执行。




8SimpleTag标签
JSP2.0中为了简化标签的复杂性,增加了制作Simple Tag的标签类SimpleTagSupport类。SimpleTagSupport类是实现SimpleTag接口的。它只需要实现一个doTag()方法即可,而不需要一堆回传值。例如:
package action;


import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.SimpleTagSupport;


public class mytld2 extends SimpleTagSupport
{
    private String kehu;
    public void setKehu(String kehu)
    {
        this.kehu = kehu;
    }


    public void doTag() throws JspException,IOException{
        JspWriter out=this.getJspContext().getOut();
        out.println("this is SimpleTagSupport:"+kehu);
    }
}


其对应的tld文件如下:

version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">

Dgzz Tags
6
 mytld
  /mytld>
 
  out
  action.mytld2
  empty
   
  kehu
   false
   false
 
 



SimpleTag标签与带标签体的标签
package action;


import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;


public class mytld3 extends SimpleTagSupport
{
    public void doTag() throws JspException,IOException{
        //fragment封装了标签体
        JspFragment fragment=this.getJspBody();
        JspWriter out=this.getJspContext().getOut();
        StringWriter sout=new StringWriter();
        //将标签体的内容写到指定的输出流,如果取值为null表示写入预设的getJspContext.getOut()取得的输出流对象
        //这里我们将它指定到StringWriter字符输出流中。
        fragment.invoke(sout);
        String msg=sout.toString();
        out.println(msg+"(body in String writer)");
        
    }


}


对应的tld文件(mytld3.tld)如下:

version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">

Dgzz Tags
6
bodytld
  /bodytld
 
  showBody
  action.mytld3



  tagdependent
 
 



然后再web.xml中配置该tld

/WEB-INF/tlds/mytld3.tld
/bodytld

在jsp中应用该标签
<%@ taglib prefix ="t3" uri = "/bodytld" %>
....

select * from Table

运行结果如下:
select * from Table (body in String writer) 


**********JspWriter与PrintWriter的区别:**********
JspWriter可以在JSP页面中直接用out对象输出.可以用pageContext.getOut();得到JspWriter对象.
PrintWriter在JSP页面中必须用response.getWriter();方法得到其对象.二者作用域不同.


不管JspWriter与PrintWriter在程序中的顺序怎么样,始终先会输出PrintWriter中的数据然后再输出JspWriter中的数据.


*********web.xml配置标签***************
如果是头是这样的
直接在后面加上

    /testTLD
    /WEB-INF/struts-logic.tld

如果头是这样的

在后面加上


    /testTLD
    /WEB-INF/validator-user.tld




注意
web.xml中的/testTLD
tld文件中的/testTLD
jsp文件中的<%@ taglib prefix ="t" uri = "/testTLD" %>
这三个地方的uri是一致的。




**************************


一个tld中可以放置多个自定义标签

version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">

oode Tags
6
  grant             
/grantTag



                           
  grant                     
  oode.pub.tag.GrantTag 
  JSP 
 
   
  menuCode
   true        
  true 
 
 



                           
  switch                     
  oode.pub.tag.SwitchTag 
  empty 
 
   
  type
   true        
  true 
 


  
  value
   true        
  true 
 
 



web.xml配置:


    /grantTag
    /WEB-INF/tlds/grantTag.tld




在JSP用引入:<%@ taglib prefix ="oode" uri = "/grantTag" %>




修改


你可能感兴趣的:(jsp,jsp)