JSP自定义标记入门
时间:2007-04-10 来源:linxh
JSP自定义标记为在动态 Web 页中将页面表示与业务逻辑分离提供了一种标准化的机制,使页面设计者可以将注意力放到页面表示上,而应用程序开发人员则专注于编写后端的代码。您可能听说现在有上百种不同的方式,但是在开发 Web 应用程序时将表示逻辑与业务逻辑分离是很重要的。近年来,Java 平台已经发展为在体系结构层次上加入了这种分离。例如,在 JSP 体系结构中加入 JavaBean 组件使开发人员使用 JSP 标记获得和设置经过特别编码的 java 组件上的属性。这些组件或者 JavaBean 再代表表示层执行后端业务处理。
JSP 自定义标记是 JSP/JavaBean 体系结构的产物。像 JavaBean 技术一样,自定义标记有助于将表示逻辑与业务逻辑分离。并且自定义标记成了 Web 设计者的 HTML、XML 和 Javascript 世界与软件工程师的 Java 代码、SQL 调用和算法世界之间的桥梁。
JSP 自定义标记
JSP 自定义标记 是用户定义的标记,它遵循 JSP JavaBean 标记(即 useBean、getProperty 和 setProperty)所使用的一种特殊的 xml 语法。当 servlet 容器处理自定义标记时,会调用一个或者多个 Java 类文件处理它,与用 Java 类文件处理 JSP 页面的 JavaBean 调用的方式基本一样。处理标记以后,容器将取其名字和属性、以及标记正文中可能有的任何内容,并将它传递给一个或者多个类文件进行处理。
Java 开发人员编写标记处理程序类以处理标记并处理所有需要的 Java 代码和数据操作。对于 Web 设计者来说,自定义标记与标准 html 标记除了都可以利用后端动态数据外,它们看上去与使用起来没什么区别。正确编写自定义标记可以让 Web 设计者创建、查询和操作数据而无需编写一行 Java 代码。正确使用自定义标记使 Java 开发人员不必再在编码过程中考虑表示层。这样应用程序开发小组的每一位成员都可以关注于他或者她最擅长的事物。
实现 JSP 自定义标记
JSP 体系结构需要以下组件以实现自定义标记:
- 在每一页中有一个 JSP 声明
- Web 应用程序描述符(web.xml)中的一个项
- 一个包含特殊 XML 文件和为处理自定义标记而调用的 Java 类的 JAR 文件
要想成功实现 JSP 自定义标记,您需要采取下面四个步骤:
- 编写标记处理程序类。
- 创建标记库描述符(TLD)。
- 引用标记库。
- 在 JSP 页面中使用标记。
那我们就以经典的"Hello,World"开始吧。。。
第 1 步. 编写标记处理程序类
我们要做的第一件事是编写标记处理程序类。在执行引用自定义标记的 JSP 页面时,JSP 容器判断每一个自定义标记。当容器遇到一个标记时,它调用与这个自定义标记相关联的标记处理程序,我们将在后面更多地讨论这个过程。然后,每一个标记处理程序实现 JSP API中的一个特殊接口。标记有两种类型:可以处理标记内容(或者正文)的标记和不能处理标记内容的标记:
<abc:tagWithBody attribute="value">
This is some body content that the tag handler can operate upon.
</abc:tagWithBody>
在 例子中不需要加入正文内容,因为它只显示一个字符串。因此,我们的处理程序类将实现 Tag 接口(一般是通过扩展 TagSupport 类)。如果我们要创建一个可以处理正文的标记,那么我们就需要实现 BodyTag 接口(一般是通过扩展 BodyTagSupport 类)。
清单 1. 标记处理程序类
import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;
public class HelloTag implements Tag
{
private PageContext context = null;//页面上下文
public HelloTag()
{
super();
// TODO 自动生成构造函数存根
}
public void setPageContext(PageContext pageContext)
{
this.context = pageContext;
}
public void setParent(Tag tag)
{
}
public Tag getParent()
{
return null;
}
public int doStartTag()throws JspException
{
try
{
this.context.getOut().println("hello,world");
}
catch(IOException ex)
{
throw new JspException(ex.getMessage());
}
return Tag.SKIP_BODY;
}
public int doEndTag()
{
return Tag.SKIP_PAGE;
}
public void release()
{
}
}
当然在这里值得注意的是,我这是采用了实现Tag接口的方法来做的,其实更好的方式是继承自TagSupport类。因为 TagSupport 类是简单的、具体类,它完全实现了在 Tag 接口中声明的方法,我们可以只实现那些在自定义标记中要使用的方法。
第 2 步. 创建 TLD
下一步是定义包含自定义标记与处理它的 Java 类(或多个类)之间的映射的库。这个库是在一个名为标记库描述符(TLD)的 XML 文档中定义的。
清单 2. mytag.tld 文件
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>hello</shortname>
<tag>
<name>sayHello</name>
<tagclass>com.vitamin.taglib.HelloTag</tagclass>
<bodycontent>empty</bodycontent>
</tag>
</taglib>
所有关键信息都包含在 Tag 标记中,在这里映射了标记名和处理程序类,我们声明了标记对于正文内容的敏感性。对于更复杂的情况,我们可以使用其他的 XML 标记以提供有关库和标记的更多信息。在一个库中定义多个标记也很常见。
第 3 步. 引用这个标记库
有两种方法声明 JSP 页面与其库之间的引用。可以通过 Web 应用程序描述符(web.xml)声明一个静态引用,也可以直接在页面中声明一个动态引用。(可奇怪的是,我在用静态引用时,居然失败,web.xml里面放进去声明时就会报错。。。)
为了进行动态引用,只需在所有需要使用这个库的页面中加入一个 JSP 声明即可:
静态引用与动态引用的比较
在进行标记库的静态引用时,JSP 声明必须查询 web.xml 文件以执行库查询。这意味着如果移动或者重命名了库,或者希望在 web.xml 文件中加入更多的库,就必须停止服务器、更新 web.xml 文件、然后重新启动服务器。动态方法让 JSP 页直接指向 TLD 位置,因而是在解释 JSP 页面时进行处理。
静态方法提供了页面与库的实际名和位置之间一定程度的非直接性,这可以为您提供一些改变这些属性而不修改页面的灵活性。另一方面,动态方法提供了更大的灵活性,让您可以在运行时增加和移动标记声明。如果您对动态方法感兴趣,但是又担心做了一些改变后、有可能要更新多个页面的维护负担,那么您可以始终将 JSP 声明放到一个单独的 JSP 文件中,并在每一个要访问 Web 应用程序的自定义库的页面中加入这一页。这使您具有在运行时只需要更新信息一次就可以增加库的灵活性。
第 4 步. 在 JSP 页面中使用标记
完成了所有这些准备工作后,我们就可以在 JSP 页面中使用这些自定义标记了。
清单 3. 带有自定义标记的 JSP 页
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ taglib uri="/WEB-INF/mytag.tld" prefix="hello" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<hello:sayHello/>
</body>
</html>
用JSTL 节省时间
您所需要的自定义标记功能中也许有多达百分之八十已经由 J2EE 团体创建并标准化了。使用现有的标记库而不是从头创建所有东西会使您节省大量时间和精力。尽管在公共域有数十种库,不过业界汇集了一个特定的自定义库。Java 标准标记库(JSTL)是由 Java Community Process 设计的,其参考实现是由 Apache Group 通过 Jakarta Taglibs 项目所开发和维护的.
JSTL 定义了针对常见 Web 应用程序处理需求,如变量支持、流程控制、URL 管理、XML 操作、国际化、数据库访问等等的标记。除了一组丰富的标记外,JSTL 还定义了自己的表达式语言(EL)。EL 使我们可以容易地访问应用程序数据并更容易在不使用脚本或者请求时表达式的条件下操作这些数据。
除了节省您从头开发所有标记的时间和精力,JSTL 还具有标准化和业界承认的所有好处。这些好处包括厂商支持、大量介绍文字、以及有很大的机会找到具有 JSTL 经验的雇员或者承包商。
结束语
在 J2EE Web 开发中越来越多地需要将业务和表示逻辑分离,JSP 自定义标记提供了替代简单的老 JavaBean 和 Java 脚本的一个有吸引力的方法。更好的是在 JSTL 中已存在一组已定义的标准的自定义标记库。
另外,标记库技术虽然解决了java代码和html混合的问题,但却带来了另一个问题,就是使用了标记库的页面不能进行可视化设计了!!!因为开发工具根本不能运行你后台的代码,所以就显示不出来页面的结果了。于是,JSF就出现了。它一改以往的基于Web的Request-Response处理机制,而是采用了类似Swing的的事件驱动处理机制。它简化了Web表单的有效性验证,Request参数解析,状态管理和多线程支持等任务,我们只需要实现具体的事件处理模块和事件逻辑模块就可以了。