有很多材料可以区分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运行以返回name
bean的User
属性值。该值将打印到HTML输出。
但我无法理解binding
的工作原理。生成的HTML如何与link
bean的User
属性保持绑定?
下面是手动美化和评论后生成的输出的相关部分(请注意,id j_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
在哪里存储?
答案 0 :(得分:120)
当构建/恢复JSF视图(Facelets / JSP文件)时,将生成JSF组件树。此时,view build time,所有binding
属性都会被评估(along with id
attribtues and taghandlers like JSTL)。当需要在添加到组件树之前创建JSF组件时,JSF将检查binding
属性是否返回预先创建的组件(即非null
),如果是,则使用它。如果它没有预先创建,那么JSF将自动创建组件&#34;通常的方式&#34;并使用自动处理的组件实例作为参数调用binding
属性后面的setter。
在效果中,它将组件树中的组件实例的引用绑定到范围变量。在生成的组件本身的HTML表示中,此信息无法显示。无论如何,此信息与生成的HTML输出无关。提交表单并恢复视图后,JSF组件树将从头开始重建,所有binding
属性将仅重新评估,如上段所述。重新创建组件树后,JSF会将JSF视图状态还原到组件树中。
了解和理解的重要一点是具体的组件实例是有效的请求范围。它们是在每个请求上新创建的,它们的属性在恢复视图阶段填充了JSF视图状态的值。因此,如果将组件绑定到辅助bean的属性,那么支持bean应绝对不在比请求范围更广的范围内。另见JSF 2.0 specitication第3.1.5章:
3.1.5组件绑定
...
组件绑定通常与通过Managed动态实例化的JavaBeans结合使用 Bean Creation工具(参见第5.8.1节“VariableResolver和默认VariableResolver”)。 强烈 建议应用程序开发人员放置由组件绑定表达式指向的托管bean “request”scope。这是因为将它放在会话或应用程序范围内需要线程安全,因为 UIComponent实例依赖于在单个线程内部运行。对...也有潜在的负面影响 将组件绑定放在“会话”范围内时的内存管理。
否则,组件实例在多个请求之间共享,可能导致&#34; duplicate component ID&#34;错误和&#34;怪异&#34;行为,因为视图中声明的验证器,转换器和侦听器将从先前的请求重新附加到现有组件实例。症状很明显:它们被执行多次,每次请求的次数都与组件绑定的范围相同。
并且,在负载很重的情况下(即,当多个不同的HTTP请求(线程)同时访问和操作同一个组件实例时),您可能迟早会遇到应用程序崩溃的情况。 Stuck thread at UIComponent.popComponentFromEL,或Java Threads at 100% CPU utilization using richfaces UIDataAdaptorBase and its internal HashMap,甚至某些&#34;奇怪的&#34;当JSF忙于保存或恢复视图状态(即堆栈跟踪指示IndexOutOfBoundsException
或ConcurrentModificationException
方法等)时,saveState()
或restoreState()
直接来自JSF实现源代码。
binding
是不好的做法无论如何,以这种方式使用binding
,将整个组件实例绑定到bean属性,甚至是在请求范围的bean上,在JSF 2.x中是一个相当罕见的用例,通常不是最佳实践。它表明了一种设计气味。您通常在视图方面声明组件,并将其运行时属性(如value
)以及styleClass
,disabled
,rendered
等其他属性绑定到普通bean属性。然后,您只需操作所需的bean属性,而不是抓取整个组件并调用与该属性关联的setter方法。
如果某个组件需要动态构建&#34;基于静态模型,最好是在view build time tags like JSTL中使用tag file,而不是createComponent()
,new SomeComponent()
,getChildren().add()
,而不是<ui:repeat>
。另请参阅How to refactor snippet of old JSP to some JSF equivalent?
或者,如果组件需要动态呈现&#34;基于动态模型,只需使用iterator component(<h:dataTable>
,<cc:implementation>
等)。另请参阅How to dynamically add JSF components。
复合材料组件是一个完全不同的故事。将<cc:interface componentType>
内的组件绑定到支持组件(即由binding
标识的组件是完全合法的。另请参阅ao Split java.util.Date over two h:inputText fields representing hour and minute with f:convertDateTime和How to implement a dynamic list with a JSF 2.0 Composite Component?
binding
但是,有时您希望了解特定组件内部不同组件的状态,而不仅仅是与操作/值相关验证相关的用例。为此,可以使用binding
属性,但不与bean属性结合使用。您可以在binding="#{foo}"
属性中指定本地EL范围唯一变量名称,如UIComponent
,并且组件在同一视图中的其他位置的呈现响应期间直接与#{foo}
引用可用{{1}}。以下是几个相关问题,其中答案中使用了这样的解决方案:
Use an EL expression to pass a component ID to a composite component in JSF
(仅限上个月......)
答案 1 :(得分:1)
每个JSF组件都将自己呈现为HTML,并完全控制它生成的HTML。 JSF可以使用许多技巧,并且具体使用哪些技巧取决于您使用的JSF实现。
对于像hlink这样的东西,你可以在url中包含绑定信息作为查询参数或作为url本身的一部分或作为matrx参数。举些例子。
http:..../somelink?componentId=123
将允许jsf在组件树中查看是否单击了链接123。或者它可以是htp:..../jsf;LinkId=123
回答这个问题的最简单方法是创建一个只有一个链接的JSF页面,然后检查它产生的html输出。这样,您将使用您正在使用的JSF版本确切地知道这是如何发生的。