简体   繁体   English

JSF生命周期和自定义组件

[英]JSF Lifecycle and Custom components

There are a couple of things that I am having a difficult time understanding with regards to developing custom components in JSF. 关于在JSF中开发自定义组件,我有一些事情很难理解。 For the purposes of these questions, you can assume that all of the custom controls are using valuebindings/expressions (not literal bindings), but I'm interested in explanations on them as well. 出于这些问题的目的,您可以假设所有自定义控件都使用值绑定/表达式(不是文字绑定),但我也对它们的解释感兴趣。

  1. Where do I set the value for the valuebinding? 我在哪里设置值绑定的值? Is this supposed to happen in decode? 这应该在解码中发生吗? Or should decode do something else and then have the value set in encodeBegin? 或者应该解码做其他事情,然后在encodeBegin中设置值?
  2. Read from the Value Binding - When do I read data from the valuebinding vs. reading it from submittedvalue and putting it into the valuebinding? 从值绑定中读取 - 何时从值绑定读取数据与从提交值读取数据并将其放入值绑定?
  3. When are action listeners on forms called in relation to all of this? 何时调用表单上的动作侦听器与所有这些相关? The JSF lifecycle pages all mention events happening at various steps, but its not completely clear to me when just a simple listener for a commandbutton is being called JSF生命周期页面都提到了在各个步骤中发生的事件,但是当我只调用一个简单的commandbutton监听器时,它并不完全清楚

I've tried a few combinations, but always end up with hard to find bugs that I believe are coming from basic misunderstandings of the event lifecycle. 我已经尝试了一些组合,但最终总是很难找到我认为来自对事件生命周期的基本误解的错误。

There is a pretty good diagram in the JSF specification that shows the request lifecycle - essential for understanding this stuff. JSF规范中有一个非常好的图表,它显示了请求生命周期 - 这对理解这些东西至关重要。

The steps are: 步骤是:

  • Restore View . 还原视图 The UIComponent tree is rebuilt. UIComponent树已重建。
  • Apply Request Values . 应用请求值 Editable components should implement EditableValueHolder. 可编辑组件应实现EditableValueHolder。 This phase walks the component tree and calls the processDecodes methods. 此阶段遍历组件树并调用processDecodes方法。 If the component isn't something complex like a UIData, it won't do much except call its own decode method. 如果组件不像UIData那样复杂,除了调用自己的解码方法之外,它不会做太多事情。 The decode method doesn't do much except find its renderer and invokes its decode method, passing itself as an argument. 除了找到它的渲染器并调用其解码方法,将自身作为参数传递之外, decode方法没有太大作用。 It is the renderer's job to get any submitted value and set it via setSubmittedValue . 获取任何提交的值并通过setSubmittedValue设置它是渲染器的工作。
  • Process Validations . 流程验证 This phase calls processValidators which will call validate . 此阶段调用processValidators ,它将调用validate The validate method takes the submitted value, converts it with any converters, validates it with any validators and (assuming the data passes those tests) calls setValue . validate方法获取提交的值,使用任何转换器转换它,使用任何验证器验证它并(假设数据通过那些测试)调用setValue This will store the value as a local variable. 这会将值存储为局部变量。 While this local variable is not null, it will be returned and not the value from the value binding for any calls to getValue . 虽然此局部变量不为null,但它将返回,而不是任何getValue调用的值绑定值。
  • Update Model Values . 更新模型值 This phase calls processUpdates . 此阶段调用processUpdates In an input component, this will call updateModel which will get the ValueExpression and invoke it to set the value on the model. 在输入组件中,这将调用updateModel ,它将获取ValueExpression并调用它以设置模型上的值。
  • Invoke Application . 调用应用程序 Button event listeners and so on will be invoked here (as will navigation if memory serves). 将在此处调用按钮事件侦听器等(如果内存服务则将导航)。
  • Render Response . 渲染响应 The tree is rendered via the renderers and the state saved. 树通过渲染器渲染并保存状态。
  • If any of these phases fail (eg a value is invalid), the lifecycle skips to Render Response. 如果这些阶段中的任何一个失败(例如,值无效),则生命周期将跳至“渲染响应”。
  • Various events can be fired after most of these phases, invoking listeners as appropriate (like value change listeners after Process Validations). 在大多数这些阶段之后可以触发各种事件,适当地调用侦听器(比如在过程验证之后的值更改侦听器)。

