级别: 中级
Jason Van Cleve (jason@vancleve.com), Web 开发人员, Else For If
2007 年 4 月 13 日
对于具有动态内容的 Web 页面,可以使用 Java™Server Pages(JSP)技术将开发人员和 UI 设计人员的工作分离开来。遗憾的是,JSP 对于许多设计人员来说太复杂了,所以 Java 开发人员只好自己处理 JSP 代码,这往往会产生令人不满意的结果。本文演示一种非正统的替代方法:通过使用简单的 helper 对象,根据纯 servlet 构建 Web 界面。
设计 JSP 的目的是将 Web 开发人员的任务与设计动态页面 UI 的非开发人员的任务分离开来。遗憾的是,JSP 对于许多设计人员来说太复杂了,为解决各种动态内容问题添加的软件层让他们觉得非常棘手。(例如,国际化要求将文本存储在其他地方并通过键来引用。)所以对于大多数项目,Java 开发人员只好自己处理 JSP 代码,这常常会包含本属于设计人员的工作,使他们的精力消耗在标记库和其他东西上,无法集中于 Java 代码。
与正统的方式不同,可以使用简单的 helper 对象,根据常规 servlet 构建简洁优美的 Web 界面。本文讲解如何以标准的 Java 形式编写动态 Web 页面的视图输出。我将解释这种方法的好处,并用一个计分应用程序演示这种方法,这个程序管理一个 NCAA 三月狂热 奖金池。
这种纯 servlet 方法非常简单。它涉及一个 servlet 基类和一个定制的写出器对象,servlet 子类使用这个对象产生输出。代码很简洁,因为大多数 HTML 封装在 helper 对象的方法中,都可以按需重写。代码重用总是令人愉快,而且大多数 Web 站点的页面共享许多 HTML,所以重用应该是个重要的考虑因素。HTML 输出方法产生直观紧凑的 servlet 代码,因此可维护性很高,这使代码的维护成本差不多直接与代码规模成正比。通过将 JSP 界面重写成纯 servlet,可以将代码缩减三分之二。
例如,要根据用户权限输出一个链接,就需要下面这样冗长的构造代码:
<c:if test="${user.permission[ sessionScope.ConstantMap[ EDIT_WIDGET ] ] != 0}"> <c:url var="editUrl" value="/EditWidget.jsp"/> <div class="navigation"><a href="<c:out value="${editUrl}"/>">Edit this widget</a></div> </c:if> |
通过使用 Java 语法,代码就简洁多了:
if (user.getPermission(Constants.EDIT_WIDGET) != 0) out.printNavlinkDIV("/EditWidget.jsp", "Edit this widget"); |
另外,在同一个地方获取和输出业务对象,而不是通过请求对象传递它们,这也会节省大量代码。简洁是美。
使用 JSP 和其他视图技术可能是 Web 开发中最让人头疼的部分。JSP 页面不是 HTML 或 XML、Java 代码、JavaServer Pages Standard Tag Library(JSTL)代码或表达式语言(EL),而是这些东西的大杂烩。JSP 代码不但是奇怪的组合体,而且每个抽象层都给开发带来新的障碍。例如,对 JSP 页面进行调试简直就像探矿那样困难。您知道某个地方出了毛病,但是无法找到出问题的位置;神秘难懂的错误消息虽然指出了行号,但这个行号往往不是问题的真正所在。
JSP 技术不能扩展基类,所以代码重用只能通过 bean、include 文件和定制的标记库来进行。标记库太麻烦,不适合进行有效的重用。为您所做的每处 API 修改维护一个 XML 是非常麻烦的,而且 “标记设计就是语言设计”(参见 参考资料 中 Noel Bergman 的文章)。结果是在本已分了很多层的接口上又加了一层。
|
我们正面对着全新的 World Wide Web。无论 Ajax 能否引领 Web 开发的方向,Web 站点都会继续向着更加智能化的方向发展。另外,尽管 HTML 本身总是声明性的,但是产生它的代码却不一定如此。JSP 技术和其他模板化系统必然过分复杂,因为它们试图以声明式的方式表达本质上动态的输出。这正是开发人员无法容忍在 JSP 源代码中添加 scriptlet 的原因:我们试图表达的逻辑 具有各种各样的形式。
通过将 HTML 封装成 Java 代码,可以简洁地表达输出逻辑。if 语句和 for 循环可以采用大家熟悉的形式。页面元素可以重构成方法,这样就很容易理解和维护它们。(对较大的 JSP 页面进行维护是非常麻烦的,非常容易出现错误,尤其是在缺少良好的注释的情况下。)通过使用纯 servlet,可以尽可能增加代码重用,因为不需要为每个页面的构造编写新的类。
|
为了演示纯 servlet 的概念,我为一个 NCAA March Madness 锦标赛奖金池构建了一个计分界面。(参见 三月狂热 和 下载)。用户可以从参加锦标赛的 64 支球队中选择他们认为最出色的 20 支球队,并给每个球队分配一个加权的分数。比赛开始之后,他们的选择就变成只读的;当比赛结束时,管理员输入获胜球队的名称。根据用户选择的球队,自动地计算用户的累积分数并显示分数的排名。
这个项目大约花费了我三周的业余时间,大部分时间花在样式和图像上(毕竟我不是画家)。除了一个 HTML 文件和其他静态资源之外,UI 层由 21 个 Java 类组成,根据 JavaNCSS 的度量标准,一共有 1,334 个 Java 语句(参见 参考资料)。