自定义JSP标签.docx
- 文档编号:10622380
- 上传时间:2023-02-21
- 格式:DOCX
- 页数:22
- 大小:119.25KB
自定义JSP标签.docx
《自定义JSP标签.docx》由会员分享,可在线阅读,更多相关《自定义JSP标签.docx(22页珍藏版)》请在冰豆网上搜索。
自定义JSP标签
自定义JSP标签
自定义标签技术是在JSP1.1版本中才出现的,它允许开发人员创建客户化的标签,并且在JSP文件中使用这些标签,这样可以使JSP代码更加简洁。
这些可重用的标签能处理复杂的逻辑运算和事务,或者能定义JSP网页的输出内容和格式。
本次课将结合具体的范例,详细介绍自定义标签的创建过程,以及它在JSP文件中的使用方法。
1自定义JSP标签简介
JSP标签包括以下几种形式。
(1)主体内容和属性都为空的标签,例如:
hello/> hello> hello> (2)包含属性的标签,例如: messagekey=”hello.hi”/> (3)包含主体内容的标签,例如: greeting>Howareyou. greeting> 以上 greeting>称为标签的起始标志, greeting>称为标签的结束标志,两个标签之间的内容“Howareyou.”称为标签主体。 (4)包含属性和主体内容的标签,例如: greetingusername=”Tom”>Howareyou. greeting> (5)嵌套的标签,例如: greeting> choose> when> when> choose> username=”Tom”age=”18”/> greeting> 以上外层标签 greeting>称为父标签,内层标签 user>称为子标签。 为了便于组织和管理标签,可以把一组功能相关的标签放在同一个标签库中。 开发包含自定义标签的标签库包括以下步骤: (1)创建自定义标签的处理类(TagHandlerClass)。 (2)创建TLD标签库描述文件(TagLibraryDescriptor)。 假定甲方开发了重用性比较高的标签库,那么除了甲方本身的Web应用可以使用它,其他方(如乙方)也可以使用它。 JSTLCore标签库的使用介绍了如何在Web应用中使用由第三方提供的JSP标准标签库(JSTL)。 本次课将按照如下步骤在Web应用中使用标签库: (1)把标签处理类及相关类的class文件存放在WEB-INF/classes目录下。 (2)把TLD标签库描述文件存放在WEB-INF目录或者其自定义的子目录下。 (3)在web.xml文件中声明所引用的标签库。 (4)在JSP文件中使用标签库中的标签。 2JSPTagAPI Servlet容器在运行JSP文件时,如果遇到自定义标签,就会调用这个标签的处理类(TagHandlerClass)的相关方法。 标签处理类可以继承JSPTagAPI中的TagSupport类或者BodyTagSupport类。 JSPTagAPI位于javax.servlet.jsp.tagext包中,图13-1是其中的主要接口和类的类框图。 图13-1JSPTagAPI 2.1JspTag接口 所有的标签处理类都要实现JspTag接口。 这个接口只是一个标识接口,没有任何方法,主要是作为Tag和SimpleTag接口的共同接口。 在JSP2.0以前,所有的标签处理类都要实现Tag接口,实现该接口的标签称为传统标签(ClassicTag)。 JSP2.0提供了SimpleTag接口,实现该接口的标签称为简单标签(SimpleTag)。 本章将介绍传统标签的用法。 2.2Tag接口 Tag接口定义了所有传统标签处理类都要实现的基本方法,包括以下几种。 ●setPageContext(PageContextpc): 由Servlet容器调用该方法,向当前标签处理对象(即Tag对象)传递当前的PageContext对象。 ●setParent(Tagt): 由Servlet容器调用该方法,向当前Tag对象传递父标签的Tag对象。 ●getParent(): 返回Tag类型的父标签的Tag对象。 ●release(): 当Servlet容器需要释放Tag对象占用的资源时,会调用此方法。 ●doStartTag(): 当Servlet容器遇到标签的起始标志时,会调用此方法。 doStartTag()方法返回一个整数值,用来决定程序的后续流程。 它有两个可选值,即Tag.SKIP_BODY和Tag.EVAL_BODY_INCLUDE。 Tag.SKIP_BODY表示标签之间的主体内容被忽略,Tag.EVAL_BODY_INCLUDE表示标签之间的主体内容被正常执行。 例如对于以下代码: mytag> HelloWorld …… mytag> 假若 ●doEndTag(): 当Servlet容器遇到标签的结束标志时,就会调用doEndTag()方法。 doEndTag()方法也返回一个整数值,用来决定程序后续流程。 它有两个可选值,即Tag.SKIP_PAGE和Tag.EVAL_PAGE。 Tag.SKIP_PAGE表示立刻停止执行标签后面的JSP代码,网页上未处理的静态内容和Java程序片段均被忽略,任何已有的输出内容立刻返回到客户的浏览器上。 Tag.EVAL_PAGE表示按正常的流程继续执行JSP文件按。 以上提到的Tag.SKIP_BODY、Tag.EVAL_BODY_INCLUDE、Tag.SKIP_PAGE和Tag.EVAL_PAGE是在Tag接口中定义的4个int类型的静态常量,用于指示标签处理流程。 标签处理类的对象(Tag对象)由Servlet容器负责创建。 Servlet容器在执行JSP文件时,如果遇到JSP文件中的自定义标签,就会寻找缓存中的相关的Tag对象,如果还不存在,就创建一个Tag对象,把它放在缓存中,以便下次处理自定义标签时重复使用。 当Servlet容器得到了Tag对象后,会按照如图13-2所示的流程调用Tag对象的相关方法: (1)Servlet容器调用Tag对象的setPageContext()和setParent()方法,把当前JSP页面的PageContext对象及父标签处理对象传给当前Tag对象。 如果不存在父标签,则把父标签处理对象设为null。 (2)Servlet容器调用Tag对象的一系列set方法,设置Tag对象的属性。 如果标签没有属性,则无需这个步骤。 (3)Servlet容器调用Tag对象的doStartTag()方法。 (4)如果doStartTag()方法返回Tag.SKIP_BODY,就不执行标签主体的内容;如果doStartTag()方法返回Tag.EVAL_BODY_INCLUDE,就执行标签主体的内容。 (5)Servlet容器调用Tag对象的doEndTag()方法。 (6)如果doEndTag()方法返回Tag.SKIP_PAGE,就不执行标签后续的JSP代码;如果doEndTag()方法返回Tag.EVAL_PAGE,就执行标签后续的JSP代码。 图13-2Servlet容器调用Tag对象的相关方法的流程 注: 一个Tag对象在被创建后,就会一直存在,可以被Servlet容器重复调用。 当Web应用终止时,Serlvet容器会先调用该Web应用中的所有Tag对象的release()方法,然后销毁这些Tag对象。 2.3IterationTag接口 IterationTag接口继承自Tag接口,IterationTag接口增加了重复执行标签主体内容的功能。 IterationTag接口定义了一个doAfterBody()方法,Servlet容器在执行完标签主体内容后,会调用此方法。 如果Serlvet容器未执行标签主体内容,那么就不会调用此方法。 doAfterBody()方法也返回一个整数值,用来决定程序后续流程,它有两个可选值: Tag.SKIP_BODY和IterationTag.EVAL_BODY_AGAIN。 Tag.SKIP_BODY表示不再执行标签主体内容;IterationTag.EVAL_BODY_AGAIN表示重复执行标签主体内容。 IterationTag接口还定义了一个可作为doAfterBody()方法的返回值得int类型的静态常量: IterationTag.EVAL_BODY_AGAIN,用于指示Servlet容器重复执行标签主体内容。 Servlet容器在处理JSP文件中的这种标签时,会寻找缓存中的相关的IterationTag对象,如果还不存在,就创建一个IterationTag对象,把它放在缓存中,以便下次处理自定义标签时重复使用。 Servlet容器在得到了IterationTag对象后,会按照如图13-3所示的流程调用IterationTag对象的相关方法: (1)Servlet容器调用IterationTag对象的setPageContext()和setParent()方法,把当前JSP页面的PageContext对象及父标签处理对象传给当前IterationTag对象。 如果不存在父标签,则把父标签处理对象设为null。 (2)Servlet容器调用IterationTag对象的一系列set方法,设置Tag对象的属性。 如果标签没有属性,则无需这个步骤。 (3)Servlet容器调用IterationTag对象的doStartTag()方法。 (4)如果doStartTag()方法返回Tag.SKIP_BODY,就不执行标签主体的内容;如果doStartTag()方法返回Tag.EVAL_BODY_INCLUDE,就执行标签主体的内容。 (5)如果在步骤(4)中Servlet容器执行了标签主体的内容,那么就调用doAfterBody()方法。 (6)如果doAfterBody()方法返回Tag.SKIP_BODY,就不再执行标签主体的内容;如果doAfterBody()方法返回IterationTag.EVAL_BODY_AGAIN,就继续重复执行标签主体的内容。 (7)Servlet容器调用IterationTag对象的doEndTag()方法。 (8)如果doEndTag()方法返回Tag.SKIP_PAGE,就不执行标签后续的JSP代码;如果doEndTag()方法返回Tag.EVAL_PAGE,就执行标签后续的JSP代码。 与Servlet容器调用Tag对象的流程相比,可以看出,以上步骤(5)和步骤(6)是增加的步骤。 图13-3Servlet容器调用IterationTag对象的相关方法的流程 2.4BodyTag接口 BodyTag接口继承自IterationTag接口,增加了直接访问和操纵标签主体内容的功能。 BodyTag接口定义了两个方法。 ●setBodyContent(BodyContentbc): Servlet容器通过此方法向BodyTag对象传递一个用于缓存标签主体的执行结果的BodyConent对象。 ●doInitBody(): 当Servlet容器调用完setBodyContent()方法之后,在第一次执行标签主体之前,先调用此方法,该方法用于为执行标签主体做初始化工作。 只要符合以下两种条件之一,setBodyContent(BodyContentbc)和doInitBody()就不会被Servlet容器调用: ●标签主体为空。 ●doStartTag()方法的返回值为Tag.SKIP_BODY或者Tag.EVAL_BODY_INCLUDE。 只有同时符合以下两个条件,Servlet容器才会调用setBodyContent(BodyContentbc)和doInitBody()方法: ●标签主体不为空。 ●doStartTag()方法的返回值为BodyTag.EVAL_BODY_BUFFERED。 以上提到的BodyTag.EVAL_BODY_BUFFERED是在BodyTag接口中定义的int类型的静态常量,它可作为doStartTag()方法的返回值,指示Servlet容器调用BodyTag对象的setBodyContent()和doInitBody()方法。 Servlet容器在处理JSP文件中的这种标签时,会寻找缓存中的相关的BodyTag对象,如果还不存在,就创建一个BodyTag对象,把它放在缓存中,以便下次处理自定义标签时重复使用。 Servlet容器在得到了BodyTag对象后,会按照如图13-4所示的流程调用BodyTag对象的相关方法: (1)Servlet容器调用BodyTag对象的setPageContext()和setParent()方法,把当前JSP页面的PageContext对象及父标签处理对象传给当前BodyTag对象。 如果不存在父标签,则把父标签处理对象设为null。 (2)Servlet容器调用BodyTag对象的一系列set方法,设置Tag对象的属性。 如果标签没有属性,则无需这个步骤。 (3)Servlet容器调用BodyTag对象的doStartTag()方法。 (4)如果doStartTag()方法返回Tag.SKIP_BODY,就不执行标签主体的内容;如果doStartTag()方法返回Tag.EVAL_BODY_INCLUDE,就执行标签主体的内容;如果doStartTag()方法返回BodyTag.EVAL_BODY_BUFFERED,就先调用setBodyContent()和doInitBody()方法,再执行标签主体的内容。 (5)如果在步骤(4)中Servlet容器执行了标签主体的内容,那么就调用doAfterBody()方法。 (6)如果doAfterBody()方法返回Tag.SKIP_BODY,就不再执行标签主体的内容;如果doAfterBody()方法返回IterationTag.EVAL_BODY_AGAIN,就继续重复执行标签主体的内容。 (7)Servlet容器调用BodyTag对象的doEndTag()方法。 (8)如果doEndTag()方法返回Tag.SKIP_PAGE,就不执行标签后续的JSP代码;如果doEndTag()方法返回Tag.EVAL_PAGE,就执行标签后续的JSP代码。 图13-4Servlet容器调用BodyTag对象的相关方法的流程 2.5TagSupport类和BodyTagSupport类 TagSupport类和BodyTagSupport类是标签实现类,其中TagSupport类实现了IterationTag接口,而BodyTagSupport类则继承自TagSupport类,并且实现了BodyTag接口。 用户自定义的标签处理类可以继承TagSupport类或者BodyTagSupport类。 例程13-1是TagSupport类的部分源代码。 例程13-1TagSupport.java importjava.io.Serializable; importjava.util.Enumeration; importjava.util.Hashtable; importjavax.servlet.jsp.JspException; importjavax.servlet.jsp.PageContext; importjavax.servlet.jsp.tagext.IterationTag; importjavax.servlet.jsp.tagext.Tag; publicclassTagSupportimplementsIterationTag,Serializable{ publicstaticfinalTagfindAncestorWithClass(Tagfrom, @SuppressWarnings("unchecked")Classklass){ booleanisInterface=false; if(from==null ||klass==null ||(! Tag.class.isAssignableFrom(klass)&&! (isInterface=klass .isInterface()))){ returnnull; } for(;;){ Tagtag=from.getParent(); if(tag==null){ returnnull; } if((isInterface&&klass.isInstance(tag)) ||klass.isAssignableFrom(tag.getClass())) returntag; else from=tag; } } publicTagSupport(){ } publicintdoStartTag()throwsJspException{ returnSKIP_BODY; } publicintdoEndTag()throwsJspException{ returnEVAL_PAGE; } publicintdoAfterBody()throwsJspException{ returnSKIP_BODY; } publicvoidrelease(){ parent=null; id=null; if(values! =null){ values.clear(); } values=null; } publicvoidsetParent(Tagt){ parent=t; } publicTaggetParent(){ returnparent; } publicvoidsetId(Stringid){ this.id=id; } publicStringgetId(){ returnid; } publicvoidsetPageContext(PageContextpageContext){ this.pageContext=pageContext; } publicvoidsetValue(Stringk,Objecto){ if(values==null){ values=newHashtable } values.put(k,o); } publicObjectgetValue(Stringk){ if(values==null){ returnnull; }else{ returnvalues.get(k); } } publicvoidremoveValue(Stringk){ if(values! =null){ values.remove(k); } } publicEnumeration if(values==null){ returnnull; } returnvalues.keys(); } privateTagparent; privateHashtable protectedStringid; protectedPageContextpageContext; } TagSupport类的主要方法参见表13-1。 表13-1TagSupport类的主要方法 方法 属性 doStartTag() 当Servlet容器遇到自定义标签的起始标志时调用该方法 doEndTag() 当Servlet容器遇到自定义标签的结束标志时调用该方法 setValue(Stringkey,Objectvalue) 在标签处理对象中设置key/value getValue(Stringkey) 根据参数key返回匹配的value removeValue(Stringkey) 在标签处理对象中删除key/value setPageContext(PageContextpc) 设置PageContext对象,该方法由Servlet容器在调用doStartTag()方法前调用 setParent(Tagt) 设置父标签的处理对象,该方法由Servlet容器在调用doStartTag()方法前调用 getParent() 返回父标签的处理对象 1、parent和pageContext成员变量 TagSupport类有两个重要的成员变量。 ●parent: private访问级别的成员变量,代表父标签的处理对象。 ●pageContext: protected访问级别的成员变量,代表当前JSP页面的PageContext对象。 Servlet容器在调用doStartTag()方法前,会先调用setPageContext()和setParent()方法,设置pageContext和parent成员变量,因此在TagSupport子类的doStartTag()或doEndTag()等方法中可以通过getParent()方法获取父标签的处理对象。 在TagSupport类中定义了protected访问级别的pageContext成员变量,因此在TagSupport子类的doStartTag()或doEndTag()等方法中可以直接访问pageContext变量。 JSP课程中(PageContext抽象类)已经介绍了PageContext类的作用,它在标签处理类中将大有用武之地。 在本章及下一章的标签处理类的例子中,都会用到PageContext类。 注: 在TagSupport的构造方法中不能访问pageContext成员变量,因为此时Servlet容器还没有调用setPageContext()方法对pageContext成员变量进行初始化。 2、处理标签的方法 对于用户自定义的标签处理类,主要重新实现TagSupport类中的以下方法。 ●doStartTag(): 提供Servlet容器在遇到标签起始标志时执行的操作。 ●doEndTag(): 提供Servlet容器在遇到标签结束标志时执行的操作。 如果希望Servlet容器重复执行标签主体的内容,那么还可以重新实现TagSupport类的doAfterBody()方法。 3、用户自定义的标签属性 如果在标签中包含自定义的属性,例如: mytagusername
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 自定义 JSP 标签
![提示](https://static.bdocx.com/images/bang_tan.gif)