关于jsf 2:“绑定”属性在JSF中如何工作? 什么时候以及如何使用?

How does the 'binding' attribute work in JSF? When and how should it be used?

在JSF中,有很多资料可以区分value属性和binding属性。

我对两种方法之间的差异感兴趣。 鉴于:

1
2
3
4
5
6
public class User {
    private String name;
    private UICommand link;

    // Getters and setters omitted.
}
1
2
3
<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是自动生成的,并且有两个隐藏的输入小部件)。
我正在使用Sun的JSF RI 1.2版。

1
2
3
4
5
6
7
<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">
    Name
    <input autocomplete="off" id="javax.faces.ViewState" name="javax.faces.ViewState"
        type="hidden" value="-908991273579182886:-7278326187282654551">
</form>

binding存放在哪里?


它是如何工作的?

构建/恢复JSF视图(Facelets / JSP文件)时,将生成JSF组件树。那时,在视图构建时,将评估所有binding属性(以及id属性和JSTL之类的标记处理程序)。当需要在将JSF组件添加到组件树之前创建JSF组件时,JSF将检查binding属性是否返回了预先创建的组件(即非null),如果是,则使用它。如果未预先创建,则JSF将以"通常的方式"自动创建组件,并使用自动创建的组件实例作为参数调用binding属性后面的setter。

好。

实际上,它会将组件树中组件实例的引用绑定到作用域变量。在组件本身的生成的HTML表示中,该信息绝不是可见的。无论如何,此信息绝不与生成的HTML输出相关。提交表单并还原视图后,将仅从头开始构建JSF组件树,并且将像上段中所述那样重新评估所有binding属性。重新创建组件树之后,JSF会将JSF视图状态恢复到组件树中。

好。

组件实例是请求范围的!

重要的是要知道和理解的是,具体的组件实例是有效地请求范围的。它们是在每个请求上新创建的,并且其属性在还原视图阶段被JSF视图状态的值填充。因此,如果将组件绑定到支持Bean的属性,则支持Bean绝对不应在比请求范围更广的范围内。另请参见JSF 2.0规范第3.1.5章:

好。

3.1.5 Component Bindings

...

Ok.

Component bindings are often used in conjunction with JavaBeans that are dynamically instantiated via the Managed
Bean Creation facility (see Section 5.8.1"VariableResolver and the Default VariableResolver"). It is strongly
recommend that application developers place managed beans that are pointed at by component binding expressions in
"request" scope. This is because placing it in session or application scope would require thread-safety, since
UIComponent instances depends on running inside of a single thread. There are also potentially negative impacts on
memory management when placing a component binding in"session" scope.

Ok.

否则,组件实例将在多个请求之间共享,这可能会导致"重复的组件ID"错误和"怪异"的行为,因为视图中声明的验证器,转换器和侦听器已从先前的请求重新附加到现有组件实例。症状很明显:它们执行了多次,在与该组件绑定到相同范围内的每个请求,都执行了一次。

好。

并且,在繁重的负载下(即,当多个不同的HTTP请求(线程)同时访问和操作相同的组件实例时),您可能迟早会遇到应用程序崩溃的问题,例如使用Richfaces UIDataAdaptorBase及其内部HashMap将线程卡在UIComponent.popComponentFromEL上,或将Java线程卡在100%CPU利用率上,甚至在JSF忙于保存或恢复时甚至直接来自JSF实现源代码的某些"奇怪" IndexOutOfBoundsExceptionConcurrentModificationException视图状态(即堆栈跟踪指示saveState()restoreState()方法等)。

好。

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

无论如何,以这种方式使用binding,甚至在请求范围内的bean上,将整个组件实例绑定到bean属性,在JSF 2.x中都是很少见的用例,通常不是最佳实践。它指示设计气味。通常,您在视图侧声明组件,并将其运行时属性(如value)以及其他诸如styleClassdisabledrendered等的属性绑定到常规bean属性。然后,您只需要精确地操纵所需的bean属性,而不是获取整个组件并调用与该属性关联的setter方法。

好。

在需要基于静态模型"动态构建"组件的情况下,最好在标记文件中使用JSTL之类的视图构建时间标记(如有必要),而不是createComponent()new SomeComponent()getChildren().add()和没什么另请参见如何将旧JSP的代码段重构为等效的JSF?

好。

或者,如果需要基于动态模型"动态呈现"组件,则只需使用迭代器组件(等)。另请参阅如何动态添加JSF组件。

好。

复合组件是一个完全不同的故事。将中的组件绑定到支持组件(即由标识的组件)是完全合法的。另请参见在两个h:inputText字段上分别用f:convertDateTime和How拆分java.util.Date。用JSF 2.0复合组件实现动态列表?

好。

仅在本地范围内使用binding

但是,有时您想从特定组件内部了解不同组件的状态,而在与动作/值相关的验证相关的用例中,这种情况要多得多。为此,可以使用binding属性,但不能与bean属性结合使用。您只需在binding属性中在本地EL作用域中指定一个唯一变量名即可,例如binding="#{foo}",并且该组件在渲染响应期间的其他位置,与#{foo}可用的UIComponent引用直接在同一视图中。以下是在答案中使用了此类解决方案的几个相关问题:

好。

  • 仅在按下某些命令按钮后才根据需要验证输入
  • 仅当未渲染另一个组件时才如何渲染组件?
  • 不带dataModel的JSF 2 dataTable行索引
  • Primefaces依赖的selectOneMenu和required =" true"
  • 至少填充一个字段时,根据需要验证一组字段
  • 验证失败时,如何更改输入字段和标签的CSS类?
  • 使用Javascript获取JSF定义的组件
  • 使用EL表达式将组件ID传递给JSF中的复合组件

    好。

    (那只是从上个月开始的...)

    好。

  • 好。

    也可以看看:

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

    好。


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

    • 确保每个from输入都有一个唯一的总名称,以便在将表单提交回呈现给它的组件树时,很容易分辨每个组件可以从何处读取其值表单。
    • JSF组件可以生成提交回Serer的javascript,生成的javascript也知道每个组件的绑定位置,因为它是由组件生成的。
    • 对于诸如hlink之类的事物,您可以在URL中包括绑定信息,作为查询参数或作为URL本身的一部分或作为matrx参数。举些例子。

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

    回答此问题的最简单方法是创建一个只有一个链接的JSF页面,然后检查它产生的html输出。这样,您将使用所使用的JSF版本确切地了解这种情况。