JSP 技术的承诺
现在,我们来讨论 JSP 编码的具体内容。JSP 技术承诺为设计人员和开发人员提供他们所需的最合适的表示技术。JSP 技术是 J2EE 平台的一部分,显示了 Sun 公司所能给予 Java 产品的最强大支持。为了使您对此解决方案的流行程度有一个概念,您可以试着在 amazon.com 上搜索一下“JSP”,您会发现,论述 JSP 的书籍比论述其他任何一种 Java API 的书籍都要多。在我深入讨论 JSP 技术存在的特定问题之前,您需要对它承诺的功能有一个清楚的了解。
内容与表示
首先,JSP 技术是用来分离内容和表示的,这一点最早出现在 Sun 对于 JSP 公布的一系列目标中。实际上,JSP 的设计直接针对开发人员的抱怨,这些开发人员对于在 servlet 代码中反复键入 out.println("<HTML><HEAD><TITLE>"
+ pageInfo.getTitle() + "</TITLE></HEAD>")
感到厌烦。这种硬编码内容和运行时变量的混合对 servlet 开发人员造成了巨大的负担,也使开发人员在对表示层进行即便是最小的改动时也困难重重。
JSP 技术通过支持普通 HTML 页(以及稍后的 WML 或其他标记语言页)在运行时编译为 Java servlet,改变了这种情况。它实际上是模仿 out.println()
语句,而无须开发人员编写代码。同时还允许在页面中插入变量,直到运行时才解释这些变量。
清单 2 所示的 HTML 片段相对应的 JSP 页应与清单 3 中的示例相似。
清单 3. 一个使用表示技术包含数据的 JSP 页
<%@ page import="com.ibm.display.PageUtils" %> <%@ page import="com.ibm.display.PageInfo" %>
<% PageInfo pageInfo = (PageInfo)session.getAttribute("PAGE_DATA") %>
<HTML> <HEAD> <TITLE> <%=pageInfo.getTitle()%> </TITLE> </HEAD> <BODY>
<!-- 其他 HTML 内容 -->
</BODY> </HTML> |
按这些初始原则判断,JSP 技术(至少在它的声明设计中)会满足表示技术的第一个原则,如上所述:即内容与表示的分离。
代码与标记
JSP 技术所列的第二个特性可能引起你的注意,那就是,JSP 编码允许直接向标记页中插入 Java 代码。为了理解作出这种决定的原因,我们回想一下制定 JSP 规范时的情况。Sun 与微软的竞争一直非常激烈,主要源于微软 Active Server Pages (ASP)的成功。JavaServer Pages 与 Active Server Pages 在名称上的相似并非巧合。而且模仿 ASP 的多种特性似乎亦是有意的。所以 JSP 的作者选择了在他们的标记中加入 Java 代码。
作为向标记中加入 Java 代码的一个例子,清单 4 中的 JSP 片段自动按需要添加行,以显示演员 Vector 中的每一项。
清单 4. 插入到标记语言页中的 Java 代码
<%@ page import="com.ibm.display.PageUtils" %> <%@ page import="com.ibm.display.PageInfo" %> <%@ page import="com.ibm.people.Actor" %> <%@ page import="java.util.Iterator" %> <%@ page import="java.util.Vector" %> <% PageInfo pageInfo = (PageInfo)session.getAttribute("PAGE_DATA") Vector actors = pageInfo.getActors() %>
<HTML> <HEAD> <TITLE> <%=pageInfo.getTitle()%> </TITLE> </HEAD> <BODY>
<H2 ALIGN="center">搜索结果:演员</H2> <CENTER> <HR WIDTH="85%"> <TABLE WIDTH="50%" CELLPADDING="3" CELLSPACING="3" BORDER="1" BGCOLOR="#FFFFCC">
<% for (Iterator i = actors.iterator(); i.hasNext()) { Actor actor = (Actor)i.next(); %> <TR BGCOLOR="#FFCCCC"> <TH WIDTH="50%" ALIGN="center"> <%=actor.getLastName()%> </TH> <TH WIDTH="50%" ALIGN="center"> <%=actor.getFirstName()%> </TH> </TR> <% } %> </TABLE> </CENTER>
</BODY> </HTML> |
请记住,到目前为止,我是在简述设计 JSP 技术的最初目标。在后面的章节中谈及关于 JSP 技术的问题时,我才会作出本人对此目标的判断。但是,您现在可能已经有点怀疑了,因为向 JSP 页中嵌入代码似乎会导致与 JSP 技术的第一个目标有关的问题(即把内容和表示分离开来)。但是实际上(啊咳),我还没有发表意见呢。
设计人员与开发人员
JSP 技术值得一提的最后一个(也是值得赞赏的)目标是,它试图在应用程序开发过程中建立明确定义的角色。通过表面上将内容和表示分离开来,JSP 技术在设计人员和开发人员之间划定了一条更加明显的界线。设计人员只使用标准的 HTML、WML、或其他适当的语言创建标记,开发人员编写代码。当然,现在许多设计人员已经学会了JavaScript,所以不应惊奇的是,他们中的许多人也开始学习 JSP 编码。很多情况下,他们不只是做纯标记,而是编写完整的 JSP 页,并把它交给开发人员。进行常规的调整后,开发人员把这些 JSP 页作为整体应用程序某一部分的前端放置到适当位置。但关键是,许多设计人员不会 JSP 编码,所以在这种环境中还有工作可做。
问题
我已清楚地说明了良好的表示技术应提供的东西,以及 JSP 技术试图解决的特定问题。现在,我准备切入正题:JSP 技术的设计虽然想法很好,但是它带来了相当多的问题。在选择在应用程序中使用 JSP 之前(您可能仍会使用),您应该至少知道可能存在的缺陷。
您也应该了解 J2EE 编程平台常被忽视的一个小问题:此平台提供一种 API 并不意味着您必须使用它。正像这句话听起来有点愚蠢一样,许多开发人员还在 JSP、EJB 或 JMS API 中挣扎,他们认为如果不使用这些 API,他们的应用程序就有点不像是真正的“J2EE 应用程序”。实际上,此平台承诺的诸多 API,对大多数应用程序来说都不必要。如果您在使用 JSP 技术时出现问题或对它有怀疑,您完全可以不使用它! 在选择在应用程序中使用 JSP 技术之前,请仔细看一下它的优缺点。现在让我们看一下它的几个缺点。
可移植性与语言锁定
JSP 技术把您锁定在一种特定的语言中。对于这一点不应该看得太重。在设计企业应用程序时,Java 技术是唯一的语言选择(至少我的观点是这样)。在这个问题上,没有独立于语言的解决方案。当然,在游戏的这个阶段,我还不考虑 Microsoft .NET 平台的烟幕及其实际情况。只有时间会证明 Microsoft .NET 平台是否会发展成为一个真正独立于语言的产品。(我很怀疑。)
还有,选择 JSP 技术会强制您使用 Java 语言,至少对表示和内容而言是这样。虽然 CORBA 可用于业务逻辑,但进行 JSP 编码确实需要熟悉一些 servlet 以及核心的 Java 语言。由于许多开发人员都是从 J2EE 平台转向 JSP 编程,所以这点通常不是问题。
混合与独立
在全文中,我多次提到把内容和表示分离的想法。您也许已经听烦了,那么现在到了我们来确定 JSP 是否真的实现了这个目标的时候了。正像我已说过的那样,既然 JSP 声称是为这一分离目标而设计的,所以我们应该假定它实现了这个目标?对吗?未必。
模糊了内容与表示之间的界限
JSP 允许向标记语言页中插入 Java 代码,这一点相当危险,它甚至允许将内容混合到表示中。更糟的是,业务逻辑经常混入 JSP 页中,如清单 5 所示。
清单 5. 包含业务逻辑的 JSP 页
<%@ page import="com.ibm.display.PageUtils" %> <%@ page import="com.ibm.display.PageInfo" %> <%@ page import="com.ibm.logic.AdminUtils" %> <%@ page import="com.ibm.people.Actor" %> <%@ page import="java.util.Iterator" %> <%@ page import="java.util.Vector" %>
<% PageInfo pageInfo = (PageInfo)session.getAttribute("PAGE_DATA") %>
<HTML> <HEAD> <TITLE> <%=pageInfo.getTitle()%> </TITLE> </HEAD> <BODY> <H2 ALIGN="center">搜索结果:演员</H2> <CENTER> <HR WIDTH="85%"> <TABLE WIDTH="50%" CELLPADDING="3" CELLSPACING="3" BORDER="1" BGCOLOR="#FFFFCC">
<%
// 根据用户的权限,执行不同的搜索(业务逻辑!) Vector actors = pageInfo.getActors() if (pageInfo.getUserInfo().hasPermission("ADMINISTRATOR")) { actors = AdminUtils.getActors(pageInfo.getSearchCriteria()); } else { actors = pageInfo.getActors(); }
for (Iterator i = actors.iterator(); i.hasNext()) { Actor actor = (Actor)i.next(); %> <TR BGCOLOR="#FFCCCC"> <TH WIDTH="50%" ALIGN="center"> <%=actor.getLastName()%> </TH> <TH WIDTH="50%" ALIGN="center"> <%=actor.getFirstName()%> </TH> </TR> <% } %> </TABLE> </CENTER> </BODY> </HTML> |
JSP 的拥护者会马上告诉您 JSP 标记库可以帮助您避免这种问题。标记库允许向 JSP 页加入定制的标记(例如<AUTHORS />
),这些标记在运行时解释为标记库中的代码片段。
使用定制标记和相关的标记库会使上面的示例变为清单 6 中的代码。
清单 6. 结合到页中的定制标记和标记库
<CENTER> <TABLE WIDTH="50%" CELLPADDING="3" CELLSPACING="3" BORDER="1" BGCOLOR="#FFFFCC">
<ACTORS />
</TABLE> </CENTER> |
在运行时,这个标记的代码就会执行,正确的结果会插入到页中。但这并没有解决问题。此时,对 JSP 技术不利的论点不在于表示和内容是否能够分离,而是在于他们是否必须分离。只要 JSP 编程允许内嵌代码,则使用内嵌代码作最后的修改就很容易(特别是在限期邻近时),而不是把代码转化到标记库中。如果不是这样,请考虑一下 Java 语言的流行速度迅速超过C 和 C++ 的原因:Java 不允许 C 中许多有问题的特性,例如指针加法。尽管您总是可以争辩在 C 中不是必须执行指针加法,或者优秀的程序员从来不会插入代码 scriptlet,但是我们都知道实际情况会是怎样。Java 语言优于 C,是因为它禁止这种坏习惯出现。但 JSP 在这种情况下,与 C 语言极为相似,它允许一些坏习惯。
对于 JSP 技术是否达到了它所宣称的目标, 还有一个测试标准,就是看它实际上是否能够达到目标。当然,以不可能达到的标准来要求 JSP 是不公平的。大多数模板引擎(例如 FreeMarker 和 WebMacro)有这种相同的内嵌代码功能,通常这些模板使用类似 Perl 的语言。但是,像 enhydra 的 XMLC 这样的技术,不允许这种内嵌代码。这些技术使用一个纯标记语言页作为输入来代替,并生成 Java 方法。这种做法实质上是改变了程序流,而不是页面(JSP 技术)调用应用程序的逻辑,应用程序(enhydra)使用方法来影响页面中的值。在 enhydra 的特定情况下,XMLC 把页面转化为一个 DOM 树,并使用 DOM 的 HTML 绑定来允许页中“域”的更新。(关于 enhydra XMLC 的详细信息,请参阅参考资料。)
在这一点上,JSP 比 XMLC 问题更严重。例如,虽然 JSP 技术能够实现它的目标,但是它只允许使用标记库。但是,Sun 规范中的总趋势是始终保持向后兼容,或至少保持相当长的一段时间。当前版本的 JSP 1.1 允许使用 scriptlet,所以估计 JSP 页包含代码这一情况还要维持几年。在深入探讨 JSP 编码前,请注意它实际提供了产品(它至多不过是用户界面和驱动应用程序的代码之间的伪分离)和它的目标(即完全分离内容和表示)之间仍有相当大的差距。
单一处理与多任务
如上讨论,理想情况下,设计人员应该只执行单一处理,即只进行图形设计工作,开发人员应该只注重于编码。这样,在一个页面转化为应用程序所使用的格式后,设计人员应能够修改它。在 JSP 页的情况下,这应该在导入 JavaBean、插入内嵌代码、在页中加入定制标记库之后。问题是有些设计人员使用 HTML 编辑器,如 HoTMetaL、Macromedia Dreamweaver 或 FrontPage,这些编辑器不能识别代码 scriptlet 或标记库,这意味着设计人员实际上只收到了部分页面。当标记库或代码段在页中产生表格行或其他格式的具体内容时,其困难程度可想而知。使用不兼容的 HTML 编辑器,设计人员无法看到那些元素是什么样子。当设计人员无法方便地修订开发人员编译后的页面时,JSP 编码不是把不同的角色区分开来,而是使这些角色合并在一起:开发人员必须能够完成多种任务,成为开发人员兼设计人员并承担其他角色。
这种重要特性没有使您信服吗?那么您可以下载 J2EE 参考实现,并把其中任意一个包含的 JSP 页调入所见即所得的 HTML 编辑器,如 Dreamweaver。这个页面立即充满黄色区域,使您知道包含在页面中的所有“非法”标记。当然,黄色区域是由 JSP 标记和代码造成的,不是页中的任何实际错误。
到目前为止,还没有出现任何能够支持 JSP 的所见即所得编辑器,我也没有听说有人正致力于开发这样的编辑器。模板引擎亦有这种相同的问题,许多基于 Java 的方案(例如我喜欢的 enhydra),允许把标记页作为输入提交表示技术。在这种情况下,设计人员可以反复修改标记页,再把它们重新提交回去。运行表示技术的引擎或编译器可以将此页面转换为正确的格式,并且不需要改变代码(在通常情况下)。结果正是我们所希望的:设计人员就是设计人员,而开发人员就是开发人员。
所以,和 JSP 技术实际提供的功能相比较,我希望您一定要小心对待 JSP 技术提出的承诺。实际上,为了使应用程序在一个 JSP 技术驱动的环境下成功运行,您必须让您的开发人员处理大量标记,或者使设计人员至少学习一些 JSP 编程。
HTML 与 XML
JSP 技术的一个最严重的缺陷,也是最易被忽视的一点,就是它与 XML 不兼容。更准确的说,尤其是在 HTML 领域中,JSP 页不需要兼容 XHTML。XHTML 是一个万维网联盟 (W3C) 规范,它现在正取代 HTML 4.0。XHTML 按照一种结构完整的 XML 文档定义 HTML 标记集。例如 <br>
标记必须转换为 < br/>
,以确保遵守 XML 规定。(如果您觉得这一点没有阐明清楚,可以查阅 XML 规范和 developerWorks 关于 XHTML 的文章,它们在列在参考资料中。)
图像标记也有类似的规则,在 XHTML 1.1 (最近诞生的) 中,大多数字体属性和其他样式转移到了 CSS 样式表中。另外,大多数标准的 HTML 文档可以很容易转换为 XHTML 1.0,这意味着它们很容易使用 XML 兼容的分析程序阅读,例如 Apache Xerces,并且能够以 XML 方式控制。
您会问:“最重要的是什么?”最重要的一点就是 XML 迅速成为互联网和企业内部网的全球标准。对于任何使用基本 XML 数据处理工具的其他应用程序,以 XML 格式传送数据,它们可以很容易地使用您的应用程序的数据。试想一下,只须把数据转换为 XML 格式就能与信用卡公司进行电子商务通信! 很多情况下,您的数据表示也需要和其他公司交换数据。最常见的情况是门户站点应用程序,它从不同的提供者(例如天气、股票报价和新闻等)接收内容,这些内容还常常带有提供者的标志。但是,JSP 页面由于混合了代码和定制标记库,所以无法在这样的环境中良好工作。
JSP 页几乎不是格式完整的 XML 文档,更不用提符合 XHTML了。因为 XHTML是一种标记语言,它不允许各种 JSP 定制标记库。但是更重要的是,插入到 JSP 页中的代码片段不是任何形式的标记,而且一旦用另一个应用程序处理它们,就会产生分析程序错误的负担。
在您对我进行评论之前,让我讲完整个故事。如果应用程序允许原始客户机计算 JSP 页的值,其结果会是纯 HTML (或 WML、VoXML 等)。但是,大多数请求数据的应用程序使用某些形式的缓存,因为网络上的往返是很昂贵的。在这些情况下,缓存的页面返回陈旧的数据。在这种情况下,您可能更希望返回完全符合纯 XML 的结果,最好是静态表单。但是 JSP 技术对这种情况无能为力。JSP 页必须始终在运行时求值,这样才能去掉 JSP 代码 scriptlet 和标记库。
检验一下:有其他表示技术能够完成这个任务吗?答案是肯定的。在此领域的绝对领先者是 Apache Cocoon 项目,它完全基于 XML,是一个 XSLT 样式表应用程序(即可在运行时应用,也可静态地应用)。由于 XML Server Pages(在Cocoon 框架中叫作 XSP)实际上是 XML 文档,所以它们始终是符合 XML 的。其他允许纯标记语言页输入的技术(例如 Tea 和 enhydra XMLC)也可以允许这一点,虽然它们不强制这样做。在这些情况下,用户可以使用 XHTML 或标准 HTML。但是这样仍然比 JSP 的情况要好,因为在 JSP 中无法无法静态实现格式完整的 XML。
小结
我希望我为您拓宽了一些眼界,使您看到了 JSP 技术的优缺点。现在,您可以把 JSP 编程看成是多种表示技术中的一种可选技术。在这一点上,您可能对整体的 J2EE 编程模型有所怀疑。现在您也许希望更进一步研究此平台的替代方案,并在 Apache Cocoon、enhydra 和多种模板中选择替代 JSP 编码的方案。
最后,应该记住的是,尽管本文似乎提出了反对意见,但并没有建议您使用或不使用 JSP。我无意鼓励您深入到任何技术的深层探究它是否符合您的要求。编程模型就像是例子,有时行得通,有时行不通。三思而后行,找到最适合您的方案再做决定,这总比草率做决定要好。
玩得开心,网上见!
参考资料
作者简介
Brett McLaughlin 是 Lutris Technologies 公司的 enhydra 战略家,专门研究分布式系统体系。他是 Java and XML (O'Reilly) 的作者;从事 Java servlet、Enterprise JavaBeans 技术、XML 和企业对企业的应用程序的研究。最近与 Jason Hunter 起创建了 JDOM 项目,此项目为从 Java 应用程序操纵 XML 提供简单的 API。他还是 Apache Cocoon 项目、EJBoss EJB 服务器的活跃开发人员,并且是 Apache Turbin 项目的创始人之一。可以通过 brett@newInstance.com 与 Brett 联系。