JSP中标签库的深入研究

 
JSP 中标签库的深入研究
标签库 Taglib

标签被定义和分布在一个称为标签库的结构中,一个标签库是由元信息和类组成的集合:
1.
标签处理器:实现定制标签功能的 Java 类。
2.
标签附加信息( TEI ):向 JSP 容器提供边辑以确认标签属性和创建变量的类。
3.
标签库描述器( TLD ):描述单个标签和整个标签库属性的 XML 文档。

标签处理器和标签附加信息需要定位在 JSP 容器类载入器可以找到的地方。标签库描述器可在 URL 指定的符意位置。 JSP1.1 规范要求 JSP 容器接受一个打包成因定结构的 JAR 文件的标签库。 TLD 必须是 /META-INF 目录中名为 taglib.tld 的文件, JAR 文件则复制到 /WEB-INF/lib 目录下。

一、标签实现

1.
开发步骤
a.
定义标签的名字、属性、声明的变量和标签体的内容。
b.
编写标签库描述器 TLD
c.
编写标签处理器。
d.
JSP 页面中使用标签。

2.JSP
页面在 JSP 容器中的转换步骤:
JSP
页面存在三种形式: jsp 文件、 java 文件和 class 文件。
a.
指令元素 、 和 向 JSP 容器提供转换时信息。
b.HTML
行在 _jspService() 方法中依顺序转换到 out.print() 语名中。
c.
脚本元素的声明被原封不动地复制到 _jspService() 方法外的源码中。
d.
脚本元素的表达式在 _jspService() 方法中依顺序转换到 out.print() 语名中。
e.
脚本元素的 Scriptlet 被原封不动地复制到 _jspService() 方法中。
f.
行为元素被转换为执行其功能的运行时逻辑代码。
g.
定制标签被扩展到调用其相应标签处理器中方法的 Java 语句中。

3.
标签在 JSP 容器中的转换步骤:
a.JSP
容器使用 taglib 指令元素定位标签库描述器,将页面中用到的定制标签和 TLD 相匹配。
b.
读取标签库描述器的标签列表和每一标签相关的类名字。
c.
在页面中遇到一个标签时,查找与具有指定名字的标签前缀相关的一个标签库。
d.
容器使用在 TLD 中找到的标签结构信息生成一系列完成标签功能的 Java 语句。


