调试 JSF 生命周期——每个阶段到底发生了啥
Posted
技术标签:
【中文标题】调试 JSF 生命周期——每个阶段到底发生了啥【英文标题】:Debugging JSF Life Cycle - what exactly happens in each phase调试 JSF 生命周期——每个阶段到底发生了什么 【发布时间】:2014-03-21 18:35:09 【问题描述】:我决定完全深入研究 JSF 2.0,因为我的项目需要深入了解它。我正在阅读JSF Lifecyle Debug,这是一篇关于 JSF 生命周期的精彩文章。在阅读本文时,我有以下困惑。
如果是初始请求,则在Restore View Phase
中创建一个空视图并直接发生Render Response Phase
。此时没有要保存的状态。那么render response phase
到底发生了什么?我在运行示例时有点困惑。
文章指出,检索到的输入值在Apply Request Values
阶段设置在inputComponent.setSubmittedValue()
中。如果验证和转换通过,则在inputComponent.setValue(value)
和inputComponent.setSubmittedValue(null)
运行中设置该值。在同一点文章指出,现在如果在下一个回发请求中更改了值,则将其与每次回发时始终为空的提交值进行比较,将调用 value change listener
。这意味着如果我们甚至不更改值,因为提交的值将为空,那么 valueChangeListener 将始终被调用?我对这个说法感到困惑。有人可以详细说明一下吗?
文章说明了immediate
属性的用法。如果在输入组件上设置了immediate
属性,则理想情况下会跳过Process Validation Phase
,但所有转换和验证都发生在Apply Request Values
中。我的观点是,仍然在进行转换和验证时,跳过第三阶段有什么好处?
检索值是什么意思?
我想知道,如果假设视图上有五个字段。 JSF 是否会列出这些值的一些集合并 Apply Request Values
和 Process Validations
阶段逐一迭代它们?
在本文的最后一点,它说明了何时使用immediate
属性。据我了解,如果在输入组件和命令组件中都设置了立即属性,它将跳过从应用请求值到调用应用程序的阶段,以获取任何不具有immediate
的属性。那么最后一条语句是什么意思是登录表单中的“忘记密码”按钮,其中包含必填且立即的用户名字段和必填但非立即的密码字段。
我知道这些是非常基本的混淆,但明确这些主题肯定有助于提高 JSF 知识。
【问题讨论】:
【参考方案1】:1:那么在渲染响应阶段实际发生了什么?
为客户端生成 html 输出,从 UIViewRoot#encodeAll()
开始。您可以通过右键单击在 webbrowser 中查看结果 View Source(因此不能通过右键单击,在 webbrowser Inspect Element,因为这只会显示 webbrowser 的 HTML DOM 树已基于原始 HTML 源代码和之后的所有 javascript 事件构建)。
2:与提交的值进行比较,每次回发时该值始终为空
不,它是作为实例变量保存的。 JSF 不会调用getSubmittedValue()
来比较它。
3:我的意思是,仍然在进行转换和验证时,跳过第三阶段有什么好处?
这在文章底部的Okay, when should I use the immediate attribute? 下得到了回答。简而言之:优先验证。如果带有immediate="true"
的组件在转换/验证时失败,那么没有immediate="true"
的组件将不会被转换/验证。
4:检索值是什么意思?
最终用户提交的“原始”值(最终用户在输入表单中输入的确切输入值)。这通常是String
。如果您熟悉 servlet,那么很容易理解,这正是您通过request.getParameter()
获得的值。
5:JSF 是否会列出这些值的一些集合,并在应用请求值和流程验证阶段逐一迭代它们?
几乎。该集合已经存在于 JSF 组件树的风格中。因此,JSF 基本上迭代了一个树结构,从 FacesContext#getUIViewRoot()
开始。
6:那么最后一条语句的含义是什么意思是登录表单中的“忘记密码”按钮,其中包含必填且立即的用户名字段和必填但非立即的密码字段。
这样您就可以在“忘记密码”的情况下重复使用登录表单。如果您提交“登录”按钮,那么显然必须验证用户名和密码字段。但是,如果您提交“忘记密码”按钮,则不应验证密码字段。
也就是说,您可能会发现以下 JSF 阶段/生命周期备忘单对快速参考也很有用:
fc = FacesContext
vh = ViewHandler
in = UIInput
rq = HttpServletRequest
id = in.getClientId(fc);
1
RESTORE_VIEW
String viewId = rq.getServletPath(); fc.setViewRoot(vh.createView(fc, viewId));
2
APPLY_REQUEST_VALUES
in.setSubmittedValue(rq.getParameter(id));
3
PROCESS_VALIDATIONS
Object value = in.getSubmittedValue(); try value = in.getConvertedValue(fc, value); for (Validator v : in.getValidators()) v.validate(fc, in, value); in.setSubmittedValue(null); in.setValue(value); catch (ConverterException | ValidatorException e) fc.addMessage(id, e.getFacesMessage()); fc.validationFailed(); // Skips phases 4+5. in.setValid(false);
4
UPDATE_MODEL_VALUES
bean.setProperty(in.getValue());
5
INVOKE_APPLICATION
bean.submit();
6
RENDER_RESPONSE
vh.renderView(fc, fc.getViewRoot());
另见:
Difference between Apply Request Values and Update Model Values JSF - Another question on Lifecycle What's the view build time?【讨论】:
一如既往的好@BalusC。太感谢了。专家的另一个出色回答。老实说,我很荣幸。以上是关于调试 JSF 生命周期——每个阶段到底发生了啥的主要内容,如果未能解决你的问题,请参考以下文章