日期:2014-05-16  浏览次数:20462 次

深入理解JSF原理与执行过程

转载于http://www.ibm.com/developerworks/cn/java/j-jsf2/
JSF 生命周期:概述
JSF 程序生命周期的 5 个阶段如下(注意每个阶段的事件处理):
恢复视图
应用请求的值;处理验证
更新模型值;处理事件
调用程序;处理事件
进行响应;处理事件
这 5 个阶段显示了 JSF 通常处理 GUI 的顺序。虽然这个清单列出了每个阶段中事件处理的可能执行顺序,但是 JSF 的生命周期很难是固定一成不变的。您可以通过忽略某个阶段或合并整个生命周期从而对执行顺序进行修改。例如,如果一个无效的请求值被拷贝到一个组件中,那么当前的视图就会重新显示,而有些阶段就可能不会执行。在这种情况中,您可以执行一个 FacesContext.responseComplete方法调用,将用户重定向到一个不同的页面上,然后使用请求分发器(从 FacesContext中的请求对象中获得)将其转发到一个适当的 Web 资源上。另外,您可以调用 FacesContext.renderResponse重新显示原来的视图。(详细信息请参看下面的示例程序。)
关于本系列文章
这个 4 部分的系列文章专门用来消除那些怀疑论者对 JavaServer Faces(JSF)技术的恐惧、怀疑或疑虑(FUD),方法是给您一个机会自己通过一个一步步的、容易学习的格式来了解这种技术。通过这 4 篇文章的教程介绍,我们将提供一系列的例子简要介绍 JSF 的基本架构、特性和功能。一旦熟悉 JSF 处理事情的方法之后,我想您将发现很难再返回 Struts Model 2 风格的开发了。毕竟,在体验过 JSF 的事件驱动的 GUI 组件模型之后,谁还会希望重新经历 XML 配置的恶梦呢?
要掌握本系列教程的内容,您应该熟悉 Java 编程、JavaBeans(即事件模型和属性)、JavaServer Pages(JSP)、JSP Standard Tag Library Expression Language 以及 Web 开发的所有基本概念。
关键是让生命周期构成您的开发项目,而不完全依赖于生命周期。在需要时,您可以修改生命周期,而不用担心破坏您的程序。在大部分情况中,您会发现 JSF 的生命周期是值得遵守的,因为它的逻辑非常好。表单必须在任何应用程序逻辑执行之前进行验证,并且在进行验证之前,必须对域中的数据进行转换。遵守生命周期的规定,可以让您更自由地考虑有关验证和转换的问题,而不是请求处理本身的阶段。有一点非常重要:其他 Web 框架也都具有类似的生命周期;它们只不过是没有很好地进行宣传。
专注
有些使用 JSF 的开发者可能从来都不会编写一个组件,也不会对框架进行任何扩展;而另外一些人则专注于这种任务的开发。尽管 JSF 的生命周期与大部分那其他项目都是相同的,但是根据在项目中的角色您可以采用不同的阶段。如果您更专注于通用的应用程序开发,就可能会关注请求处理生命周期的中间阶段:
应用请求值
更新模型值
调用程序
如果您专注于 JSF 组件的开发,就可能会关注于整个生命周期中的第一个阶段和最后一个阶段:
恢复视图
进行响应
在接下来的几节中,我们将遍历 JSF 请求处理生命周期的每个步骤,包括事件处理和验证。了解了每个步骤的基本知识之后,我们将简要介绍一个示例程序,它可以展示这些步骤如何一起使用。在开始之前,首先来看一下图 1,这是一个有关 JSF 生命周期的图。

图 1. JSF 生命周期
 