二、标签库描述器( TLD

标签库描述器是一个描述整个标签库标记信息和库中每个标签处理器及其属性的 XML 文档。

标签库描述器的 DTD 由一个简单的 元素组成,此元素包含下列一些子元素。
整个标签库标记信息
tlibversion    
标签库版本号。是一个点式十进制数,最多为 4 组小数点分隔的数字组成。
jspversion    
标签库所需的 JSP 规范最低版本。例如 JSP1.1
shortname    
标签库的缩写名。 JSP 可以使用该名字作为库中标签的缺省前缀。
uri    
标签库唯一 URI 的元素。典型 URL 位置来自可下载 taglib 的位置。
info    
标签库描述信息。
每个标签处理器及其属性
tag    
TLD 中加入标签,描述组成库的每个标签。
name    
与标签库的名字前缀一起使用的标签的名字,  JSP 容器唯一的标签标识。
tagclass    
实现标签的标签处理器类的全名。
teiclass    
标签附加信息( TEI )类的全名。 TEI 类给出关于标签处理器创建变量及对标签司性执行的任意有效性验证的信息。
bodycontent    
描述标签处理器如何使用标签体的内容。有三种取值:
    empty
:表示标签体必须为空;
    JSP:
表示脚本元素和模板及其它标签一样被评估。
    tagdependent
:体内容被原封不动写入 BodyContent ,其它脚本元素以源码形式出现,而不被 JSP 容器解释。
info    
标签的人工可读描述性信息。
attribute    
使用标签时被编码的属性信息。用于定义标签的属性。
    
属性名:属性的名字。
     true|false
:属性在标签用到的位置是否要被编码。
     true|false
:属性值能否用表达式指定。

三、标签处理器

标签处理器是通过实现 JSP 容器调用的一系列预定义方法执行定制标签行为的一个 Java 类。
标签处理器实现了标签的行为,标签处理器是 Java 类。

1.
标签处理器的工作方式
a.
导入 javax.servlet.jsp javax.servlet.jsp.tagext 包。
b.
实现 javax.servlet.jsp.tagext 包中的 Tag 接口或 BodyTag 接口。 BodyTag Tag 的子接口。
c.
继承 TagSupport 类或 BodyTagSuppoert 类。它们是上述接口的缺省实现。
d.
重载 public int doStartTag()throws JspException 方法。

2.
标签处理器的接口与实现
javax.servlet.jsp.tagext.Tag
是实现标签的最基本的接口。
javax.servlet.jsp.tagext.TagSupport
是实现 Tag 接口的具体类。
通常情况下继承 tagSupport 类而不直接实现 Tag 接口通常是有益的。除了对所有必需方法提供了缺省实现外、还保存了 pageContext 对象及对嵌套标签的支持。
Tag
接口包含 4 个常量,表示 doStartTag() doEndTag() 方法可能的返回码。
EVAL_BODY_INCLUDE    
doStartTag() 返回时,指明 servlet 应对标签体进行评估。
SKIP_BODY    
doStartTag() 返回时,指明 servlet 应忽视标签体。
EVAL_PAGE    
doEndTag() 返回时,指明页面其余部分应被评估。
SKIP_PAGE    
doEndTag() 返回时,指明页面其余部分就被跳过。
Tag
接口的方法
public void setPageContext (PageContext ctx)    
生成的 servlet 在请求处理器执行其它任务前首先调用此方法,实现类应保存上下文对象以便它可以在标签生命期中使用。从页面上下文中标签处理器可以访问所有 JSP 隐含对象。
public void setParent(Tag p)    
使用一个标答可以找到操作栈中它上面的标签。在 setPageContext 后立即调用。
public Tag getParent()    
返回父标签。
public int doStartTag() throws Jsp    
在设置了页面上下文、父标签和开始标记中编码的属性后调用。返回码表明 JSP 实现 servlet 是否就评估标签体。
public int doEndTag()throws JspException    
当遇到结否标记时调用。返回码表明 JSP 是否就继纽页面的其余部份。
public void release()    
确保在页面退出前被调用。释放资源并重置标签处理器状态。
TagSupport
类的方法
public static Tag finAncestorWithClass(Tag thisTag, Class cls)    
为所需的父标签处理器查找运行时标签栈。一个标签处理器可以提供其范围内子标签调用的方法。
public void setId(String id)    
保存和检索在 id 属性中指定的名字。
public void setValue(String name, Object o)    
在本地哈希表中设置指定名字的值。
public Object getValue (String name)    
从本地哈希表中获取指定名称的值。
public void removeValue (String name)    
从本地哈希表中删除指定名称的值。
public Enumeration getValues()    
返回哈希表中关键字的一个枚举。
3. 标签处理器的生命期
a.
生成 servlet 需要创建标签处理器类的一个实例。实现方式通常是调用 JSP 容器的工厂类的一个方法,工厂类包含一个标签处理器实例池以使其可重用不再处于激活状态的对象。
b.
初始化标签处理器,使 servlet 获知其存在性。 servlet 通过调用标签处理器的两个方法实现此过程: setPageContext(PageContext ctx) setParent(Tag parent)
c.
如果标签具有属性,属性的取值通过处理器提供 setter 方法传入到对象。属性 setter 方法是一个标签支持属性所需的唯一方法。
d.
页面的上下文和父标签已被调置,并已具备属性。此时调用标签处理器的 doStartTag() 方法,该方法可以读取这些变量并执行实现标答功能所需的计算和操作。 doStartTag() 方法必须返回一个整型数。返回 EVAL_BODY_INCLUDE 则正常处理标签体,返回 SKIP_BODY 则从初始 JSP 页面中直到此标签结束标记处的内容均被忽略。
e.
标签体被评估或忽视后调用标签处理器的 doEndTag() 方法,返回 EVAL_PAGE 则页面的其余部分被评估,返回 SKIP_PAGE servlet 代码立即从 _jspService() 中返回。

4.
体标签处理器的接口与实现
javax.servlet.jsp.tagext.BodyTag
Tag 的子接口。
javax.servlet.jsp.tagext.BodyTagSupport
是实现 BodyTag 类。
BodyContent
javax.servlet.jsp.JspWriter 的子类,但与其父类有所区别。
BodyContent
对象的内容不自动写了入 servlet 的输出流,而是积累在一字符串缓存中。当标签体完成后其对象仍可在 doEndTag() 方法中可以应用,由 getString() getReader() 方法操作。并在必要时修改及写入恢复的 JspWriter 输出流。
BodyContent
类的方法
public void flush()throws IOException    
复写 JspWrite.flush() 方法以便它总是产生溢出。刷新写入已失效,因为它没有连接到将被写入的实际输出流中。
public void clearBody()    
重置 BodyContent 缓存为空。
public Reader getReader()    
返回 Reader 读取体内容。
public String getString()    
返回包含体内容的一个字符串。
public void writeOut(Write w)    
将体内容写入指定输出。
public JspWrite getEnclosing Write()    
返回栈中下一个更高的写入者对象(可能是另一个 BodyContent 对象)。
BodyTag
接口定义了一个新的整型常量
EVAL_BODY_TAG    
doStartTag() 返回时,使得新的 BodyContent 对象被创建并与此标签处理器相关联。当 doAfterBody() 返回时,使得 JSP servlet 在修改完此标签控制的任意变量后再次评估体。
BodyTag
接口的方法
public void setBodyContern (BodyContent out)    
在当前 JspWriter 已被写入,一个新的 BodyContent 在被创建后由 Jsp servlet 调用,它发生在 doStartTag() 之后。
public void doInitBody() throws JspException    setBodyContent()
之后,体被评估前调用的生命期方法。如果多次评估体,此方法只调用一次。
public init doAfterBody() throws JspException    
体被评估后, BodyContent 写入者仍处于激活状态时调用的生命期方法。此方法必须返回 EVAL_BODY_TAG SKIP_BODY ,若返回 EVAL_BODY_TAG 时体再次被评估。
BodyTagSupport
类的方法
public int doStartTag() throws JspException    
复写 TagSupport 中的 doStartTag() 方法。
public int doEndTag() throws JspException    
调用 TagSupport 中的 doEndTag() 方法,返回结果。
public void setBodyContent (BodyContent out)    
在一保护成员变量 bodyContent 中保存新的体内容对象,子类可直接访问此对象。
public void doInitBody() throws JspException    
缺省什么都不做。被需要执行初始化的子类所复写。
public int doAfterBody() throws JspException    
每次体被评估后由 JSP servlet 调用,体同容对象仍处于激活状态。返回 SKEP_BODY EVAL_BODY_TAG 则体再次被评估
public void release()    
设置 bodyContent 对象为 null ,然后调用 super.release()
public BodyContent getBodyContent()    
返回 bodyContent 变量。子类已经可以访问保护变量,但此方法允许无关的标签处理类对此体内容发送输出。
public JspWriter getPreviousOut()    
bodyContent 变量上调用 getEnclosingWriter() 并返回结果的简便方法。

5.
体标签处理器的生命期

a.
生成 servlet 需要创建标签处理器类的一个实例。实现方式通常是调用 JSP 容器的工厂类的一个方法,工厂类包含一个标签处理器实例池以使其可重用不再处于激活状态的对象。
b.
初始化标签处理器,使 servlet 获知其存在性。 servlet 通过调用标签处理器的两个方法实现此过程: setPageContext(PageContext ctx) setParent(Tag parent)
c.
如果标签具有属性,属性的取值通过处理器提供 setter 方法传入到对象。属性 setter 方法是一个标签支持属性所需的唯一方法。
d.
页面的上下文和父标签已被调置,并已具备属性。调用标签处理器的 doStartTag() 方法,该方法可以读取这些变量并执行实现标答功能所需的计算和操作。
doStartTag()
方法必须返回一个整型数。
返回 EVAL_BODY_TAG 则正常处理标签体(跳到 e );
返回 SKIP_BODY 则从初始 JSP 页面中直到此标签结束标记处的内容均被忽略。(跳到 f
e.
如果返回 EVAL_BODY_TAG 时,则正常处理标签体。
    e1.
在栈中保存当前的 JspWriter 对象,创建新的 BodyContent 对象,并将其置为 JSP 页面的 out 对象保存在上下文范围内名为 name 的属性中。并调用它的 setBodyContent() 方法。
    e2.
调用 doInitBody() 方法进行初始化。
    e3.
处理标签体。将输出写入 BodyContent 对象中,此过程依赖于 TLD 的标签元素 ,有三种可能取值。
    e4.
调用 doAfterBody() 方法,将体内体内容写入 JspWriter ,可如下实现:
JspWriter out=bodyContent.getEnclosingWriter();
out.println(bodyContent.getString());//bodyContent.writeOut(out);
bodyContent.clear();
    e5.doAfterBody()
方法返回两种可能:
返回 EVAL_BODY_TAG 时,再对标签体进行评估,这是数组和枚举被循环处理的典型情况。
    
返回 SKIP_PAGE 时,继续页面的其余部份。
e6.
体内容完成,因此创建它的过程被反向:
    
调用 pageContent.popBody() 方法检索前面的 JspWriter 对象。
    
将写入者设置回 out 隐含对象。
f.
标签体被评估或忽视后调用 doEndTag() 方法,允许标签处理器像输出流发回内容。
返回 EVAL_PAGE 则页面的其余部分被评估;
返回 SKIP_PAGE servlet 代码立即从 _jspService() 中返回。
g. 
此时体的内容在受保护的 bodyContent 对象中仍然可用。
可以将它写入 servlet 输出流中:
JspWriter out=pageContext.getOut();
out.println(bodyContent.getString());
或者
bodyContent.WriteOut(pageContext.getOut());

6.
标签附加信息类


四、标签指令

taglib
指令元素的目的是指定 TLD 的位置,设置在页面上与标签区分开来的一个短别名。
语法:
属性: prefix :用于标识标签库的唯一标识。 uri :标签库本身的 URI
uri
不必指向一个实际文件,它是 JSP 容器可以在 web.xml 中查找实际文件位置的唯一标识符。
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值