自定义标签详解

 

传统的Tag接口

1.    建立自定义标签有3个步骤:

1.    建立实现标签类Tag的标签处理器类。一般继承自TagSupport类。

       Tag接口中有如下方法:

       doStartTag()          在标签开始时被调用

       doEndTag()           在标签结束时被调用

       getParent()            返回setParent设置的父标签

       release()                在标签类被销毁时执行

       setPageContext()   在每次jspservlet被执行时给Tag传递页面信息

       setParent()            设置标签的父标签。父标签必须也是一个jsp标签。

2.建立tld文件。

       一般可在tomcat_home\webapps\examples\WEB-INF\jsp2中找到tld文件的例子。可以把标签头及tag标签复制下来参考即可。

       需要注意的是:<uri>/SimpleTagLibrary</uri>声明的是该tld文件的名称空间,对应于jsp文件<%@taglib>标签中的uri,这是jsp识别tld文件的途径。

       <tag>标签对应的是实现标签接口的标签处理类。

              其中<name>文件用于jsp中标识标签名。

              <tag-class>必须是标签处理类带包名的限定名,用于tld定位class文件。

              <body-content>中常用的值:empty(表示标签内容为空)

                                                        JSP(必须大写,表示标签内容可包含JSP脚本)

                                                               scriptless(表示标签内容不可包含JSP脚本,这是         SUN的JSP2.0新规范,使用SimpleTag接口的标签处理器类必须声明内容是scriptless的!)

3.     在jsp页面中使用<%@taglib>声明导入tld文件。

       <%@tagliburi=”http://www.itheima.com” prefix=”mytag”%>

       其中uri对应的是tld文件所声明的uri名称空间。

       Prefix声明了在此jsp页面中对应tld标签集的标签名。

       如此声明后可使用<mytag:tagname>来调用具体的标签。

2.     Tag接口的两个子接口

       1.     IterationTag   增加了doAfterBody()方法声明,此方法在每次执行完标签体(body)内容后都会被执行。

      2.   BodyTag    在IterationTag的基础上增加了两个方法doInitBody()和setBodyContent(BodyContent b)

3.   实现Tag接口的标签处理器总的生命周期:

      1.JSP解析器发现<%@tagliburi=”” prefix=””>声明,会将prefix标签绑定到uri所指定的tld文件中。

      2.在遇到自定义标签时,JSP解析器会在tld文件中查找<tag>标签,匹配<name>属性,并根据<tag-class>所指定的限定名找到class文件。

      3.判断该标签处理器类是否已被实例化。若无,实例化之,并放入缓存中。若有,则直接从缓存中取出。故传统的标签处理器(仅限于实现Tag接口的处理器)也是享元的运行模式(与servlet一样)

      4.调用处理器的setPageContext()与setParent()方法,为处理器设定当前标签的属性。

      5.调用doStartTag()方法。

      6.(BodyTag)调用setBodyContent()方法。

      7.(BodyTag)调用doInitBody()方法。

      8.翻译和执行标签体。

      9.(IterationTag)调用doAfterBody()方法。

      10.调用doEndTag()方法。

      11.在虚拟机关闭时执行release()方法。

在实现类中(TagSupport,IterationTagSupport,BodyTagSupport)的可用对象:

1.    在实现类中的整个生命周期中都使用pageContext对象。用此对象可获得jsp页面的所有隐式对象。

2.    整个生命周期中都可调用getParent()获得父标签所对应的对象。(应用:if-else中通过父标签的flag来确定是否执行)。

3.   (BodyTagSupport)进入Body的生命周期后,可通过bodyContent对象来获取标签体的执行结果。这是一个缓冲的Writer,但在底层没有任何出口,仅仅缓冲标签体的输出结果。我们需要调用其上的getReader()(以输入流的形式读取)getString()(以字符串形式读取)writeOut(Writer out)(直接输出到输出流中)来处理其输出结果。要是我们什么都不做,标签体的输出结果是看不到的。注意的是其toString方法仅仅输出类名和内存地址,一定要与getString区分!

 

实现了Tag接口的标签处理器类的生命周期控制


      1.doStartTag()
方法:

           *    返回Tag.EVAL_BODY_INCLUDE:    指示处理器直接将标签体内容输出到out对象中。

                 若处理类实现了BodyTag接口,则不会触发doInitBody,setBodyContent方法,而完            全表现为IterationTag。

           *    返回Tag. SKIP_BODY:指示处理器直接跳过标签体的处理,直接调用doEndTag()

(BodyTag)*  返回BodyTag. EVAL_BODY_BUFFERED:指示处理器创建新的BodyContent对象,并调                             用setBodyContent方法设置bodyContent对象,将标签体内容输出                                   到其中,便于处理。

      2.doAfterBody()方法:

              *     返回IterationTag. EVAL_BODY_AGAIN:重新执行标签体一次,并执行doAfterBody

              *     返回Tag. SKIP_BODY:跳出标签体,执行doEndTag()方法。

