您的位置:首页 > Web前端 > JavaScript

10JSP自定义标签

2016-07-15 10:45 537 查看
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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: