JSF生命周期和自定义组件

时间:2008-08-28 21:48:57

标签: java jsf java-ee custom-component

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

  1. 我在哪里设置值绑定的值?这应该在解码中发生吗?或者应该解码做其他事情,然后在encodeBegin中设置值?
  2. 从值绑定中读取 - 何时从值绑定中读取数据与从提交值读取数据并将其放入值绑定?
  3. 什么时候调用表单上的动作侦听器? JSF生命周期页面都提到了在各个步骤中发生的事件,但是当我只调用一个名为commandbutton的简单监听器时,它并不完全清楚
  4. 我尝试了一些组合,但最终总是很难找到我认为来自对事件生命周期的基本误解的错误。

4 个答案:

答案 0 :(得分:19)

JSF specification中有一个很好的图表显示了请求生命周期 - 这对于理解这些内容至关重要。

步骤如下:

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

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

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

如果污染不是问题,那么就有一个Apache MyFaces形式的开源JSF实现。

答案 1 :(得分:3)

动作侦听器(例如 CommandButton )在 Invoke Application 阶段被调用,这是最终渲染响应之前的最后阶段>阶段。这显示在The JSF Lifecycle - figure 1

答案 2 :(得分:2)

  

这是我唯一的框架   曾经用过组件创建的地方   这样一个深刻复杂的过程。   没有其他Web框架   (无论是否在.net世界)   让这很痛苦,这是   对我来说完全莫名其妙。

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

如果你想要做的就是使用额外的HTML控件,大部分内容都会让你的工作变得更复杂。

  

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

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

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

答案 3 :(得分:1)

我发现的最好的文章是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.");  
         }  
     }