当浏览器首先连接到http://localhost:8080/faces/index.xhtml时,JSF实现初始化JSF代码并读取index.xhtml页面。这个页面包含诸如h:inputText等JSF标签。每个标签都有一个相关的标签处理程序类。当读取该页面时,执行相应的标签处理程序。JSF标签处理程序彼此协作来构建一棵组件树。
组件树是一种数据结构,其中包含JSF页面上所有用户界面元素的Java对象。例如UIInput对象分别对应于JSF文件中的h:inputText和h:inputSecret字段。
呈现页面
接着呈现HTML页面。除JSF标签外的所有文本直接显示。h:form、h:inputText、h:inputSecret和h:commandButton标签则被转换为HTML。其中每个标签都调用相关的组件。每个组件有一个呈现器以生成HTML输出,反映组件状态。例如,与h:inputText标签对应的组件呈现器生成以下输出:
<input type="text" name="unique ID" value="current value"/>
这个进程称为编码。UIInput对象的呈现器要求JSF实现查找user.name表达式的唯一ID和当前值。默认情况下,由JSF实现指定ID字符串。ID看上去是随机的。
编码页被发送到浏览器,浏览器按通常的方式显示它。
请求解码
当在浏览器中显示页面后,用户填写表单字段并单击登录按钮。浏览器将表单数据发回到Web服务器,格式化为一个POST请求。这是一种特殊格式,并被定义为HTML协议的一部份。POST请求包含表单的URL(/faces/index.xhtml)以及表单数据。
注意:POST请求的URL与呈现表单的请求的URL一样。在提交表单后,将导航到新页面(由于这个原因,浏览器中显示的URL通常比所显示JSF页面的URL晚一步)。
表单数据是ID/值对形式的字符串,使用“&”连接多个键。作为正常请求处理的一部份,表单数据位于所有组件都可以访问的Hash表中。
接下来,JSF实现为每个组件提供了一个检查Hash表的机会,这个过程称为解码。每个组件自行决定如何解释表单数据。
登录表单有三个组件对象:两个UIInput对象(与表单的文本字段对应)和一个UICommand对象(与提交按钮对应)。
- UIInput组件更新value特性中引用的bean属性:它们使用用户提供的值调用setter方法。
- UICommand组件检查用户是否单击了按钮。如果单击了,它触发动作事件来启动action特性引用的login操作。这个事件告诉导航处理程序查找后续页面welcome.xhtml。
然后重复以上步骤。
JSF实现的两个最重要的处理步骤:编码和解码。但是,处理顺序(也称为生命周期)则较为复杂。如果一切正常,那么用户则不必担心生命周期的复杂性。然而,当发生错误时,就必须了解JSF实现做了什么。
生命周期
JSF规范定义了六个不同的阶段:
- 还原视图
- 应用请求值
- 过程验证(处理验证)
- 更新模型值
- 调用应用程序
- 呈现响应
这里讲述生命周期最常见的流程:
- 如果请求的页面曾在以前显示过,“还原视图”阶段将检索请求页面的组件树;如果请求页面首次显示,“还原视图”将创建组件新的组件树。
- 如果没有请求值,JSF实现会直接跳转到前面的“呈现响应”阶段。这发生在页面第一次显示之时。否则进入(3)。
- 如果有请求值,则进入“应用请求值”阶段。在此阶段,JSF实现迭代组件树中的每个组件对象。每个组件对象都检查哪些请求值属于自己并将其存储。存储在组件中的值称为“本地值”。当设计JSF页面时,可添加验证器以验证本地值的正确性。这些验证器在“处理验证”阶段执行。如果通过验证,JSF生命周期正常进行。但当发生转换或验证错误时,JSF实现会直接调用“呈现响应”阶段,重新显示当前页以便用户有机会再次提供正确输入。
注意:如果转换器或验证器失败,只是重新显示当前页。应该添加标签来显示验证错误,以便让用户知道为什么他们又一次看到了以前的页面。 - 在转换器和验证器完成工作后,即认为可以安全地更新模型数据。在“更新模型值”阶段,会使用本地值来更新与组件关联的bean。
- 在“调用应用程序”阶段,引起表单提交的按钮或链接组件的action方法被执行。该方法可以执行任意的应用程序处理。它返回的结果字符串传给导航处理程序。导航处理程序然后查找下一个页面。
- 最后,“呈现响应”阶段对响应进行编码,并将它发回浏览器。当用户提交表单、单击链接或者生成新请求时,这个循环重新开始。
注意:在Ajax应用中,Ajax请求将输入组件添加到execute列表中,将输出组件添加到render列表中。对execute列表中的组件来说,会执行除“呈现响应”外的所有阶段。确切地讲,在“更新模型值”阶段,会更新模型bean。与此相反,对于render列表中的组件来说,仅执行生命周期的“呈现响应”阶段,结果被发回到Ajax请求。