JSF 生命周期和自定义组件
Posted
技术标签:
【中文标题】JSF 生命周期和自定义组件【英文标题】:JSF Lifecycle and Custom components 【发布时间】:2010-09-07 04:52:15 【问题描述】:关于在 JSF 中开发自定义组件,有几件事我很难理解。对于这些问题,您可以假设所有自定义控件都使用值绑定/表达式(不是文字绑定),但我也对它们的解释感兴趣。
-
在哪里设置值绑定的值?这应该发生在解码中吗?还是应该 decode 做其他事情,然后在 encodeBegin 中设置值?
从值绑定中读取 - 我何时从值绑定中读取数据,而不是从提交的值中读取数据并将其放入值绑定中?
何时调用与所有这些相关的表单上的动作侦听器? JSF 生命周期页面都提到了在各个步骤中发生的事件,但是当只是调用命令按钮的简单侦听器时,我并不完全清楚
我尝试了一些组合,但最终总是难以找到错误,我认为这些错误来自对事件生命周期的基本误解。
【问题讨论】:
在最初的问题发布将近 10 年之后,收到一个正在接受编辑活动的通知很有趣。 Stack Overflow 那时是一个更简单的地方! 【参考方案1】:JSF specification 中有一个非常好的图表,它显示了请求生命周期 - 对于理解这些内容至关重要。
步骤如下:
恢复视图。 UIComponent 树已重建。 应用请求值。可编辑组件应该实现 EditableValueHolder。此阶段遍历组件树并调用 processDecodes 方法。如果组件不是像 UIData 这样复杂的东西,它除了调用自己的 decode 方法外不会做太多事情。 decode 方法除了找到它的渲染器并调用它的 decode 方法,将自己作为参数传递之外,并没有做太多事情。渲染器的工作是获取任何提交的值并通过 setSubmittedValue 进行设置。 流程验证。此阶段调用 processValidators,后者将调用 validate。 validate 方法获取提交的值,使用任何转换器对其进行转换,使用任何验证器对其进行验证,然后(假设数据通过这些测试)调用 setValue。这会将值存储为局部变量。虽然此局部变量不为空,但它将被返回,而不是任何对 getValue 的调用的值绑定中的值。 更新模型值。这个阶段调用processUpdates。在输入组件中,这将调用 updateModel,后者将获取 ValueExpression 并调用它来设置模型的值。 调用应用程序。按钮事件侦听器等将在此处调用(如果有记忆,导航也会调用)。 呈现响应。树通过渲染器渲染并保存状态。 如果这些阶段中的任何一个阶段失败(例如,值无效),则生命周期会跳到呈现响应。 在大多数这些阶段之后可以触发各种事件,并酌情调用侦听器(例如流程验证之后的值更改侦听器)。这是事件的简化版本。有关详细信息,请参阅规范。
我会质疑您为什么要编写自己的 UIComponent。这是一项艰巨的任务,需要对 JSF 体系结构有深入的了解才能正确完成。如果您需要自定义控件,最好创建一个具体控件,该控件使用等效的渲染器扩展现有 UIComponent(如 htmlInputText 所做的)。
如果污染不是问题,可以使用 Apache MyFaces 形式的开源 JSF 实现。
【讨论】:
【参考方案2】:动作侦听器,例如 CommandButton,在 Invoke Application 阶段被调用,这是最终 Render Response 之前的最后一个阶段> 阶段。这显示在The JSF Lifecycle - figure 1。
【讨论】:
【参考方案3】:这是我唯一的框架 曾经在组件创建的地方使用过 像这样一个深刻而复杂的过程。 没有其他 Web 框架 (无论是否在 .net 世界中) 让这变得如此痛苦,这是 我完全无法解释。
当您考虑目标时,JSF 背后的一些设计决策开始变得更有意义。 JSF 被设计成工具化的——它为 IDE 公开了大量的元数据。 JSF 不是一个 Web 框架——它是一个可以用作 Web 框架的MVP 框架。 JSF 具有高度可扩展性和可配置性 - 您可以基于每个应用程序替换 90% 的实现。
如果您只想插入一个额外的 HTML 控件,那么大多数这些东西只会让您的工作变得更加复杂。
组件是由 几个输入文本(和其他)基础 组件,顺便说一句。
我假设基于 JSP 包含/工具的页面片段不符合您的要求。
我会考虑使用您的 UIComponentELTag.createComponent 创建具有 UIPanel 基础的复合控件,并从现有实现创建其所有子控件。 (我假设您正在使用 JSP/taglibs 并进行其他一些猜测。)如果现有的 UIPanel 渲染器都没有完成这项工作,您可能需要一个自定义渲染器,但渲染器很容易。
【讨论】:
【参考方案4】:我找到的最好的文章是Jsf Component Writing, 至于 2 我在哪里读取组件中值绑定的值,你有一个看起来像这样的 getter
public String getBar()
if (null != this.bar)
return this.bar ;
ValueBinding _vb = getValueBinding("bar");
return (_vb != null) ? (bar) _vb.getValue(getFacesContext()) : null;
这是如何进入 getValueBinding 的? 在你的标签类 setProperties 方法中
if (bar!= null)
if (isValueReference(bar))
ValueBinding vb = Util.getValueBinding(bar);
foo.setValueBinding("bar", vb);
else
throw new IllegalStateException("The value for 'bar' must be a ValueBinding.");
【讨论】:
以上是关于JSF 生命周期和自定义组件的主要内容,如果未能解决你的问题,请参考以下文章