码迷,mamicode.com
首页 > Web开发 > 详细

10JSP自定义标签

时间:2016-07-15 21:41:17      阅读:235      评论:0      收藏:0      [点我收藏+]

标签:

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中<taglib-uri>/myTag</taglib-uri>的值。


Web容器根据JSP页面中的"taglibprefix",获得声明中的taglib的uri属性值
Web容器根据uri属性在web.xml找到对应的元素
   <taglib>
       <taglib-uri>/myTag</taglib-uri>
       <taglib-location>/WEB-INF/myTag.tld</taglib-location>
  </taglib>
<taglib-uri>对应tld文件中标签库中的<uri>的值,<taglib-location>指出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 接口。
<jsptag:map scope="session" name=“tagMap”>
body
</jsptag:map>


也可能没有标签体:
<jsptag:map/>
无标签体的简单标签可以实现 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容器解释。如下: 
<test:myList> 
select name,age from users 
</test:myList> 


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


empty:空标记,即起始标记和结束标记之间没有内容。 
下面几种写法都是有效的, 
<test:mytag /> 
<test:mytag uname="Tom" /> 
<test:mytag></test:mytag> 


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


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


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




例如:WEB-INF\tlds\test.tld
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
<description><![CDATA["To make it easier to access dynamic data;"]]></description>
<display-name>Dgzz Tags</display-name>
<tlib-version>6</tlib-version>
 <short-name>test</short-name>          //标签库名,也称为前缀。比如“<c:out value=""/>” 里的“c”
  <uri>/WEB-INF/tlds/test</uri>            //在jsp页面上引用的路径
  <tag>                                //标签
  <name>out</name>                      //定义标签的名  例如“<test:out attrName=""/>“里的"out”,
  <tag-class>gdufs.tags.OutputTag</tag-class>  //指出标签处理程序类 记着带包名
  <body-content>empty</body-content>   //如果没有标签体,设置empty , 如果有标签体必须设置JSP 
 
  <attribute> 
  <name>name</name>//属性名字。例如<test:out attrName=""/>里的attrName。名字可任意取,只要标签处理类里提供相应的set方法即可。
   <required>false</required>        //是否必填属性
   <rtexprvalue>false</rtexprvalue>  //是否支持运行时表达式取值就是是否可以是${}方式传值。"
</attribute> 
</tag> 
</taglib>


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)
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--设定标签库-->
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
<description><![CDATA["To make it easier to access dynamic data;"]]></description>
<display-name>Dgzz Tags</display-name>
<tlib-version>6</tlib-version>
<!--指定Tag Library默认的前缀名(prefix)-->
 <short-name>test</short-name>
<!--设定Tag Library的惟一访问标识符,taglib下面只能有一个uri-->
  <uri>/testTLD</uri>


<!--设定标签-->
  <tag>
<!--设定标签名称-->
  <name>out</name>
<!--设定标签处理类-->
  <tag-class>action.MyTLD</tag-class>
  <body-content>empty</body-content>
<!--设定标签属性-->
  <attribute> 
  <name>name</name>
   <required>false</required>
   <rtexprvalue>false</rtexprvalue>
</attribute> 
</tag> 
</taglib>


然后web.xml中进行配置:
<jsp-config>
<taglib>
<taglib-location>/WEB-INF/tlds/mytld.tld</taglib-location>
<taglib-uri>/testTLD</taglib-uri>
</taglib>
</jsp-config>


最后在JSP中引入标签库并使用:
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix ="t" uri = "/testTLD" %>
<html>
<body>
/*使用自定义标签库/testTLD中的out标签,并给标签的name属性赋值*/
Test Tag: <t:out name="TEST"/> 
</body>
</html>
注意我们也可以不再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文件如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
<description><![CDATA["To make it easier to access dynamic data;"]]></description>
<display-name>Dgzz Tags</display-name>
<tlib-version>6</tlib-version>
 <short-name>mytld</short-name>
  <uri>/mytld></uri>
  <tag>
  <name>out</name>
  <tag-class>action.mytld2</tag-class>
  <body-content>empty</body-content>
  <attribute> 
  <name>kehu</name>
   <required>false</required>
   <rtexprvalue>false</rtexprvalue>
</attribute> 
</tag> 
</taglib>


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)如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
<description><![CDATA["To make it easier to access dynamic data;"]]></description>
<display-name>Dgzz Tags</display-name>
<tlib-version>6</tlib-version>
<short-name>bodytld</short-name>
  <uri>/bodytld</uri>
  <tag>
  <name>showBody</name>
  <tag-class>action.mytld3</tag-class>


<!-- tagdependent:标签体内容 直接被写入BodyContent,由自定义标签类来进行处理,而不被JSP容器解释 -->
  <body-content>tagdependent</body-content>
  </tag> 
</taglib>


然后再web.xml中配置该tld
<taglib>
<taglib-location>/WEB-INF/tlds/mytld3.tld</taglib-location>
<taglib-uri>/bodytld</taglib-uri>
</taglib>
在jsp中应用该标签
<%@ taglib prefix ="t3" uri = "/bodytld" %>
....
<t3:showBody>
select * from Table
</t3:showBody>
运行结果如下:
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配置标签<taglib>***************
如果是头是这样的<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
直接在后面加上
<taglib>
    <taglib-uri>/testTLD</taglib-uri>
    <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
如果头是这样的
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
在后面加上
<jsp-config>
<taglib>
    <taglib-uri>/testTLD</taglib-uri>
    <taglib-location>/WEB-INF/validator-user.tld</taglib-location>
</taglib>
</jsp-config>


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




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


一个tld中可以放置多个自定义标签
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
<description><![CDATA["To make it easier to access dynamic data;"]]></description>
<display-name>oode Tags</display-name>
<tlib-version>6</tlib-version>
  <short-name>grant</short-name>             
<uri>/grantTag</uri>


<!--  grant标签 -->
<tag>                            
  <name>grant</name>                     
  <tag-class>oode.pub.tag.GrantTag</tag-class> 
  <body-content>JSP</body-content> 
 
  <attribute> 
  <name>menuCode</name>
   <required>true</required>        
  <rtexprvalue>true</rtexprvalue> 
</attribute> 
</tag> 


<!--  switch标签 -->
<tag>                            
  <name>switch</name>                     
  <tag-class>oode.pub.tag.SwitchTag</tag-class> 
  <body-content>empty</body-content> 
 
  <attribute> 
  <name>type</name>
   <required>true</required>        
  <rtexprvalue>true</rtexprvalue> 
</attribute> 


 <attribute> 
  <name>value</name>
   <required>true</required>        
  <rtexprvalue>true</rtexprvalue> 
</attribute> 
</tag> 
</taglib>


web.xml配置:
<jsp-config>
<taglib>
    <taglib-uri>/grantTag</taglib-uri>
    <taglib-location>/WEB-INF/tlds/grantTag.tld</taglib-location>
</taglib>
</jsp-config>


在JSP用引入:<%@ taglib prefix ="oode" uri = "/grantTag" %>
<oode:switch type="menuLevel" value="${data.level}"/>


<oode:grant menuCode="0-cml-dly-0t1-maa">
<span onclick="showUpdateMenu(‘${data.menuID}‘)">修改</span>
</oode:grant>

10JSP自定义标签

标签:

原文地址:http://blog.csdn.net/bin71722/article/details/51915678

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!