回页首
阶段 1:恢复视图
在 JSF 生命周期的第一个阶段 —— 恢复视图—— 中,会有一个来自 FacesServlet控制器的请求。控制器会对请求进行考查,并提取出视图的 ID,这是由 JSP 页面的名字来确定的。
JSF 框架控制器使用这个视图 ID 来为当前的视图查找组件。如果这个视图尚未存在,那么 JSF 控制器就会创建它。如果这个视图早已存在,那么 JSF 控制器就会使用它。这个视图包含了所有的 GUI 组件。
生命周期的这个阶段表示为三个视图实例:新视图、原始视图和后视图,每个视图的处理方式都不相同。在 新视图的情况中,JSF 会构建 Faces页面的视图,并将事件处理程序和验证程序绑定到组件上。这个视图被保存在一个 FacesContext对象中。
FacesContext对象包含了 JSF 用来管理当前会话中当前请求的 GUI 组件状态所需要的所有状态信息。FacesContext将视图保存在自己的 viewRoot属性中;viewRoot包含了当前视图 ID 的所有 JSF 组件。
在 原始视图的情况中(第一次加载的是一个页面),JSF 会创建一个空视图。这个空视图会在用户事件产生时进行填充。JSF 可以直接从原始视图过渡到进行响应的阶段。
在 后视图(postback)的情况中(用户返回之前访问过的页面),包含页面的视图早已经存在了,因此只需要进行恢复就可以了。在这种情况中,JSF 就使用现有视图的状态信息来重构状态。后视图的下一个阶段是应用请求值。
回页首
阶段 2:应用请求值
应用请求值阶段的目的是让每个组件检索自己当前的状态信息。这些组件必须首先通过 FacesContext对象进行检索或创建(使用其值)。虽然组件值也可以从 cookie 或头文件中进行检索,但是它们通常是通过请求参数进行检索的。
如果一个组件的即时事件处理属性 没有设置为 true,那么就会对这些值进行转换。因此,如果 域被绑定到一个 Integer属性上,那么该值就会被转换为一个 Integer类型。如果值的转换失败了,那么就会生成一个错误消息,并在 FacesContext中进行排队,在产生响应的阶段会显示其中的消息,同时还会显示所有的验证错误。
如果一个组件的即时事件处理属性 的确被设置为 true,那么这些值就会被转换为适当的类型,并进行有效性验证。然后转换后的值会被保存到组件中。如果值转换或值的有效性验证失败了,就会生成一个错误消息,并在 FacesContext中进行排队,在产生响应的阶段会显示其中的消息,同时还会显示所有的验证错误。
即时事件处理
JSF 的即时事件处理属性用来处理那些通常不必要对整个表单进行有效性验证的事件。例如,假设一个雇员表单中有一个单选按钮来说明他是否是经理。当他选中 Manager 选项时,应用程序就会为经理生成一些内容。由于单选按钮只用来生成一个列表,而不需要用户填写整个表单,因此不需要对整个表单进行有效性验证。在这种情况中,您就可以使用即时事件处理。有关这个主题的更详细内容,请参阅 即时事件处理。
处理验证
生命周期中的第一个事件处理发生在应用请求值阶段之后。在这个阶段中,每个组件都有一些值需要根据应用程序的验证规则进行有效性验证。这些验证规则可以是预先进行定义的(JSF 中提供的),也可以由开发者进行定义。用户所输入的值会与这些验证规则进行比较。如果说输入的值无效,就会向 FacesContext中添加一个错误消息,并且该组件会被表示为无效的。如果一个组件被表示为无效的,那么 JSF 就会转到产生响应的阶段,在这个阶段中会显示当前的视图,以及验证错误消息。如果没有有效性验证错误,那么 JSF 就会转到更新模型值的阶段。
回页首
阶段 3:更新模型值
JSF 应用程序生命周期中的第三个阶段 —— 更新模型值—— 负责更新服务器端模型的实际值,通常来讲,这都是通过更新后台 bean(称为管理 bean)的属性实现的。只有那些与组件值绑定在一起的 bean 属性才会被更新。注意这个阶段发生在有效性验证之后,因此可以确保拷贝到 bean 属性的值都是有效的(至少在表单域一级都是有效的;在业务规则一级仍可能无效)。
回页首
阶段 4:调用程序
在生命周期的第四个阶段 —— 调用程序—— 中,JSF 控制程序会调用程序来处理 表单的提交操作。组件值已经经过了类型转换和有效性验证,并被应用到模型对象中了,因此您现在可以使用它们来执行应用程序的业务逻辑了。
在这个阶段,您还可以为一个给定的序列或很多可能的序列指定后面的逻辑视图,这可以通过为一次成功的表单提交定义一个特定的结果并返回这个结果来实现。例如:在成功输出时,将用户重定向到下一页中。要让这种导航工作能够起作用,您需要在 faces-config.xml 文件中创建一个到 成功输出的映射作为一条导航规则。一旦导航发生之后,您就转换到生命周期的最后一个阶段了。
回页首
阶段 5:进行响应
在生命周期的第五个阶段 —— 进行响应—— 中,您可以在视图中显示当前状态中的所有组件。
图 2 是 JSF 生命周期的第五个阶段的一个对象状态图,包括时间有效性验证和处理。

图 2. JSF 生命周期的五阶段
 
回页首
范例
现在您已经对 JSF 生命周期的阶段有了基本的了解,下面我们将向您介绍在一个范例 Web 应用程序中,这些阶段是如何协同工作的。除了展示 JSF 生命周期的基本功能之外,这个应用程序还会利用一些通用的 JSF GUI 组件,例如 Radio List, List, Text Field, Label, Panel 等等,这样您就可以亲自体验一下在 第 1 部分中曾经简要讨论过的这些组件。
这个示例程序还会展示在 JSF 中使用其他 Java 技术的两种方法。它将组合使用 JSF 和