对于 Java Server Faces (JSF) 这样一种不可或缺的技术,产生了很多不适当的 FUD(“Fear, uncertainty, and doubt”的缩写,意思是“恐惧、不确定、怀疑” )。盛传着这样一些谣言:JSF 开发很难,比一些主流方法的要求更苛刻,并且完全依赖于 WYSIWYG 工具。在这个新的由 4 部分组成的系列文章中,经常为 developerWorks 撰稿的作者 Rick Hightower,划清了 FUD 与事实真相,向您展示了:JSF 实际上比诸如 Struts 这样的 MVC Model 2 框架更加容易使用。如果您知道自己在做什么,那么确实是这样的。
FUD 已经围绕 J2EE 的 JavaServer Faces (JSF) 技术多时了,我觉得现在该让它停止了,或者至少给出一种公允的说法。关于 JSF 的第一个谣传是,需要一个 WYSIWYG 拖放工具来进行 JSF 开发。第二个谣传是,JSF 不支持诸如 Struts 这样的 MVC Model 2 框架。最后一个,也是最致命的谣传是,JSF 开发就是难。
在 这个 4 部分的系列文章中,我将尽量以最实际的方式消除所有这三个谣传,这种方式就是教您利用 JSF 进行开发。实际上,如果您认为 JSF 开发很难,可能是您没有用对,幸运的是,这很容易改正。本期一开始,我将给出 JSF 的一个结构上的概述和一个实际的例子,演示了 MVC 和 JSF 的基础。但是在开始之前,我将花一点时间来划清 JSF FUD 与事实真相。
正 如前面提到的,关于 JSF 存在三个谣传,第一个谣传是,进行 JSF 开发需要 WYSIWYG 工具。简直是胡说。就像很多 Swing 开发人员不使用 WYSIWYG 来构建 Swing 应用程序一样,您也不需要用 WYSIWYG 编辑器来构建 JSF 应用程序。事实上,不用 WYSIWYG 工具进行的 JSF 开发比利用诸如 Struts 和 WebWork 这样的传统 Model 2 框架进行的开发要容易得多。本文后面我将详细解释具体原因,但是现在您只要记住:JSF 开发比 Struts 要容易得多,即使不使用 WYSIWYG 工具!
关 于 JSF 的下一个谣传是,不支持 Model 2 架构。目前来说,这实际上说得有点对。但事实是,Model 2 是针对建立在 Servlets 之上的 Web 开发的 MVC (Model-View-Controller) 的打了折扣的版本。尽管 Model 2 连接到一个无状态协议 (HTTP),但是 JSF 支持更加丰富的 MVC 模型(这是传统 GUI 应用程序更加紧密的近似)。尽管 MVC 的基础使得 JSF 框架实现比其他框架更难构建,但是有利的是,实现 JSF 的大量实际工作已经不用您自己完成了,所以您的净付出减少了,而您的净受益就显著增加了。
|
关 于 JSF 开发最主要、流传最广的谣传是,JSF 开发太难了。我经常从那些阅读过该技术的大量资料却没有亲自体验过的人那里听到这种说法,所以我认为我可以轻易澄清这一点。事实是,如果您将您对 JSF 的观点建立在它无可否认的广泛规范上 —— 以及它的所有生命周期图表和图片 —— 那么该技术很容易让您发怵。但是请记住这样一件事情,规范是针对工具实现者的,而不是针对应用程序开发人员本身。正如前面提到的,JSF 框架设计成对应用程序开发人员来说非常容易。
事 实上,尽管 JSF 的基于组件的、事件驱动的 GUI 开发模型对于 Java 世界来说还有点新,但是在别处已经存在很长一段时间了。ASP.net 和 Apple 的 WebObjects 都是类似于 JSF 的架构。Tapestry 是一种开放源代码的、基于 Java 的 Web 组件框架,它采用的方法有些不同于 JSF 的方法,但是也建立在 Web GUI 组件模型之上。
就现在来说,对 FUD 的谈论也许已经足够了。消除您对 JSF 的偏见的最好方法是,适当地钻研这种技术,我们马上就来做这件事。但是为了避免这成为您对 JSF 的第一印象,我一开始将给出一个结构上的概述。
像 Swing 和 AWT 一样,JSF 是一个可以提供一组标准的、可重用的 GUI 组件的开发框架。JSF 用于构建 Web 应用程序接口。JSF 提供以下开发优势:
典型的 JSF 应用程序包含以下部分:
尽管使用 JSF 需要跨越一些概念上的障碍,但是这样做是值得的。JSF 的组件状态管理、容易使用用户输入验证、细粒度、基于组件的事件处理和容易扩展的架构,都将大大简化 Web 开发。在接下来的几小节中,我将更加详细地解释这些特性中最重要的特性。
JSF 为标准 HTML 中可用的每个输入字段提供了组件标签。您也可以为应用程序的特定目的,或者为了将多个 HTML 组件组合在一起形成一个复合体 —— 例如一个包含三个下拉菜单的 Data Picker 组件,而编写自己的自定义组件。JSF 组件是有状态的。组件的无状态是通过 JSF 框架提供的。JSF 使用组件来生成 HTML 响应。
JSF 的组件集包含一个事件发布模型、一个轻量级的 IOC 容器和很多用于几乎所有其他公共 GUI 特性的组件,这些特性包括可插入呈现、服务器端验证、数据转换、页面导航管理,等等。作为基于组件的架构,JSF 是相当可配置和可扩展的。大多数 JSF 功能,比如导航和托管 bean 查看,都可以用可插入的组件替换。这种程度的可插入性给予您在构建 Web 应用程序 GUI 方面相当大的灵活性,并允许您容易地将其他基于组件的技术融入到 JSF 开发中。例如,对于托管 bean 查看,您可以用更加全功能的 IOC/AOP Spring 框架来取代 JSF 的内置 IOC 框架。
JSF 应用程序的用户界面包含 JSP (JavaServer Pages) 页面。每个 JSP 页面包含呈现 GUI 功能的 JSF 组件。可以在 JSP 页面中使用 JSF 自定义标签库来做以下事情:呈现 UI 组件、注册事件处理器、关联组件与验证器、关联组件与数据转换器,等等。
这 就是说,JSF 并不内在地绑定到 JSP 技术。事实上,JSP 页面使用的 JSF 标签只是引用组件,以便显示组件。当您第一次修改 JSP 页面以更改 JSF 组件的属性,并重新加载该页面,看到没有任何事情发生时,您就会认识到这一点。这是因为标签以其当前状态查看组件。因此,如果组件已经存在,自定义标签将 不会修改它的状态。组件模型允许控制器代码更改组件的状态(例如,禁用一个文本字段),并且当显示该视图时,将会显示组件树的当前状态。
典 型的 JSF 应用程序在 UI 中不需要 Java 代码,需要很少的 JSTL EL (JSP Standard Tag Library,一种表示语言) 代码。正如前面提到的,JSF 中有很多用于构建和装配应用程序的 IDE 工具,并且 JSF GUI 组件似乎还有一个正在增长的第三方市场。不使用 WYSIWYG 工具也可以进行 JSF 开发。
|
JSF 是几年前学过的在 Java 平台上改进 Web 开发技术的课程的结果。这一趋势开始于 JSP 技术,这一技术很好,只是很容易在 HTML(和类 HTML)页面中混合 Java 代码。下一次提高是 Model 1 架构,它让开发人员将大多数后端代码放入 JavaBeans 组件中,然后用 <jsp:useBean> 标签将 JavaBeans 组件导入 Web 页面。这对于简单的 Web 应用程序工作得很好,但是许多 Java 开发人员不喜欢 JSP 技术这种与 C++ 特性(比如静态包含)的协作。所以引入了 Model 2 架构。
本质上,Model 2 架构是用于 Web 应用程序的 MVC 的打了折扣的版本(请参阅“关于 MVC”)。在 Model 2 架构中,控制器是由 Servlets 来表示的,而显示则委派给 JSP 页面。Struts 是一种简化的 Model 2 实现,其中的 Actions 代替了 Servlets。在 Struts 中,应用程序的控制器逻辑是与它的数据(由 ActionForms 表示)相分离的。对于 Struts 的主要抱怨是,它感觉上更像过程化的,而不像面向对象的。WebWork 和 Spring MVC 是另外两个 Model 2 架构,它们通过更加不像过程化的,在 Struts 的基础上有所改进,但是它们仍然没有 Struts 那样被广泛接受(或者没有那么成熟,有人可能对此有争议)。并且也不提供像 JSF 提供的那些组件模型。
关于大多数 Model 2 框架的实际问题是,事件模型太简单了(本质上是一个非常缩小的 MVC),这就给开发人员留下了太多的工作。更丰富的事件模型使得创建大多数用户期望的交互更加容易。像 JSP 技术一样,大多数 Model 2 也很容易利用 GUI 自定义标签来混合 HTML 布局和格式化,这些标签有点类似于组件。而有些 Model 架构(比如 Struts)出现分离行为与状态的错误,这让许多 Java 开发人员感觉自己是在进行 COBOL 编程。
JSF 提供一个组件模型和一个比大多数 Model 2 实现更丰富的 MVC 环境。本质上,JSF 比 Model 2 架构更加接近于真正的 MVC 编程环境,尽管它仍然是一种无状态的协议。JSF 也比 Model 2 架构更方便构建更加细致的事件驱动 GUI。尽管 JSF 给了您很多事件选项(菜单项选择、按钮单击,等等),但是大多数 Model 2 依赖于更加简单的“请求接受”。
|
JSF 的良好调优的事件模型,允许您的应用程序与 HTTP 细节的联系更少,并简化了开发。通过使得更加容易将表示和业务逻辑移出控制器,以及将业务逻辑移出 JSP 页面,JSF 也在传统的 Model 2 架构上有了一些改进。事实上,简单的控制器类根本与 JSF 没有联系,这使得它们更加容易测试。与真正的 MVC 架构不一样,JSF 模型层不可能发出许多必须在多个视窗(viewport)中解决的事件;此外,我们仍然在处理无状态的协议,所以这是没必要的。用于更改或更新视图的系统 事件几乎总是(为什么我敢说总是呢?)用户请求。
在 JSF 的 MVC 实现中,mapping backing beans(映射支持 beans)在视图和模型之间调停。因此,限制 backing beans 中的业务逻辑和持久性逻辑很重要。一个常见的替代方法是,将业务逻辑委派给应用程序模型。在这种情况下,backing beans 也映射模型对象,其中视图可以显示它们。另一种选项是,将业务逻辑放在 Business 代表中,后者充当模型。
与 JSP 技术不一样,JSF 的视图实现是一个有状态的组件模型。JSF 视图包含两个部分:视图根和 JSP 页面。视图根是 UI 组件集合,这些组件维护 UI 的状态。与 Swing 和 AWT 一样,JSF 组件使用 Composite 设计模式来管理组件树(简单地说,容器包含组件,容器也是一个组件)。JSP 页面将 UI 组件绑定到 JSP 页面,并允许您将字段组件绑定到 backing beans 的属性(或者属性的属性),以及将按钮绑定到事件处理器和操作方法。
下面是一个从 MVC 角度来看的示例应用程序(后面会详细介绍)。
这已足够小了:我们来看 JSF!
对于本文的其余部分,我把重点放在用 JSF 实际创建应用程序的详细步骤上。该示例应用程序是 JavaServer Faces 技术的一个非常简单的演示。演示了以下几个方面:
|
该 例是一个简单的 Calculator 应用程序。创建该应用程序的目标是向终端用户呈现一个页面,让他/她输入两个数值。因此,该页面具有两个文本字段、两个标签、两个错误消息位置和一个 Submit 按钮。文本字段用于输入数值。标签用于标注字段。错误消息位置用于显示针对文本字段的验证或数据转换错误消息。存在三个 JSP 页面:index.jsp,它只是重定向到 calculator.jsp;calculator.jsp,它呈现前面提到的 GUI;results.jsp,它显示结果。 一个叫做 CalculatorController 的托管 bean 充当 calculator.jsp 和 results.jsp 的 backing bean。
图 2 展示了示例 Calculator 应用程序的第二个 MVC 视图。通过单击本页顶部或底部的 Code 图标,可以下载该应用程序的源代码。
要用 JSF 构建 Calculator 应用程序,需要做以下事情:
Calculator。CalculatorController 与 Calculator 模型交谈。忽略第 1 步,因为这实际上只是设置,我将详细介绍每一步。
为了使用 Faces,首先需要在 web.xml 文件中安装 Faces Servlet,如下所示:
<!-- Faces Servlet --> |
这非常类似于大多数 web.xml 描述符,只是您将控制权交给 JSF Servlet 来处理请求,而不是指定自己的 Servlet。对使用 f:view 的 JSP 文件的所有请求都必须经过该 Servlet。因此,您需要添加一个映射,并且通过该映射只加载支持 JSF 的 JSP 技术,如下所示。
<!-- Faces Servlet Mapping --> |
上面的代码告诉 Faces Servlet 容器,将映射到 /calc/ 的所有请求发送到 Faces Servlet 进行处理。这允许 JSF 初始化 JSF 上下文和视图根。
如果您将外观配置文件命名为 faces-config.xml,并放在您的 Web 应用程序的 WEB-INF 目录中,那么 Faces Servlet 将自动找到并使用它(因为它是默认的)。另外,您也可以通过 web.xml 文件中的一个初始化参数 —— javax.faces.application.CONFIG_FILES —— 用一个以逗号分隔的文件列表作为参数,下载一个或多个应用程序配置文件。您可能愿意对除最简单的之外的所有 JSF Web 应用程序使用第二种方法。
接下来,您将声明哪些 beans 由 JSF GUI 组件使用。该示例应用程序只有一个映射 bean。它配置在 faces-config.xml 中,如下所示:
<faces-config> |
上面的配置告诉 JSF,您想要将一个 bean 添加到叫做 CalcBean 的 JSF 上下文。您可以向自己的托管 bean 调用任何事情。声明了 beans 之后,下一步是为应用程序指出高级别的导航规则。
对于这个简单的应用程序,您只需要建立从 calculator.jsp 页面到 results.jsp 页面的导航规则,如下所示。
<navigation-rule> |
上面的导航规则指出,如果一个操作从 /calculator.jsp 视图返回逻辑结果“success”,那么就会将用户转向 /results.jsp 视图。
由于我的目标是演示如何开始进行 JSF 开发,所以我让模型对象保持非常简单。该应用程序的模型包含在一个模型对象中,如清单 1 所示。