“绑定”属性在JSF中如何工作? 何时以及如何使用?

JSF中有很多区别value属性和binding属性的资料。

我感兴趣的是两种方法如何彼此不同。 鉴于:

 public class User { private String name; private UICommand link; // Getters and setters omitted. } 
 <h:form> <h:commandLink binding="#{user.link}" value="#{user.name}" /> </h:form> 

当指定value属性时,会发生什么情况。 getter运行返回User bean的name属性值。 该值被打印到HTML输出。

但我不明白binding是如何工作的。 生成的HTML如何与User bean的link属性保持绑定?

以下是手动美化和评论后生成输出的相关部分(请注意,id为j_id_jsp_1847466274_1是自动生成的,并且有两个隐藏的input小部件)。 我正在使用Sun的JSF RI版本1.2。

 <form action="/TestJSF/main.jsf" enctype="application/x-www-form-urlencoded" id="j_id_jsp_1847466274_1" method="post" name="j_id_jsp_1847466274_1"> <input name="j_id_jsp_1847466274_1" type="hidden" value="j_id_jsp_1847466274_1"> <a href="#" onclick="...">Name</a> <input autocomplete="off" id="javax.faces.ViewState" name="javax.faces.ViewState" type="hidden" value="-908991273579182886:-7278326187282654551"> </form> 

这里存储的binding在哪里?

它是如何工作的?

当构build/恢复JSF视图(Facelets / JSP文件)时,会生成一个JSF组件树。 在那一刻, 视图的 编译 时间 ,所有的binding属性都被评估( 以及id属性和标记处理程序,如JSTL )。 当JSF组件需要在被添加到组件树之前被创build时,JSF将检查binding属性是否返回预先创build的组件(即非null ),如果是,则使用它。 如果没有预先创build,那么JSF将自动创build组件“常规方法”,并使用自动创build的组件实例作为参数调用binding属性后面的setter。

在效果中,它将组件树中的组件实例的引用绑定到作用域variables。 这些信息在组件本身生成的HTML表示中是不可见的。 这些信息与生成的HTML输出无关。 当表单被提交并且视图被恢复时,JSF组件树只是从头开始重build,所有的binding属性将会像上面的段落中所描述的那样被重新评估。 在重新创build组件树之后,JSF将把JSF视图状态恢复到组件树中。

组件实例是请求范围!

重要的是要知道和理解的是,具体的组件实例有效地请求作用域。 它们是在每个请求中新创build的,并且在还原视图阶段,它们的属性将充满来自JSF视图状态的值。 所以,如果你将组件绑定到一个支持bean的属性上,那么支持bean应该绝对不会超出请求范围的范围。 另请参阅JSF 2.0 specitication一章3.1.5:

3.1.5组件绑定

组件绑定通常与通过Managed Bean Creation工具dynamic实例化的JavaBean结合使用(请参见第5.8.1节“VariableResolver和Default VariableResolver”)。 强烈build议应用程序开发人员将组件绑定expression式指向的“托pipebean”放在“请求”范围内。 这是因为将它放在会话或应用程序范围内将需要线程安全性,因为UIComponent实例依赖于在单个线程内运行。 将组件绑定放置在“会话”范围内时,也会对内存pipe理产生潜在的负面影响。

否则,在多个请求之间共享组件实例,可能导致“ 重复组件ID ”错误和“怪异”行为,因为在视图中声明的validation器,转换器和监听器被重新附加到来自先前请求的现有组件实例。 症状很明显:它们被执行多次,每次请求的次数都在与组件绑定的范围内相同。

而且,在负载很重的情况下(例如,当多个不同的HTTP请求(线程)同时访问和操作同一个组件实例时),您可能迟早会遇到应用程序崩溃,例如在UIComponent.popComponentFromEL或Java Threads在 JSF忙于保存或恢复视图状态时, 使用richfaces UIDataAdaptorBase及其内部HashMap ,甚至是一些“奇怪的” IndexOutOfBoundsExceptionConcurrentModificationException直接从JSF实现源代码获得100%的CPU利用率 (即堆栈跟踪指示saveState()restoreState()方法等)。

对bean属性使用binding是不好的做法

无论如何,使用binding这种方式,将整个组件实例绑定到一个bean属性,即使在一个请求范围的bean上,也是JSF 2.xa中比较less见的用例,通常不是最佳实践。 它表明一种devise的气味。 您通常在视图方面声明组件,并将它们的运行时属性(如value绑定,也可能将其他类似于styleClassdisabledrendered等的bean绑定到正常的bean属性。 然后,你只需要操纵你想要的bean属性,而不是抓取整个组件,并调用与属性关联的setter方法。

在组件需要基于静态模型“dynamic构build”的情况下,更好的方法是使用视图构build时间标记(如JSTL) ,如果需要的话在标记文件中 ,而不是createComponent()new SomeComponent()getChildren().add()和什么不是。 另请参见如何重构旧JSP的片段到一些JSF的等价物?

或者,如果组件需要基于dynamic模型“dynamic呈现”,那么只需使用一个迭代器组件 ( <ui:repeat><h:dataTable>等)。 另请参见如何dynamic添加JSF组件 。

复合组件是一个完全不同的故事。 将<cc:implementation>中的组件绑定到后续组件(即由<cc:interface componentType>标识的组件)是完全合法的。另请参见ao 将两个h:inputText字段拆分为代表小时和分钟的java.util.Date f:convertDateTime和如何使用JSF 2.0复合组件实现dynamic列表?

只能在本地范围内使用binding

然而,有时候您想知道特定组件内部的不同组件的状态,而且更多的情况是在与依赖于操作/值的validation相关的用例中。 为此,可以使用binding属性,但不能与bean属性结合使用。 您可以在binding属性中指定一个本地EL范围中的唯一variables名称,例如binding="#{foo}" ,并且组件在同一视图中的其他地方直接作为#{foo}提供的UIComponent引用。 这里有几个相关的问题,在答案中使用了这样的解决scheme:

  • 只有在某个命令button被按下的情况下,根据需要validationinput
  • 只有在另一个组件不被渲染的情况下如何渲染组件?
  • JSF 2 dataTable行索引没有dataModel
  • 依赖于PrimeOne selectOneMenu和required =“true”
  • 至less填写其中一个时,根据需要validation一组字段
  • 如何validation失败时更改input字段和标签的CSS类?
  • 使用Javascript获取JSF定义的组件
  • 使用ELexpression式将组件ID传递给JSF中的复合组件

    (这只是从上个月…)

也可以看看:

  • 如何在JSF中使用组件绑定的权利? (会话作用域bean中的请求作用域组件)
  • 查看范围:java.io.NotSerializableException:javax.faces.component.html.HtmlInputText
  • 绑定属性会导致在视图中find重复的组件ID

每个JSF组件都将自己呈现为HTML,并完全控制其生成的HTML。 JSF可以使用许多技巧,而使用哪些技巧取决于您正在使用的JSF实现。

  • 确保每个input都有一个唯一的名称,这样当表单被提交回组件树时,很容易知道每个组件可以读取其值的forms。
  • JSF组件可以生成提交给服务器的JavaScript,生成的JavaScript知道每个组件的绑定位置,因为它是由组件生成的。
  • 对于像hlink这样的东西,你可以在url中包含绑定信息作为查询参数,或者作为url本身的一部分或者作为matrx参数。 例如。

    http:..../somelink?componentId=123将允许jsf在组件树中查看链接123被单击。 或者它可以是htp:..../jsf;LinkId=123

回答这个问题最简单的方法是创build一个只有一个链接的JSF页面,然后检查它生成的html输出。 这样,您就可以确切知道使用您正在使用的JSF版本的情况。