JSF生命周期和自定义组件

关于在JSF中开发自定义组件,我有一些事情很难理解。 出于这些问题的目的,您可以假设所有自定义控件都使用值绑定/表达式(不是文字绑定),但我也对它们的解释感兴趣。

  1. 我在哪里设置值绑定的值? 这应该在解码中发生吗? 或者应该解码做其他事情,然后在encodeBegin中设置值?
  2. 从值绑定中读取 – 何时从值绑定读取数据与从提交值读取数据并将其放入值绑定?
  3. 什么时候调用表单上的动作侦听器? JSF生命周期页面都提到了在各个步骤中发生的事件,但是当我只调用一个简单的commandbutton监听器时,它并不完全清楚

我已经尝试了一些组合,但总是很难找到我认为来自对事件生命周期的基本误解的错误。

JSF规范中有一个非常好的图表,它显示了请求生命周期 – 这对理解这些东西至关重要。

步骤是:

  • 恢复视图 。 UIComponent树已重建。
  • 应用请求值 。 可编辑组件应实现EditableValueHolder。 此阶段遍历组件树并调用processDecodes方法。 如果组件不像UIData那样复杂,除了调用自己的解码方法之外,它不会做太多事情。 除了找到它的渲染器并调用其解码方法并将其自身作为参数传递之外, 解码方法没有太大作用。 获取任何提交的值并通过setSubmittedValue设置它是渲染器的工作。
  • 流程validation 。 此阶段调用processValidators ,它将调用validatevalidate方法接受提交的值,将其转换为任何转换器,使用任何validation器validation它并(假设数据通过这些测试)调用setValue 。 这会将值存储为局部变量。 虽然此局部变量不为null,但它将返回,而不是任何getValue调用的值绑定值。
  • 更新模型值 。 此阶段调用processUpdates 。 在输入组件中,这将调用updateModel ,它将获取ValueExpression并调用它以设置模型上的值。
  • 调用应用程序 。 将在此处调用按钮事件侦听器等(如果内存服务则将导航)。
  • 渲染响应 。 树通过渲染器渲染并保存状态。
  • 如果这些阶段中的任何一个失败(例如,值无效),则生命周期将跳至“渲染响应”。
  • 在大多数这些阶段之后可以触发各种事件,适当地调用侦听器(比如在Process Validations之后的值更改侦听器)。

这是一个稍微简化的事件版本。 有关更多详细信息,请参阅规范。

我会问你为什么要编写自己的UIComponent。 这是一项非常重要的任务,需要深入了解JSF架构才能使其正确。 如果需要自定义控件,最好创建一个具有等效渲染器的扩展UIComponent(如HtmlInputText)的具体控件。

如果污染不是问题,那么就有Apache MyFacesforms的开源JSF实现。

Invoke Application阶段调用 Action侦听器,例如CommandButton ,这是最终渲染响应阶段之前的最后阶段。 这在JSF生命周期中显示 – 图1 。

它是我曾经使用的唯一框架,其中组件创建是一个如此深刻复杂的过程。 其他网络框架(无论是否在.net世界中)都没有让这么痛苦,这对我来说是完全无法解释的。

当您考虑目标时,JSF背后的一些设计决策开始变得更有意义。 JSF旨在加工 – 它为IDE公开了大量元数据。 JSF不是一个Web框架 – 它是一个可以用作Web框架的MVP框架。 JSF具有高度可扩展性和可配置性 – 您可以在每个应用程序的基础上替换90%的实现。

大多数这些东西只会让你的工作变得更复杂,如果你想要做的就是使用额外的HTML控件。

该组件是几个inputtext(和其他)基本组件的组合,顺便说一句。

我假设JSP-includes /基于工具的页面片段不符合您的要求。

我会考虑使用您的UIComponentELTag.createComponent创建一个具有UIPanel基础的复合控件,并从现有实现创建其所有子项。 (我假设您正在使用JSP / taglib并进行一些其他猜测。)如果现有的UIPanel渲染器都没有完成这项工作,您可能需要自定义渲染器,但渲染器很容易。

我发现的最好的文章是Jsf组件编写 ,对于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."); } }