(BodyTag) 若在doStartTag()方法中返回了BodyTag. EVAL_BODY_BUFFERED,则在doAfterBody                    中返回Tag. SKIP_BODY时会清空out中所有在Body生命周期内写入的内容。                           也就是说,tomcat会保证在执行标签体期间不会有任何内容直接地写入到页面                      中。所以要注意的是必须复写doEndTag()方法,并在其中调用bodyContent对                            象的方法提取标签体的输出信息。doAfterBody()只能做循环条件的判断,而不                      能做输出信息的处理和打印。

      3.doEndBody()方法:

                 返回Tag. EVAL_PAGE:继续执行余下的jsp文件内容。

                 返回Tag. SKIP_PAGE:跳过余下的jsp文件内容,直接结束整个jspservlet!

                 特别的,对于BodyTag的标签处理器来说,若使用BodyTag. EVAL_BODY_BUFFERED,                 也就是用bodyContent缓存标签体的输出,则必须在doEndBody中获取,处理并输出                标签体输出。

 

 

 

简单的Tag接口

1.   无论是SimpleTag还是Tag,都继承自JspTag接口,这是一个无内容的标记接口。

2.   SimpleTag类有以下5个方法:

1) doTag()                      在Tag处理器实例化后运行,是简单Tag类的整个生命周期

2) getParent()                 用于获取父标签对象

3) setJspBody()               简单Tag处理器实例化时传入的标签体信息

4) setJspContext()           简单Tag处理器实例化时传入页面信息pageContext

5) setParent()            简单Tag处理器实例化时传入其父标签的对象。

3.   SimpleTag类的生命周期

1.   在tld文件中的声明和在jsp页面中标签的引入和使用与传统Tag类一样。

2.   每次生成页面文件时(运行一次jspservlet.service)都会新建一个简单标签处理器。也就是说每个简单标签处理器都是独立的局部变量

3.   调用setJspContext()和setParent()方法设置处理器的页面信息和父标签信息。

4.   如果存在标签体,则调用setJspBody()方法。

5.   调用doTag(),所有标签体内的逻辑判断,迭代,运算等操作都在此内执行。

6.   随着doTag()结束,此简单标签处理器对象声明周期结束,随时被垃圾回收。

4.   SimpleTag类的细节:

      一般继承SimpleTagSupport类。

      一般可对getJspContext()的返回值转型为PageContext,直接当作pageContext使用,但是要时刻小心。

      调用getJspBody().invoke()执行一次标签体。向其中传入Writer缓冲输出数据。一般可传入StringWriter,用toString即可取出缓冲区的值。

      调用getJspBody.invoke()时向其传入null,则可直接向pageContext.out中输出。

      若预计此标签内会嵌套其他子标签,即使此标签本身不需要输出任何内容,都要调用getJspBody.invoke(null),否则子标签的内容都无法输出。因为子标签属于父标签的标签体

 

标签属性的声明和获取

无论是传统标签处理器(Tag),还是简单标签处理器(SimpleTag),获取标签属性的方法都是一样的:

在标签处理器类中以JavaBean规范建立标签属性的setter:如属性名为var,则建立setVar(String)方法。另外,在tld文件中的<tag>标签内必须声明对应属性的名称等信息。如:

<attribute>

    <name>items</name>                               设定属性的名称(必须指定)

    <required>true</required>                   设定属性是否必需(默认false)

    <rtexprvalue>true</rtexprvalue>               设定属性是否支持运行时动态表达式(默认                                                 为false)。

</attribute>

通常要声明这三个属性。

如此之后,jsp解析器会根据tld文件的声明调用标签处理器类对应的setter方法,传入属性名对应的值。需要特别注意的是,由于传统标签处理器采用享元的设计模式,所以在并发访问时,肯定会导致标签属性值的错乱。故一定要非常小心地上锁!

 

 

*自定义标签库的打包:

1.建立普通的JavaProject,把标签处理器包复制到其中。

2.在Project中建立META-INF目录,将tld配置文件放在其中。

3.导出jar包。

4.以后要使用时,放入WebProject的\webroot\WEB-INF\lib中,即可自动导入。

5.需要注意的是,现在的tomcat6.0还不支持简单标签处理器SimpleTag类。所以要建立自己的标签处理器包,必须用传统的标签处理器

 

 

 

JSTL核心标签

1.   要特别注意JSTL核心包的版本号,必须是1.1的,

      名称空间为http://java.sun.com/jsp/jstl/core(1.0版本的不带jsp/部分)

2.   <c:out>标签:将value属性值输出到页面中。用escapeXml(true|false)属性设定是否进行HTML编码转换(<,>,&,,, )的转义。默认为true。用于Html代码的转义原样输出。

3.   <c:set>标签:用于设定属性。

      两个用处: 1)用于设定域属性

                      <c:setvar=name scope=page|request|session|application value=value>

                      再次注意的是page域和jsp中page对象的区别!(前者是一个域,代表是当前的页                           面,后者是jsp中的this,代表整个servlet。

                      2)用于设定Map或JavaBean的属性。

                      <c:setproperty=属性名 target=对象(EL表达式取出) value=属性值>

      出现的问题 使用EL表达式时出现的问题:忘记将建立的Map放入域中,当然无法用EL表达式取                   出。

                      测试JavaBean时出现的问题:企图建立一个内部类,但这个内部类是要交给Bean的                   内省器进行解析的。所以要保证这个内部类的可见性!首先,若放入<%%>标签内,则                 成为jspservlet的service方法的一个内部类,方法外都是不可见的!所以一定要                          放入<%! %>标签内,用jsp声明使得其成为jspservlet的一个内部类,而且这个类                       必须是public的!否则内省器无法访问!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值