Head First JSP---随笔八(简单标记)

11 篇文章 0 订阅
11 篇文章 0 订阅

定制标记开发

有时JSTL和标准动作还不够。构建自己的标记处理器有3种不同的方法。在这3种方法中,有两种(简单标记和标记文件)是在JSP 2.0新引入的。


建立定制标记库

10.1 描述执行各个事件方法(doStartTag()、doAfterBody()和doEndTag())时“传统”定制标记事件模型的语义;解释各事件方法返回值的含义,并编写标记处理器类。
10.2 使用PageContext API,编写标记处理器来访问JSP隐式变量以及Web应用属性。
10.3 给定一个场景,编写标记处理器代码来访问父标记和任意的祖先标记。
10.4 描述执行事件方法(doTag())时“简单”定制标记事件模型的语义;编写一个标记处理器;并解释标记中对JSP内容的限制。
10.5 描述标记文件模型的语义:描述标记文件的Web应用结构;编写一个标记文件;解释标记体中对JSP内容的限制。


标记文件

利用标记文件,可以使用一个定制标记调用可重用的内容,而不是使用通用的<jsp:include><c:import>。可以把标记文件看做是一种“轻型标记处理器”,这是因为页面开发人员利用标记文件创建定制标记,而不用表写复杂的Java标记处理类,但是标记文件只是“美化了”的include。
这里写图片描述


对于标记文件,发送的不是请求参数,而是标记属性!

这里写图片描述


标记文件使用attribute指令

与TLD类似,需要指明标记的属性的属性名是什么,是否可选的,是否可以是一个EL**表达式**。
这里写图片描述


如果属性值很大

假设有一个标记属性很长,甚至是一段文字。我们就可以使用<jsp:doBody>
这里写图片描述


声明标记文件的body-content

使用tag指令,有一个属性“body-content”,默认值为“scriptless”。还有另外2个属性值:empty和tagdependent。如果值为scriptless,这说明不能有脚本元素(<%...%>)。

在标记文本的体中不能使用脚本代码!
这里写图片描述


容器在哪里查找标记文件

这里写图片描述


Jar中标记文件的TLD

问:你说过,标记文件没有TLD,还记得吗?不就是因为这个原因才要使用attribute指令吗?因为你没办法在TLD中声明属性,是这样吗?

答:这个问题有点意思,如果把标记文件部署在Jar中,就必须有一个TLD来描述它的位置。但是它并不描述属性、body-content等内容。标记文件的相应TLD项只描述具体标记文件的位置。如下:
这里写图片描述


建立一个简单标记处理器

这里写图片描述


有体的简单标记

这里写图片描述


简单标记的API

这里写图片描述


简单标记处理器的生命期

这里写图片描述


标记体使用表达式

这里写图片描述
上面的${message}将输出“Wear sunscreen.”。


有动态行数据的标记:迭代执行体

这里写图片描述
最后*输出结果是:
这里写图片描述


有属性的简单标记

这里写图片描述


什么是JspFragment?

JspFragment是表示JSP代码的一个对象。它存在的意义就是让别人调用。换句话说,它要运行并生成输出。如果标记调用了一个简单标记处理器,这个标记的体就会封装在JspFragment对象中,然后再setJspBody()方法发送给标记处理器

关键是必须记住,JspFragment中不能包含任何脚本元素!也就是说,可以包含模板文本、标准和制定动作,以及EL表达式,但是不能出现scriptlet、声明或脚本表达式

有一点很棒,因为JspFragment是一个对象,所以可以把这个片段传递给其他辅助对象。这些辅助对象再调用JspFragment的另一个方法getJspContext(),从中得到信息。当然,一旦得到上下文,就可以请求属性。所以getJspContext()实际上是标记体向其他对象提供信息的一个途径

JspFragment的API:
这里写图片描述
对于invoke()方法:
这里写图片描述


SkipPageException:停止处理页面

假设有一个页面调用了标记,而且标记依赖于特定请求属性。下面假设这个标记找不到它需要的属性,它知道如果自己不成功,页面的余下部分就不能正常工作,这个时候你想显示前面部分的内容,后一部分的内容不显示,你该怎么办呢?

这个时候SkipPageException就出来了!如下:
这里写图片描述
会显示异常出现之前的所有内容,如下:
这里写图片描述


如果从一个被包含页面调用标记,会发生什么情况?

如图:pageB调用了抛出异常的标记
这里写图片描述
结果如下:
这里写图片描述
会发现停止页面B的输出,而不影响A的继续处理


一个有趣的问题

这里写图片描述


简单标记要点

  1. 标记文件使用一个页面来实现标记功能,而标记处理器使用一个Java标记处理器类实现标记功能。
  2. 标记处理器有两种类型:传统简单(简单标记和标记文件是JSP 2.0中新增加的)。
  3. 建立简单标记处理器时,要扩展SimpleTagSupport(这个类实现了SimpleTag接口)。
  4. 要部署一个标记处理器,必须创建一个TLD,使用<tag>元素来描述标记,JSTL和其他定制标记库也使用这个元素描述标记。
  5. 如果使用一个有体的简单标记,要保证这个标记的TLD<tag>没有将<body-content>声明为empty。然后调用getJspBody().invoke()来处理体。
  6. 简单标记生命周期:简单标记不会由容器重用,所以每次调用标记时,都会实例化标记处理器,并调用其setJspContext()方法。如果标记本身是从另一个标记中调用,则会调用setParent()方法。如果调用标记时有属性,对于每个属性会调用一个bean式的设置方法(setXxx())。如果调用标记时有体(假设其TLD没有声明它的体为空),则会调用setJspBody()方法。最后,调用doTag()方法,结束时,撤销标记处理器实例。
  7. 只有调用标记时确实有体,才会调用setJspBody()方法。如果调用标记时没有体,不论是空标记<my:tag/>,还是开始和结束标记<my:tag></my:tag>之间没有内容,都不会调用setJspBody()方法。记住,如果标记有体,TLD必须反映出这一点,而且<body-content>的值不能是“empty”。
  8. 简单标记的doTag()方法可以设置标记体使用的一个属性,为此先调用getJspContext().setAttribute(),在调用getJspBody().invoke()。
  9. doTag()方法声明了一个JspException和一个IOException,所以可以直接写至JspWriter,而无需包装在一个try/catch中。
  10. 通过在循环中调用体(getJspBody().invoke()),可以迭代处理简单标记的体。
  11. 如果标记有一个属性,要在TLD中使用<attribute>元素声明这个属性,并在标记处理器类中提供一个bean式的设置方法。调用标记时,会在doTag()之前先调用这个设置方法。
  12. getJspBody()方法返回一个JspFragment,它有两个方法:invoke(java.io.Writer)和getJspContext(),getJspContext()返回一个Jspcontext,标记处理器可以用这个JspContext访问PageContext API(访问隐式变量和作用域属性)。
  13. 如果向invoke()传入null,会把计算的体写至响应输出,不过,如果你想直接访问体内容,可以传入另一个Writer。
  14. 如果你希望当前页面停止处理,可以抛出一个SkipPageException。如果调用标记的页面包含在另一个页面中,尽管被包含的页面在抛出异常之后就会停止处理,但外层页面仍会继续。

简单标记完。。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值