jsp页面标签定义:
实现行为
实现标记行为的第一步是将scriptlet代码从原先所在的地方移到一个Java类( LastModifiedTag )中,如清单 1 所示:
清单 1. 创建一个时间戳标记
package com.jrcz.aura.util;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.tagext.TagSupport;
/*
* 编写标签对应的实现类时,需要重载BodyTagSupport类几个方法:doStartTag(), setBodyContent(),
* doInitBody(), doAfterBody(), doEndTag();
* 他们执行顺序如下:doStartTag()→doInitBody()→setBodyContent()→doAfterBody()→doEndTag()
* doStartTag()方法可返回EVAL_BODY_INCLUDE或SKIP_BODY,如果返回EVAL_BODY_INCLUDE则继续执行;
* 如果返回SKIP_BODY则接下来的doInitBody(),setBodyContent(), doAfterBody()三个方法不会被执行,
* 而直接执行doEndTag()方法
* setBodyContent()方法用于设置标签体内容,如果在此之前要作一些初始化工作,则在doInitBody()方法中完成
* 标签体内容执行完后,会调用doAfterBody()方法,此方法可返回EVAL_BODY_TAG, SKIP_BODY, EVAL_PAGE或SKIP_PAGE。
* 如果返回EVAL_BODY_TAG则会再次设置标签体内容,直到返回SKIP_BODY;
* 如果返回EVAL_PAGE则标签体执行完后会继续执行JSP页面中接下来的部分;
* 如果返回SKIP_PAGE,则JSP页面的后续内容将不再执行。
* 标签中静态常量:
EVAL_BODY_INCLUDE:告诉服务器正文的内容,并把这些内容送入输出流
SKIP_BODY:告诉服务器不要处理正文内容
EVAL_PAGE:让服务器继续执行页面
SKIP_PAGE:让服务器不要处理剩余的页面
EVAL_BODY_AGAIN:让服务器继续处理正文内容,只有doAfterBody方法可以返回
EVAL_BODY_BUFFERED:BodyTag接口的字段,在doStartTag()返回
EVAL_BODY_INCLUDE、SKIP_BODY一般由doStartTag()返回,而EVAL_PAPGE、SKIP_PAGE由doEndTag()返回。
*/
public class LastModifiedTag extends TagSupport{
public int doEndTag(){
try {
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
String path = pageContext.getServletContext().getRealPath(request.getServletPath());
File file = new File(path);
DateFormat formatter = DateFormat.getDateInstance(DateFormat.LONG);
pageContext.getOut().println(formatter.format(new Date(file.lastModified())));
pageContext.getOut().println("你好你好");
System.out.println("path:"+path);
} catch (IOException e) {
e.printStackTrace();
}
return EVAL_PAGE;
}
}
这个方法中的代码看上去比较熟悉;实质上,它正是我们在先前用到的相同的时间戳代码。由于不需要用户输入,而且该标记也没有属性或者嵌入的内容,我们惟一需要关心的一个新方
法就是 doEndTag() (),在这个方法中该标记可以输出内容(在这个例子中是最后修改数据)到JSP页面。
清单 1 中其他的更改更多地与作为一个JSP标记的代码有关,而与在一个页面内运行的scriptlet没有多大关系。例如,所有的JSP标记都应该扩展JSP类
javax.servlet.jsp.tagext.TagSupport ,这个类为JSP标记提供了基本框架。可能您还注意到 ,该标记返回的 EVAL_PAGE . EVAL_PAGE 是一个预定义的整型常量,它指示容器处理页面
的剩下部分。另一种选项就是使用 SKIP_PAGE ,它将中止对页面剩下部分的处理。如果您要将控制转移到另一个页面,例如您要前进(forward)或者重定向(redirect)用户,那么只
需要使用 SKIP_PAGE 。剩下来的细节都是与时间戳自身有关的事情。
接下来,编译这个类,并将 LastModifiedTag.class 文件放到一个WEB-INF/classes 目录下,注意要放到正确的路径层次结构中。这个路径应该匹配该标记的包名,包名中的圆点(.)
用斜杠(/)代替。在本例中,目录的路径是基路径(WEB-INF/classes)再加上层次结构com/newInstance/site/tags。如果有一个名为 foo.bar.tag.MyTag 的标记,那么它将被放在
WEB-INF/classes/foo/bar/tag中。这种路径层次结构确保了Web容器在任何需要装载该标记的时候都能够找到这个类。
回页首
创建TLD
接下来的一步是创建一个 标记库描述符(tag library descriptor ,TLD)文件。TLD向容器和任何要使用该标记库的JSP页面描述您的标记库。清单 2 显示了一个非常标准的TLD,其中
只包含了一个标记。当您将更多的标记添加到库中时,TLD文件的长度和复杂性将随之增长。
清单 2. 一个标记库描述符
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2/EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>gpb</short-name>
<uri>http://www.newInstance.com/taglibs/site-utils</uri>
<tag>
<name>lastModified</name>
<tag-class>com.jrcz.aura.util.LastModifiedTag</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
TLD 文件顶部的信息应用于整个标记库。在本例中,我提供了一个版本(这对于跟踪某个标记库的JSP创建者拥有哪个版本很有用,尤其是在您需要经常修改标记库的情况下更是如此);
该标记库所依赖的JSP版本;一个为该标记库推荐的前缀;以及用于引用这个标记库的URI。注意,我使用了前缀 short-name 作为URI的一部分,这样 比较容易将前缀和标记库的URI看成
一个整体。
剩下的信息用于一个特定的标记,这些信息用 tag 元素表示。我指定了该标记的名称、用于该标记的类(这个类应该被编译好并放在适当的地方,以便容器能够装载),最后还指定了该
标记是否有嵌入的内容。在本例中,标记没有嵌入的内容,因此使用"empty"。
保存这个文件,并将其放到WEB-INF/tlds目录下(您可能需要在您的容器中创建这个目录)。我将这个文件保存为site-utils.tld,并在该标记库的URI(推荐的前缀)和TLD文件本身之
间再次创建一个干净的链接。对于这个特定的标记库,要使其可以使用,最后一步要做的是让您的Web应用知道如何连接一个JSP页面中的URI,如何请求使用一个标记库。这可以通过应用
的web.xml文件来做。清单 3 显示了一个非常简单的web.xml片段,正是 它为我们的标记库做这样的事情。
清单 3. 将一个URI与一个标记库链接起来
<taglib>
<taglib-uri>http://www.newInstance.com/taglibs/site-utils</taglib-uri>
<taglib-location>/WEB-INF/tlds/site-utils.tld</taglib-location>
</taglib>
回页首
包装起来
如果您已经按照上述步骤执行了,那么现在您应该能够在JSP页面中引用新标记了。清单 4 向我们展示了新改进的footer.jsp,这个文件中现在完全没有scriptlet,也没有指向具有
scriptlet的JSP页面的引用。
清单 4. 使用新的标记库
<%@ taglib prefix="site-utils"
uri="http://www.newInstance.com/taglibs/site-utils" %>
</td>
<td width="16" align="left" valign="top"> </td>
</tr>
<!-- End main content -->
<div id="divab"></div>
<div>自定义标签</div>
<gpb:lastModified />
在前面几期中看了JSTL如何工作(参见“ 利用JSTL更新您的JSP页面”和“ 导入内容到您的Web站点”)之后,接下来该做什么您应该很清楚了:我们通过使用web.xml文件中的URI来引
用这个标记库,为之分配一个前缀(来自TLD的 short-name 始终是最好的选择),然后就像使用任何其他JSP标记一样使用这个标记。最终得到的是一个简洁的、更好的JSP页面,这个
JSP页面运行起来不比有 scriptlet 的时候差。