java JSF 生命周期和自定义组件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33476/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JSF Lifecycle and Custom components
提问by jsight
There are a couple of things that I am having a difficult time understanding with regards to developing custom components in 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.
关于在 JSF 中开发自定义组件,有几件事我很难理解。对于这些问题,您可以假设所有自定义控件都使用值绑定/表达式(不是文字绑定),但我也对它们的解释感兴趣。
- 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?
- Read from the Value Binding - When do I read data from the valuebinding vs. reading it from submittedvalue and putting it into the valuebinding?
- 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
- 我在哪里设置值绑定的值?这应该发生在解码中吗?或者应该 decode 做其他事情然后在 encodeBegin 中设置值?
- 从值绑定中读取 - 我什么时候从值绑定中读取数据与从提交的值中读取数据并将其放入值绑定中?
- 什么时候调用与所有这些相关的表单上的动作侦听器?JSF 生命周期页面都提到了在各个步骤发生的事件,但是当仅调用命令按钮的简单侦听器时,我并不完全清楚
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.
我尝试了几种组合,但最终总是很难找到错误,我认为这些错误来自对事件生命周期的基本误解。
回答by McDowell
There is a pretty good diagram in the JSF specificationthat shows the request lifecycle - essential for understanding this stuff.
JSF 规范中有一个很好的图表,它显示了请求生命周期——对于理解这些东西至关重要。
The steps are:
步骤是:
- Restore View. The UIComponent tree is rebuilt.
- Apply Request Values. Editable components should implement EditableValueHolder. This phase walks the component tree and calls the processDecodesmethods. If the component isn't something complex like a UIData, it won't do much except call its own decodemethod. The decodemethod doesn't do much except find its renderer and invokes its decodemethod, passing itself as an argument. It is the renderer's job to get any submitted value and set it via setSubmittedValue.
- Process Validations. This phase calls processValidatorswhich will call validate. The validatemethod takes the submitted value, converts it with any converters, validates it with any validators and (assuming the data passes those tests) calls 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.
- Update Model Values. This phase calls processUpdates. In an input component, this will call updateModelwhich will get the ValueExpressionand invoke it to set the value on the model.
- 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 (e.g. 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).
- 恢复视图。UIComponent 树被重建。
- 应用请求值。可编辑组件应实现 EditableValueHolder。此阶段遍历组件树并调用processDecodes方法。如果组件不是像 UIData 这样复杂的东西,除了调用自己的decode方法外,它不会做太多事情。该解码方法并没有做太多除外找到它的渲染器和调用其解码方法,将自身作为一个参数。渲染器的工作是获取任何提交的值并通过setSubmittedValue设置它。
- 过程验证。此阶段调用将调用validate 的processValidators。的验证方法以提交的值,与任何转换器将其转换,与任何验证器验证它和(假定该数据传送的那些测试)调用的setValue。这会将值存储为局部变量。虽然这个局部变量不为空,但它会被返回,而不是任何对getValue调用的值绑定中的值。
- 更新模型值。此阶段调用processUpdates。在输入组件中,这将调用updateModel,它将获取ValueExpression并调用它来设置模型上的值。
- 调用应用程序。按钮事件侦听器等将在此处调用(如果没有记错,导航也将被调用)。
- 渲染响应。树通过渲染器渲染并保存状态。
- 如果这些阶段中的任何一个失败(例如一个值无效),生命周期就会跳到渲染响应。
- 在这些阶段的大多数之后,可以触发各种事件,根据需要调用侦听器(例如流程验证之后的值更改侦听器)。
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. This is a non-trivial task and a deep understanding of the JSF architecture is required to get it right. 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。这是一项非常重要的任务,需要对 JSF 架构有深入的了解才能正确完成。如果您需要自定义控件,最好创建一个扩展现有 UIComponent(如 HtmlInputText 所做的)并具有等效渲染器的具体控件。
If contamination isn't an issue, there is an open-source JSF implementation in the form of Apache MyFaces.
如果污染不是问题,则可以使用 Apache MyFaces 形式的开源 JSF 实现。
回答by Peter Hilton
Action listeners, such as for a CommandButton, are called during the Invoke Applicationphase, which is the last phase before the final Render Responsephase. This is shown in The JSF Lifecycle - figure 1.
动作侦听器,例如CommandButton,在调用应用程序阶段调用,这是最终渲染响应阶段之前的最后一个阶段。这在JSF 生命周期中显示 - 图 1。
回答by McDowell
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.
它是我使用过的唯一一个框架,其中组件创建是一个像这样的深度复杂过程。其他 Web 框架(无论是否在 .net 世界中)都没有使这如此痛苦,这对我来说是完全无法解释的。
Some of the design decisions behind JSF start to make a little more sense when you consider the goals. JSF was designed to be tooled - it exposes lots of metadata for IDEs. JSF is not a web framework - it is a MVPframework that can be used as a web framework. JSF is highly extensible and configurable - you can replace 90% of the implementation on a per-application basis.
当您考虑目标时,JSF 背后的一些设计决策开始变得更有意义。JSF 被设计为工具化——它为 IDE 公开了大量元数据。JSF 不是 Web 框架——它是一个MVP框架,可以用作 Web 框架。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.
该组件是几个输入文本(和其他)基本组件的组合,顺便说一句。
I'm assuming JSP-includes/tooling-based page fragments don't meet your requirements.
我假设基于 JSP 的包含/基于工具的页面片段不符合您的要求。
I would consider using your UIComponentELTag.createComponentto create a composite control with a UIPanel base and creating all its children from existing implementations. (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.
我会考虑使用你的UIComponentELTag.createComponent来创建一个带有 UIPanel 基的复合控件,并从现有的实现中创建它的所有子控件。(我假设您正在使用 JSP/taglibs 并进行其他一些猜测。)如果现有的 UIPanel 渲染器都没有完成这项工作,您可能需要一个自定义渲染器,但渲染器很容易。
回答by David Waters
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 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;
}
how did this get into the getValueBinding? In your tag class setProperties method
这是如何进入 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.");
}
}

