自定义“Hello, world”JSP 标记最常见的需求就是能够接受来自某个页面(或者页面作者)的数据,并响应该数据。标记 attributes允许我们将这种功能性融入到自定义标记中。
举个非常简单的例子,比如典型的“Hello, world”应用程序。很容易想象实现这一 scriptlet 的功能性的自定义标记是什么样子,但是,对这个标记作一点点扩展如何?
在清单 1 中我们可以看到一个 JSP 页面片段,其中有一个典型的“Hello, world!”标记,但是这个标记包括了一个名为 name 的属性。
清单 1. 一个简单的 "Hello, world!" 标记1
2
3
| <p>
<examples:hello name="Reader" />
</p>
|
name 属性为页面作者将数据提供给 hello 标记创造了空间,在这个例子中,所提供的数据是一个人的名称,应用程序将把它的消息转播给这个人。实际上,我们已经自定义了“Hello,world” ―― 但我们是怎样进行定义的呢?清单 2 显示了用于实现 hello 标记的 Java 代码 :
清单 2. hello 标记的代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| package com.ibm.examples;
import java.io.IOException;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
public class HelloTag extends TagSupport {
// The "person" to say hello to
private String name;
// Accept the attribute data
public void setName(String name) {
this.name = name;
}
public int doEndTag() {
try {
StringBuffer message = new StringBuffer("Hello, ");
message.append(name)
.append("!");
pageContext.getOut().println(message.toString());
} catch (IOException ignored) { }
return EVAL_PAGE;
}
|
清单 2 中的代码对于它所做的事情非常简单。我们只是添加了一个 setXXX() 方法,其中 XXX 指的是该属性的名称,但正是由于这一添加,我们便已大大扩展了 hello 标记的功能性。现在,页面作者可以为特定用途设置自定义数据,该数据可以根据需要进行保存、操纵或者激活。 doEndTag() 方法允许我们以任何方式使用标记数据。
现在,让讨论更深入一点,看看当我们添加一个属性到 lastModified 标记时会发生什么情况。
扩展 lastModified 标记 我们希望页面作者能够设置他们想要的输出格式(最后修改数据),而不是只有一种显示选择。我们将从后端开始,首先扩展 lastModifiedTag 类, 使其包括一个 java.text.SimpleDateFormat 以用于输出格式化,如清单 3 所示:
清单 3. 在 LastModifiedTag 类中使用 SimpleDateFormat1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| package com.newInstance.site.tags;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.tagext.TagSupport;
public class LastModifiedTag extends TagSupport {
private String format = "MMM d, yyyy";
public int doEndTag() {
try {
HttpServletRequest request =
(HttpServletRequest)pageContext.getRequest();
String path = pageContext.getServletContext().getRealPath(
request.getServletPath());
File file = new File(path);
<span class="boldcode">DateFormat formatter = new SimpleDateFormat(format);</span>
pageContext.getOut().println(
formatter.format(new Date(file.lastModified())));
} catch (IOException ignored) { }
return EVAL_PAGE;
}
}
|
在清单 4 中,我们将新的格式化功能添加到 lastModified 标记中,这是通过添加一个属性办到的。注意, format 属性的值与 中新引入的 format 方法变量是联系在一起的。
清单 4. 处理新属性1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| package com.newInstance.site.tags;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.tagext.TagSupport;
public class LastModifiedTag extends TagSupport {
private String format = "MMM d, yyyy";
public void setFormat(String format) {
this.format = format;
}
public int doEndTag() {
try {
HttpServletRequest request =
(HttpServletRequest)pageContext.getRequest();
String path = pageContext.getServletContext().getRealPath(
request.getServletPath());
File file = new File(path);
DateFormat formatter = new SimpleDateFormat(format);
pageContext.getOut().println(
formatter.format(new Date(file.lastModified())));
} catch (IOException ignored) { }
return EVAL_PAGE;
}
}
|
实现细节format 属性允许页面作者按照自己的喜好设置日期/时间的输出格式。不过,在使用这个新属性之前,我们必须在TLD 文件(这个文件应该是 WEB-INF/tlds 目录下的 site-utils.tld)中作一点修改,如清单 5 所示:
清单 5. 修改 TLD1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| <?xml version="1.0" encoding="ISO-8859-1"?>
<!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>site-utils</short-name>
<uri>http://www.newInstance.com/taglibs/site-utils</uri>
<tag>
<name>lastModified</name>
<tag-class>com.newInstance.site.tags.LastModifiedTag</tag-class>
<body-content>empty</body-content>
<span class="boldcode"><attribute>
<name>format</name>
</attribute></span>
</tag>
</taglib>
|
默认值更新了 TLD 之后,我们应该可以开始使用新属性了,那么让我们来测试一下吧。重新启动 servlet 容器,以确保 servlet 容器接受了新的标记和TLD 更改,然后连上带有 lastModified 标记的页面。
千真万确,时间戳出现了。但是我们可以看到,输出的格式与之前没什么两样。问题就在于没有添加新的 format 值,因此我们所看到的格式与老格式是一样的。这个小测试展示了为 format 属性添加默认值(在这个例子中,就是您马上要看到的那个格式)的重要性。
为自定义属性添加一个默认值是一种很好的思想,因为这使得页面作者在不想提供他们自己的值时可以省点力气。在某些情况下,页面作者可能会很高兴使用默认值;在其他一些情况下,他们可能需要花点时间来了解新的属性和格式,在这段时间内,暂时使用默认值是很有必要的。不管是哪种情况,通过为标记添加自定义属性来创建选项,并为执行某种功能的页面提供默认的行为,这样做才是良好的编程习惯。
包装起来当然,我们做这么多事情并不是漫无目的的!清单 6 显示了 footer.jsp ,这个文件来自原有的那个时间戳实例(参见 “ ” ),不过这里为 format 属性提供了一个值:
清单 6. 使用 format 属性1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| <%@ 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 -->
<!-- Begin footer section -->
<tr>
<td width="91" align="left" valign="top" bgcolor="#330066"> </td>
<td align="left" valign="top"> </td>
<td class="footer" align="left" valign="top"><div align="center"><br>
© 2003
<a href="mailto:webmaster@newInstance.com">Brett McLaughlin</a><br>
Last Updated: <site-utils:lastModified
<span class="boldcode">format="HH:mm a zz :: MM/dd/yyyy"/></span>
</div></td>
<td align="left" valign="top"> </td>
<td width="141" align="right" valign="top" bgcolor="#330066"> </td>
</tr>
</table>
<!-- End footer section -->
|
虽然我们完成了一个良好的开端,但我们还只是简要地描绘了关于处理自定义标记中的属性的一些表面的东西。在下一期的 JSP 最佳实践中,我们将讨论一些更复杂的场景,这些场景都是您在创建自定义的、可扩展的时间戳标记时可能遇到的――例如错误处理和对不同时区的处理。同时,还将看到为不同类型的功能使用自定义属性的实践,到时候网上见。 |