JSF中的“绑定”属性如何工作?什么时候以及如何使用?


78

在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返回bean的name属性值User。该值将打印到HTML输出。

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

以下是经过手动美化和注释后生成的输出的相关部分(请注意,idj_id_jsp_1847466274_1是自动生成的,并且有两个隐藏的输入小部件)。我正在使用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存放在这里?

Answers:


132

它是如何工作的?

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

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

组件实例是请求范围的!

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

3.1.5组件绑定

...

组件绑定通常与通过受管Bean创建工具动态实例化的JavaBean结合使用(请参见第5.8.1节“ VariableResolver和默认VariableResolver”)。强烈建议应用程序开发人员将由组件绑定表达式指向的托管bean置于“请求”范围内。这是因为将其放置在会话或应用程序范围内将需要线程安全,因为UIComponent实例取决于在单个线程内部运行。将组件绑定置于“会话”范围中时,也可能对内存管理产生负面影响。

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

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

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

无论如何,binding在JSF 2.xa中,即使是在请求范围的bean上,使用这种方法将整个组件实例绑定到Bean属性也是相当罕见的用例,通常不是最佳实践。表示设计气味。你通常在观察侧声明组件,把他们的运行属性,如value,或许别人喜欢styleClassdisabledrendered,等,正常的bean属性。然后,您只需要精确地操作所需的bean属性,而不是获取整个组件并调用与该属性关联的setter方法。

在情况下,当进行“动态生成”一个组件需要基于静态模型,更好的方法是使用视图构建时间标签,如JSTL,如果有必要的标记文件,而不是createComponent()new SomeComponent()getChildren().add(),什么不是。另请参见如何将旧JSP的代码段重构为等效的JSF?

或者,如果要“动态呈现”组件的需求基础上的动态模型,然后只需使用一个迭代器组件<ui:repeat><h:dataTable>,等)。另请参阅如何动态添加JSF组件

复合组件是一个完全不同的故事。将a<cc:implementation>中的组件绑定到支持组件(即由标识的组件)是完全合法的<cc:interface componentType>。另请参见在两个h:inputText字段上使用f:convertDateTime如何使用以下代码实现动态列表来拆分java.util.Date JSF 2.0复合组件?

binding在本地范围内使用

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

也可以看看:


我将用户设置为请求范围的bean。并尝试在getlink和setlink方法中使用sysout。当登陆页面=User.User(), User.getLink(), User.setLink(), User.getValue()当我点击链接=User.User(), User.setLink()...
John

为什么要再次调用setLink()并又创建另一个UICommand对象?
约翰,

“如果绑定[...,则后备bean绝对不应在比请求范围更广的范围内”。在JSF 2.2中是否仍然如此?如果必须使用getChildren()。addAll(...)以编程方式在页面中包含组件,什么是最佳选择?
RinaldoPJr 2014年

@Rinaldo:使用JSTL以XML语法以编程方式构建视图。
BalusC 2014年

1
@Shirgill:的确如此。UIViewRootUIComponent基本上所有内容)都无法序列化。
BalusC

1

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

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

    http:..../somelink?componentId=123将允许jsf查看组件树以查看单击了链接123。否则可能htp:..../jsf;LinkId=123

回答此问题的最简单方法是创建一个只有一个链接的JSF页面,然后检查它产生的html输出。这样,您将确切知道使用所使用的JSF版本会如何发生。


我要说的是,我只在服务器端动态生成组件时使用了组件绑定,将所有属性设置为 actionvalue,然后让JSF框架来完成工作。
Luiggi Mendoza

我将其存储user为应用程序范围的托管Bean,每次单击链接时,只有value="-908991273579182886:-7278326187282654551"更改的第二个数字和其他所有事物都是相同的。不知道这些有什么魔术。
约翰,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.