This is a somewhat simplified version of events. 这是一个有点简化的事件版本。 Refer to the specification for more details. 有关更多详细信息,请参阅规范。

I would question why you are writing your own UIComponent. 我会问你为什么要编写自己的UIComponent。 This is a non-trivial task and a deep understanding of the JSF architecture is required to get it right. 这是一项非常重要的任务,需要深入了解JSF架构才能使其正确。 If you need a custom control, it is better to create a concrete control that extends an exisiting UIComponent (like HtmlInputText does) with an equivalent renderer. 如果需要自定义控件,最好创建一个具有等效渲染器的扩展UIComponent(如HtmlInputText)的具体控件。

If contamination isn't an issue, there is an open-source JSF implementation in the form of Apache MyFaces. 如果污染不是问题,那么就有Apache MyFaces形式的开源JSF实现。

Action listeners, such as for a CommandButton , are called during the Invoke Application phase, which is the last phase before the final Render Response phase. Invoke Application阶段调用 Action侦听器,例如CommandButton ,这是最终渲染响应阶段之前的最后阶段。 This is shown in The JSF Lifecycle - figure 1 . 这在JSF生命周期中显示 - 图1

It is the only framework that I've ever used where component creation is a deep intricate process like this. 它是我曾经使用的唯一框架,其中组件创建是一个如此深刻复杂的过程。 None of the other web frameworks (whether in the .net world or not) make this so painful, which is completely inexplicable to me. 其他网络框架(无论是否在.net世界中)都没有让这么痛苦,这对我来说是完全无法解释的。

Some of the design decisions behind JSF start to make a little more sense when you consider the goals. 当您考虑目标时,JSF背后的一些设计决策开始变得更有意义。 JSF was designed to be tooled - it exposes lots of metadata for IDEs. JSF被设计为加工 - 它为IDE公开了大量元数据。 JSF is not a web framework - it is a MVP framework that can be used as a web framework. JSF不是一个Web框架 - 它是一个可以用作Web框架的MVP框架。 JSF is highly extensible and configurable - you can replace 90% of the implementation on a per-application basis. JSF具有高度可扩展性和可配置性 - 您可以在每个应用程序的基础上替换90%的实现。

Most of this stuff just makes your job more complicated if all you want to do is slip in an extra HTML control. 大多数这些东西只会让你的工作变得更加复杂,如果你想要做的就是使用额外的HTML控件。

The component is a composition of several inputtext (and other) base components, btw. 该组件是几个inputtext(和其他)基本组件的组合,顺便说一句。

I'm assuming JSP-includes/tooling-based page fragments don't meet your requirements. 我假设JSP-includes /基于工具的页面片段不符合您的要求。

I would consider using your UIComponentELTag.createComponent to create a composite control with a UIPanel base and creating all its children from existing implementations. 我会考虑使用您的UIComponentELTag.createComponent来创建具有UIPanel基础的复合控件,并从现有实现创建其所有子项。 (I'm assuming you're using JSPs/taglibs and making a few other guesses.) You'd probably want a custom renderer if none of the existing UIPanel renderers did the job, but renderers are easy. (我假设您正在使用JSP / taglib并进行其他一些猜测。)如果现有的UIPanel渲染器都没有完成这项工作,您可能需要自定义渲染器,但渲染器很容易。

The best article I've found is Jsf Component Writing , as for 2 where do I read the value for a value binding in your component you have a getter that looks like this 我发现的最好的文章是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;  
}

how did this get into the getValueBinding? 这是怎么进入getValueBinding的? In your tag class setProperties method 在您的标记类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.");  
         }  
     }  

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM