出现的问题
我刚刚介绍了一种良好的表示技术应该提供的功能,以及 JSP 技术尝试解决的具体问题。现在,我将转入正题:JSP 技术虽然建立在良好理念的基础之上,但是却出现了一些问题。在选择 JSP 编写您的应用程序之前(您可能仍然会这样做),至少应该注意一些容易出现的问题。
您还需要注意经常被忽略的 J2EE 编程平台:仅仅因为平台附带了 API 并不意味着一定要使用它。和这种想法同样可笑的是,很多开发人员在使用 JSP、EJB 或 JMS API 时,都在想如果不使用这些 API 的话,他们的应用程序就不是真正的 “J2EE 应用程序” 了。实际上,平台提供的 API 远远超过大多数应用程序的需要。如果您不能使用或对 JSP 技术还持有怀疑态度,那么可以不使用它!在选择 JSP 编写应用程序之前,仔细研究它的优点和 缺点。让我们看看其中一些缺点。
可移植性和语言锁定
JSP 技术将您锁定到某种特定的语言。这一点不应该给予太多的关注。至少在我看来,Java 技术是企业应用程序的惟一 选择。在这个领域,根本不存在可以独立于语言的解决方案。当然,在这个时候,我没有把 Microsoft .NET 平台牵涉进来。只有时间可以告诉我们这个平台是否可以真正独立于语言(我很怀疑这一点)。
然而,选择 JSP 技术将强制您使用 Java 语言,至少对于内容和表示是这样的。尽管 CORBA 可以用于业务逻辑,JSP 编码要求必须熟悉 servlet 和核心 Java 语言。因为很多开发人员通过 J2EE 平台接触 JSP 编码,因此这通常算不成问题。
混合和独立
在本篇文章中,我始终围绕分离内容和表示这一概念。您可能对此已经感到不耐烦,那么现在让我们看看 JSP 究竟能不能实现这个目标。正如我们之前讨论的一样,JSP 宣称 一直致力于实现内容和表示分离,那么我们可以因此认为它实现了目标,是吗?未必如此。
内容和表示之间的界限变得模糊
JSP 允许将 Java 代码插入到标记语言页面中,这个非常危险的特性允许将内容混合到表示中。更糟糕的是,业务逻辑通常会进入到 JSP 页面中,如清单 5 所示。
<%@ 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">Search Results: Actors</H2>
<CENTER>
<HR width="85%">
<TABLE width="50%" CELLPADDING="3" CELLSPACING="3" border="1"
BGCOLOR="#FFFFCC">
<%
// Based on user's permissions, perform search differently (business logic!)
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 标记库 可以帮助您避免这个问题。标记库允许将自定义标记(例如 <AUTHORS />)添加到 JSP 页面,然后在运行时在标记库内将其解析为代码片段。
使用自定义标记和相关的标记库允许把以上示例转换为清单 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 语言是一种更好的选择,因为它严禁 使用这些不好的习惯。但是 JSP 在这方面更类似于 C,允许实现一些非常糟糕的实践。
检验 JSP 技术是否成功达到其所述目标的另一种方法是看它能否在实践中实现这个目标;显然,如果认为 JSP 无法实际实现目标,这是不公平的。大多数模板引擎,比如 FreeMarker 和 WebMacro,都提供了相同的内联编码功能,通常附带了一种类似 Perl 的语言。然而,诸如 Enhydra 的 XMLC 这样的技术不 允许进行这种类型的编码。相反,这些技术将一个纯标记语言页面作为输入,然后生成 Java 方法。这实际上改变了编程流程;应用程序并不像 JSP 技术那样使用页面从应用程序调用逻辑,而是使用方法影响页面的值(Enhydra)。以 Enhydra 为例,使用 XMLC 将页面转换为一个 DOM 树,然后使用 DOM 的 HTML 绑定更新页面中的 “字段”(有关 Enhydra XMLC 的更多信息,请查阅 参考资料)。
这里的重点是,JSP 技术实现目标的能力远远超过 XMLC,例如,仅仅是允许标记库这一项就比 XMLC 强很多。但是 Sun 规范总体趋向于始终维护向后兼容性,或至少在相当长的一段时间内维护向后兼容性。JSP 规范的当前版本为 1.1,它允许使用 scriptlets,因此在未来几年内 JSP 页面内都会支持这个特性。在深入探究 JSP 编码之前,请注意,在其强调的完全分离内容和表示的理念和实际实现之间存在一个很大的缺口,它充其量只是假装分离了用户界面和驱动应用程序的代码。


