3 自订组件
3.1 JSF 生命周期与组件概述
要开发 JSF 组件,您需要更深入了解 JSF 的一些处理细节,包括了 JSF 生命周期以 及 JSF 框架。
3.1.1 JSF 生命周期
JSF 的每个组件基本上都是可替换的,像是转换器(Converter)、验证器(Validator)、
组件(Component)、绘制器(Renderer)等等,每个组件都可以替换让 JSF 在使用时更有 弹性,但相对的所付出的就是组件组合时的复杂性,为此,最基本的,如果您打算自订一 些 JSF 组件,那么您对于 JSF 处理请求的每个阶段必须要有所了解。
下图是 JSF 处理请求时的每个阶段与简单说明,起始状态即使用者端发出请求时,终止状 态则相当于绘制器发出响应时:
扣除事件处理,JSF 总共必须经过六个阶段:
• 回复画面(Restore View)
对于选择的页面如果是初次浏览则建立新的组件树。如果是会话阶段,会从使用者端或服 务器端的数据找寻数据以回复每个组件的状态并重建组件树,如果不包括请求参数,则直 接跳过接下来的阶段直接绘制响应。
• 套用申请值(Apply Request Values)
每个组件尝试从到来的请求中找寻自己的参数并更新组件值,在这边会触发 ActionEvent,
这个事件会被排入队列中,然后在唤起应用程序阶段之后才会真正由事件处理者进行处理。
然而对于设定 immeduate 为 true 的命令(Commamnd)组件来说,会立即处理事件并跳过之 后的阶段直接绘制响应,而对于设定 immediate 为 true 的输入(Input)组件,会马上进 行转换验证并处理值变事件,之后跳过接下来的阶段,直接绘制响应。
• 执行验证(Process Validations)
进行转换与验证处理,如果验证错误,则会跳过之后的阶段,直接绘制响应,结果是重新 呼叫同一页绘制结果。
• 更新模型值(Update Model Values)
更新每一个与组件绑定的 backing bean 或模型对象。
• 唤起应用程序(Invoke Application)
处理动作事件,并进行后端应用程序逻辑。
• 绘制回应(Render Response)
使用绘制器绘制页面。
如果您只是要「使用」JSF,则您最基本的只需要知道「执行验证」、「更新模型值」、与
「唤起应用程序」这三个阶段及中间的事件触发,JSF 参考实作将这三个阶段之外的其它阶 段之复杂性隐藏起来了,您不需要知道这几个阶段的处理细节。
然而如果您要自订组件,则您还必须知道「回复画面」、「套用请求值」与「绘制响应」
这些阶段是如何处理的,这几个阶段相当复杂,所幸的是您可以使用 JSF 所提供的框架来 进行组件自订,JSF 提供的框架已经很大程度上降低了组件制作的复杂性。
当然,即使 JSF 框架降低了复杂性,但实际上要处理 JSF 自订组件还是很复杂的一件事,
在尝试开发自订组件之前,您可以先搜寻一些网站,像是 Apache MyFaces,看看是不是已 经有相关类似的组件已经开发完成,省去您重新自订组件的气力。
3.1.2 概述自订组件
所谓的「自订 JSF 组件」是一个概略的称呼,事实上,一个 JSF 组件包括了三个部份:Tag、
Component 与 Renderer。
Tag 即之前一直在使用的 JSF 标签,类似于 HTML 标签,JSF 标签主要是方便网页设计人员 进行版面配置与数据呈现的一种方式,实际的处理中,JSF 标签的目的在于设定 Component 属性、设定验证器、设定数据绑定、设定方法绑定等等。
Component 的目的在于处理请求,当请求来到服务器端应用程序时,每一个 Component 都有 机会根据自己的 client id,从请求中取得属于自己的值,接着 Component 可以将这个值作 处理,然后设定给绑定的 bean。
当请求来到 Web 应用程序时,HTTP 中的字符串内容可以转换为 JSF 组件所需的值,这个动 作称之为译码(decode),相对的,将 JSF 组件的值转换为 HTTP 字符串数据并送至客户端,
这个动作称之为编码(encode),Component 可自己处理编码、译码的任务,也可以将之委 托给 Renderer 来处理。
当您要自订 Component 时,您可以继承 UIComonent 或其相关的子类别,这要根据您实际要 自订的组件而定,如果您要自订一个输出组件,可以继承 UIOutput,如果要自订一个输入 组件,则可以继承 UIInput,每一个标准的 JSF 组件实际上都对应了一个 UIComponent 的 子类别,下图为一个大致的类别继承架构图:
实际上要自订一个组件是复杂的一件工作,您首先要学会的是一个完整的自订组件流程,
实际上要自订一个组件时,您可以参考一下网络上的一些成品,例如 Apache MyFaces,接 下来后面的几个主题所要介绍的,将只是一个自订组件的简单流程。
Renderer 是一个可替换的组件,您的 Component 可以搭配不同的 Renderer,而不用自行担 任绘制响应或译码的动作,这会让您的 Component 可以重用,当您需要将响应从 HTML 转换 为其它的媒介时(例如行动电话网络),则只要替换 Renderer 就可以了,这是一个好处,
或者您可以简单的替换掉一个 Renderer,就可以将原先简单的 HTML 响应,替换为有 JavaScript 功能的 Renderer。
当您开始接触自订组件时,您会开始接触到 JSF 的框架(Framework),也许有几个类别会 是您经常接触的:
• javax.faces.component.UIComponent
自订 Component 所要继承的父类别,但通常,您是继承其子类别,例如 UIInput、UIOutput 等等。
• javax.faces.webapp.UIComponentTag
自订 JSF 标签所要继承的父类别,继承它可以帮您省去许多 JSF 标签处理的细节。
• javax.faces.context.FacesContext
包括了 JSF 相关的请求信息,您可以透过它取得请求对象或请求参数,或者是 javax.faces.application.Application 物件。
• javax.faces.application.Application
包括了一个应用程序所共享的信息,像是 locale、验证器、转换器等等,您可以透过一些 工 厂方法 取得相关的信息。