1.自定义标签(Custom Tag)概述 <!--[if !supportLists]-->(1)用户自定义的一种jsp标记。自定义标签将那些重复工作进行封装,从而提高了工程生产力,而且将具有共用特性的标签库应用于不同的项目中,体现了软件复用的思想。 <!--[if !supportLists]-->(2)当一个含有自定义标签的jsp页面被jsp引擎(Web容器)编译成servlet时,标签将被转化成对一个称为tag处理类的对象的操作。之后当JSP页面对应的servlet被执行时,jsp引擎就调用这些操作。 2.标签的形式 <前缀:标签名 属性名1=值1属性名2=值2 …>标签主体</前缀:标签名> 一个标签可以没有属性或者没有主体,也可以同时没有属性和主体。没有主体的标签可以简写成这样的形式:<前缀:标签名 属性名1=值1 …/>、<前缀:标签名/>。 3.自定义标签的优点 <!--[if !supportLists]-->(1)分离了程序逻辑和表示逻辑。 <!--[if !supportLists]-->(2)将Java代码从HTML中剥离,便于美工维护页面。 <!--[if !supportLists]-->(3)减少了JSP页面中的脚本,减少了维护成本。 <!--[if !supportLists]-->(4)提供了可重用的功能组件。 4.自定义标签库(Custom Tag library) 由一系列功能相似、逻辑上互相联系的自定义标签构成的集合称为标签库。 5.创建自定义标签的方式 (1)Java类文件方式。 (2)标签文件方式。 标签文件是一个扩展名为.tab的文件,它必须存储在Web应用程序的WEB-INF目录中。标签文件的作用类似标签处理文件,它是一个包含一些内容或JSP代码的要重用的JSP片段。在JSP页面遇到自定义标签时,它会转到标签文件以执行标签定义。不需要一个单独的标签库描述符,因为标签文件包含自定义标签的完整实现。 Java类文件方式创建和使用一个自定义标签库的基本步骤有如下几步。 (1)创建标签的处理类(Tag Handle Class)。定义标签的行为,并在JSP引擎遇到自定义标签时调用执行。标签处理类是一个Java类,这个类继承了TagSupport或者扩展了SimpleTag接口,通过这个类可以实现自定义JSP标签的具体功能。 (2)创建标签库描述文件TLD(Tag Library Descrptor File)。描述标签库的XML文档,向JSP引擎提供有关自定义标签的标签处理程序的信息。 (3)在web.xml文件中声明TLD的位置。 (4)在JSP文件中用taglib指令引入标签库。 (5)在JSP中使用标签库标签。 6.创建标签的处理类 (1)传统标签处理器在javax.servlet.jsp.tagext包中的接口和类,如图8-1所示。 <!--[if !vml]--><!--[endif]--> 图8-1 传统标签的接口和类 我们要写的自定义标签处理类主要继承自TagSupport、BodyTagSupport这两个类。通过继承这两个类,只需要重新定义那些需要自定义的行为的方法,从而简化了标签处理程序的开发。 (2)简单标签处理器javax.servlet.jsp.tagext包中的接口和类。我们要写的自定义标签处理类继承自SimpleTagSupport类,重写doTag()方法。这是在JSP2.0新规范中增加的类,这个类实现自SimpleTag接口,之所以称其为“简单”是指它相对于传统标签处理器实现任务要简单得多。 (3)TagSupport类。TagSupport类并不能对标签主体的内容做任何处理,您所能决定的只是是否显示主体的内容。 ① 生命周期 当JSP容器在解释JSP页面时,如果碰到自定义标签,将利用“标签处理类”建立一个“标签处理对象”。在建立“标签处理对象”的过程中,JSP容器会根据自定义标签的属性值来初始化“标签处理对象”的属性。 首先,JSP容器会运行doStartTag()方法内的程序代码,然后根据此方法的返回值决定后续动作。如果返回SKIP_BODY,表示要求JSP容器忽略标签主体的内容;如果返回EVAL_BODY_INCLUDE,表示要求JSP容器要显示标签主体的内容,然后运行doAfterBody()方法。 如果doAfterBody()方法传回EVAL_BODY_AGAIN,表示要求JSP容器再次显示标签主体的内容,如果返回SKIP_BODY,JSP容器将会运行doEndTag()方法。 最后,JSP容器会运行doEndTag()方法内的程序代码,并根据此方法的返回值决定后续动作:如果返回SKIP_PAGE,JSP容器会运行release()方法,然后忽略自定义标签以后的JSP内容;如果返回EVAL_PAGE,JSP容器会先运行release()方法,然后运行自定义标签以后的JSP内容。 ② 生命周期主要方法 ● doStartTag()方法可返回的值有SKIP_BODY,忽略标签主体的内容(此方法的预设返回值);VAL_BODY_INCLUDE,表示要求JSP容器要显示标签主体内容。 ● doAfterBody()方法可返回的值有以下几项。 ● SKIP_BODY:要求JSP容器忽略主体内容,进入标签处理程序的下一步工作(此方法的预设返回值)。 ● EVAL_BODY_AGAIN:要求JSP容器再次显示标签主体内容。 ● doEndTag()方法可返回的值有以下几项 ● SKIP_PAGE:忽略自定义标签以后的JSP网页内容。 ● EVAL_PAGE:运行自定义标签以后的JSP网页内容(此方法的预设返回值)。 ● release():释放标签处理对象所占用的系统资源。 (4)BodyTagSupport类。 ① 生命周期 BodyTagSupport与TagSupport的区别主要是标签处理类是否需要读取标签体的内容和改变标签体返回的内容,如果不需要交互的就用TagSupport,否则就用BodyTagSupport。 这里需要注意的是TagSupport也可以有体,如果将TagSupport理解成是没有体的标签,而将BodyTagSupport理解成是有体的标签就错了。当然用TagSupport实现的标签,都可以用BodyTagSupport来实现,道理很简单,因为BodyTagSupport继承了TagSupport。 ② 生命周期主要方法 ● doStartTag() 方法可返回的值有SKIP_BODY,表示要求JSP容器忽略主体内容; EVAL_BODY_INCLUDE,表示要求JSP容器要显示标签主体内容;EVAL_BODY_BUFFERED 表示JSP容器会将标签主体的处理结果建立成一个BodyContent对象(此方法的预设返回值)。 ● setBodyContent()方法会设置BodyContent对象的一些属性,包括标签主体的内容和在处理标签过程中要输出至response的数据对象。 ● doInitBody()方法在第一次处理标签主体内容时,它将对主体进行初始化的工作。 ● doAfterBody()方法可返回的值有SKIP_BODY,表示要求JSP容器忽略主体,进入下一步的处理工作;EVAL_BODY_AGAIN,表示要求JSP容器再次处理标签主体。 ● doEndTag()方法可返回的值有SKIP_PAGE,表示忽略自定义标签以后的JSP网页内容; EVAL_PAGE,表示运行自定义标签以后的JSP网页内容。 ● release()方法释放标签处理对象所占用的系统资源。 (5)SimpleTagSupport类。 生命周期事件有以下几种。 ● 当JSP容器遇到标记时,将标签处理类的默认构造方法建立一个标签处理实例。注意必须为每个标记都创建一个新的实例,这很重要。 ● 在标记处理程序中调用setJspContext()和setParent()方法。如果传递的值是“null”,则不需要调用setParent()方法。在使用标记文件的情况下,创建一个JspContext包装,以便标记文件看上去具有其本身的页面范围。调用getJspContext()必须返回所包装的JspContext。 ● 容器为每个标记所定义的属性,同时也需要提高set方法,set方法是用来让外界设置属性的值,其顺序是它们出现在JSP页或标记文件中的顺序。如果属性值是表达式语言的表达式或运行时表达式,则它首先被赋值,然后被传递到设置器;另一方面,如果属性为动态属性,则调用setDynamicAttribute()。 ● 由容器调用setJspBody()方法,将该标记的主体设置为JspFragment;如果标记被声明为具有空的值,则将null值传递到setJspBody()。 ● 由容器调用doTag()方法。所有的标记逻辑、迭代、主体赋值等都在该方法中发生。 ● 在doTag()方法返回后,所有的变量被同步。 7.撰写标签处理类 你所撰写的标签处理类应该具备下列特性: ● 承TagSupport类或BodyTagSupport类或SimpleTagSupport类; ● 对自定义标签的属性声明相对应的变量,并提供一个setXXX()方法; ● doStartTag()、doAfterBody()或doEndTag()方法(或doTag()方法)内撰写Java程序代码,实现自定义标签欲提供的功能。 示例如下: |