JSF规范(二)

9 篇文章 0 订阅

本文是基于JSF规范的翻译而来,并省掉一些无关紧要的章节。如有不当之处请大家指正。

作者:youfly      email:seedcloned-pub@yahoo.com.cn

转载请注明出处:www.jfuns.com www.jfuns.cn http://blog.csdn.net/youfly

 

2.2 标准处理生命周期阶段

在下面的各个小节中描述了“请求处理生命周期”的各个标准阶段。

2.2.1 Restore View

JSF实现必需在“请求处理生命周期”的Restore View阶段执行下面的各项任务:

调用ViewHandlerinitView()方法。这个过程将为请求设置字符集编码。

检查当前请求的FacesContext实例。如果已存在UIViewRoot

调用当前请求的ExternalContextgetRequestLocale()方法,取得Local,并设置到UIViewRoot中。

对于组件树里的每一个组件, 检查它是否有名为“binding”ValueExpression 如果有,则调用ValueExpression setValue()方法,并传递当件组件实例。

在这个阶段不需要作更多的处理,返回。

根据下面的规则得到当前请求的viewId(view identifier):

如果FacesServlet采用前缀印射 (例如“/faces/*”), viewId根据请求URI的扩展路径信息(extra path information)生成。

如果 FacesServlet 采用的是后缀印射 (例如 “*.faces”),viewId根据请求URIservlet路径信息(servlet path information)生成,并替换后缀为ViewHandler.DEFAULT_SUFFIX_PARAM_NAME指定的上下文(context)指定的初始化参数值。(如果没有指定这个上下文(context)初始化参数值,默认使用ViewHandler.DEFAULT_SUFFIX常量来替换后缀)。

如果不能得到viewId, 则抛出一个异常。在第二章的“请求处理生命周期”2-5介绍。

根据下面的算法判断当前请求是postback还是初始请求。调用应用ViewHandlercalculateRenderKitId() 方法得到当前请求的render-kit-id。并根据render-kit-id得到RenderKitResponseStateManager对象,调用isPostback(),将结果传递给当前的FacesContext

如果一个请求是 non-postback 请求,则调用FacesContext.renderResponse()来跳过中间的各个阶段。

如果一个请求是 postback请求, 则调用ViewHandler.restoreView()方法,并传递当前请求的FacesContext以得到viewId 返回restored viewUIViewRoot对象。如果

ViewHandler.restoreView()方法返回null 则抛出相应出错信息的 ViewExpiredException异常。javax.faces.application.ViewExpiredException 异常是一个FacesException异常。它用来告诉应用viewId对应的view没有被找到,应用可以根据这个异常执行一些动作。

对于组件树里的每一个组件,判断 ValueExpression“binding” 是否存在 如果是则调用 它的setValue()方法,并传递当前的组件实例。处理遵循“parent-first”规则,先调用parentsetValue()方法,然后再调用子节点的setValue()方法。

如果请求是一个non-postback请求, 则调用ViewHandler.createView(), 并传递当前请求的

FacesContext和得到的viewId

       保存创建或者恢复的UIViewRoot对象到当前请求的FacesContext对象中。

 

在这个阶段结束,当前请求的FacesContext实例的viewRoot属性将被恢复成先前由JSF响应保存的配置信息,或者根据得到的viewId调用ViewHandler.createView()创建得到的新实例。

 

2.2.2 ApplyRequest Values

“请求处理生命周期”的Apply Request Values阶段的目的让每个组件有机会根据当前请求信息(parameters, headers, cookies,等等)更新自己的状态。如果当前请求的信息被正确的更新到当前组件的状态中,则这个组件被称为具有“本地值(Local value)”的。

 

Apply Request Values阶段,JSF实现必须调用组件树UIViewRoot对象的processDecodes()方法。这将引起组件是里每个组对于processDecodes()方法的递归调用,就像JavaDocUIComponent.processDecodes()方法所描述的那样。对于UIInput组件,数据转换如JavaDocUIInput所描述的那样发生。

 

decoding请求值的时候,一些组件将执行一些特殊的处理。包括:

实现ActionSource(例如UICommand)的组件,它们能识别自己被激活,并队列ActionEvent 要是组件的immediate属性被设为true,则在Apply Request Values阶段,这些事件被触发,否则在Invoke Application阶段触发这些事件。

实现EditableValueHolder的组件(例如UIInput),如果它的immediate被设置成 true, 则通常在Process Validations阶段发生的数据转换和验证(包括替在的触发 ValueChangeEvent事件)将在Apply Request Values阶段触发。

 

正如2.3部分“Common Event Processing”所描述的,组件树的根对象UIViewRoot.processDecodes()方法将广播所有的事件到感兴趣的监听器中。

 

在这个阶段结束,组件树里的所EditableValueHolder组件将被更新当前请求提交上来的新值()

(如果发生数据转换错误,将保存重新生成错误输入的足够数据)。另外,如果EditableValueHolderimmediate属性被设置成true, 附加的数据转换和验证将被执行。如果发生数据转换或者验证错误,将引起对当前请求的FacesContext. addMessage()方法的调用,将出错信息添加到出错队列中,并设置对应组件的valid属性为false

 

如果任何的decode()方法或者事件监听器所处理的事件队列调用了当前请求的FacesContext 上的responseComplete()方法,都将清除事件队列里的剩余的事件并且结束当前请求的生命周期。否则,控制进入ProcessValidations阶段。

2.2.3 Process Validations

作为创建请求视图的一部分,每一个组件都会注册0个或多个Validator实例。另外,组件类也可能在它的validate()方法里自己实现了验证逻辑。在“请求处理生命周期”的Process Validations阶段,JSF实现必须调用组件树UIViewRoot上的processValidators()方法。该方法将引起对组件树里每个组件的递归调用,就像UIComponent.processValidators()API reference

所描述的那样。请注意如果EditableValueHolder组件的immediate被设置成true的话,它的数据转换和验证将在ApplyRequest Values阶段完成。

 

在处理验证期间,事件被组件队列,Validatorvalidate()方法被调用。正如2.3“Common Event Processing”的描述,UIViewRootprocessValidators()方法将广播所有的事件到感兴趣的事件监听器中。

 

在这个阶段结束,所有的转换及配置的验证都将完成。如果发生数据转换或者验证错误,将引起对当前请求的FacesContext. addMessage()方法的调用,将出错信息添加到出错队列中,并设置对应组件的valid属性为false

 

如果任何被调用的validate()方法,或者事件监听器所处理的事件中调用了当前请求的FacesContext实例上的responseComplete()方法,都将清除事件队列里的剩余的事件并且结束当前请求的生命周期。如果任何被调用的validate()方法,或者事件监听器所处理的事件中调用了当前请求的FacesContext实例上的renderResponse()方法,都将清除事件队列里的剩余事件并且转移控制到“请求处理生命周期”的RenderResponse阶段。否则控制进入Update Model Values阶段。

 

2.2.4 Update Model Values

如果“请求处理生命周期”到达这个阶段,则可以认为进入的请求在语义和语法上是有效的(依据验证已成功的执行),组件树里每个组件的本地值都被更新。因此现在是更新应用程序的模型数据(model data)以准备执行队列里的应用事件的时候了。

Update ModelValues阶段,JSF实现必须调用组件树UIViewRoot上的processUpdates()方法,该方法将引起对每个组件的递归调用。正如API文档对UIComponent.processUpdates()方法所描述的那样。组件实际的模型更新操作是在updateModel()里完成。

 

在处理模型更新期间,被调用updateModel()的组件可能会触发一些事件。正如在2.3 “Common Event Processing”节中的介绍,调用组件树的根节点UIViewRoot上的processUpdates()将广播队列中的事件到感兴趣的事件监听器中。

 

在这个阶段结束后,所有相关的数据模型对象都被更新成和它相匹配的组件对象的本地值(local value),并且组件对象的本地值被清除

 

如果任何被调用的updateModel()方法,或者事件监听器所处理的事件中调用了当前请求的FacesContext实例上的responseComplete()方法,都将清除事件队列里的剩余的事件并且结束当前请求的生命周期。如果任何被调用的updateModel()方法,或者事件监听器所处理的事件中调用了当前请求的FacesContext实例上的renderResponse()方法,都将清除事件队列里的剩余事件并且转移控制到“请求处理生命周期”的RenderResponse阶段。否则控制进入Invoke Application阶段。

 

2.2.5 Invoke Application

 

如果“请求处理生命周期”到达这个阶段,则可以认为所有的模型数据更新都已完成,并且所有剩余的广播到应用的事件都被执行。JSF实现必须确保UIViewRoot实例的processApplication()方法被调用。这个方法的默认行为将广播事件队列中所有指定了阶段IDPhaseId.INVOKE_APPLICATION的事件。如果当前请求的FacesContext实例上的responseComplete()方法被调用,则清除事件队列里的剩余的事件并且结束当前请求的生命周期。如果当前请求的FacesContext实例上的renderResponse()方法被调用也清除事件队列里的剩余的事件并且结束当前请求的生命周期。

 

高级的应用程序(或者应用程序开发框架)可能通过调用Application实例上的setActionListener()方法替换默认的ActionListener实例。然而,JSF实现必须提供默认的ActionListener实例,该默认的实例具体行为在7.1.1“ActionListener Property”节中描述。

2.2.6 Render Response

本阶段完成两件事:

1. 呈现响应到客户端。

2. 保存响应的状态到后续的处理请求中。

 

将这两个任务作为本阶段的职责的原因是,在JSP的应用中,作为页面的呈现者,在呈现页面的时候可能会创建一个视图(view)。因此,我们不能保存状态直到一个视图被创建,并且我们必须在将响应发送到客户端前将状态保存在客户端中。

 

JSF支持一系列方法允许JSF的实现创建对应响应视图内容的响应文本,包括:

■  调用encoding(可以是组件或者对应的renders)方法,直接得到所有的响应内容。

合并组件的encoding结果和应用程序逻辑动态生成的内容。

合并组件的encoding结果和静态模块资源的内容。

■  合并嵌入调用组件的encoding方法得到的结果到动态的资源中(如JSP页面里的自定义标记库组件)。

 

因为存在一定不确定性,实现Render Response阶段的机制不能被精确的指定。但所有的JSF实现者都必须遵循下面的要求:

JSF实现必须提供默认的ViewHandler实现,它能够执行RequestDispatcher.forward()来调用context-relative路径等于组件树的ViewIdweb应用资源。

如果响应的所有内容都通过组件或者Renderers encoding方法得到,则组件树必须用深度优先的方法被遍历,就和前几个阶段处理组件树的方法一样。但也有一些附加的约束在这里列出。

如果响应的内容是从附加的资源和encoding方法合并得到,组件可以选择自己想要的顺序来显现结果

在呈现处理期间,根据ViewHandler的有效信息可以添加附加的组件到组件树中。但是在添加前,ViewHandler的实现必须检查组件树,查看相关的组件是否已经存在。如果组件已经存在(可能在先前的各个阶段预创建了一个或者多个组件),则必须使用已存在的组件的属性。

在没有具体环境的情况下,如果一个组件在组件树中的父组件或者祖先组件的rendersChildren被设置为true,则这个组件也要被呈现。在这种情况下,父组件或者祖先组件被呈现的情况下,它也必须呈现它的子组件。

如果组件的isRendered()方法返回false,则该组件将不生成任何标记本文(markup),并且它的子组件及facets也将不被呈现。

在请求处理的生命周期期间,必须让应用有可能通过编程来修改组件树(在呈现期间除外),并且拥有期望的系统行为。例如,必须允许下面的情况。在呈现期间修改一个view将会产生不可预料的结果。必须允许一个模块系统(例如JSP)在呈现之前添加一个组件到组件树,或者组件树中删除一个组件。必须允许通过编程的方式添加一个组件到组件树中,并且在正确的层次中呈现它们的结果。在呈现这前,必须允许重新排列组件树里的组件。这些处理要求被添加的组件在最靠近的父组件的NamingContainer作用域中具有唯一的ID值。属性rendersChildren的值要求被处理,可能设置成true或者false

 

对于组件树中被选择呈现的每一个组件,必须按照3.1.12“Component Specialization Methods”节所描述的那样调用它的encodeXxx()方法。对于每个一实现了ValueHolder的组件 (例如UIInput UIOutput),必须按照UIOutputJavadocs所描述的那样执行数据转换。

 

在完成呈现后,视图的完成状态必须通过StateManager上的方法保存起来。这些状态信息必须可以让后续的请求访问,所以Restore View 就能够访问这些状态信息。更多的关于StateManager的信息请参考7.6.3 “State Saving Methods”节。

1.Typically, component selection will be driven by the occurrence of specialmarkup (such as the existence of a JSP

customtag) in the template text associated with the component tree.

2. Forexample, this technique is used when custom tags in JSP pages are utilized asthe rendering technology, as described

in Chapter 9“Integration with JSP.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值