我有两个变量“userId”和“name”。例如,当我单击“SHOW USERID”按钮时,它工作正常并设置“renderUserId=true”,并使用“render”显示它,但是如果我单击另一个“SHOW”按钮,Bean 将被重建,我松了“renderUserId=true”,它变成“false”和“renderName=true”,所以它显示正常,但 USERID 被隐藏。
我的问题是,在呈现 xhtml 时如何避免丢失 bean 值?
这是我的代码的简单模拟。
注意:如果我在“h:commandButton”中使用“actionListener”而不是“f:setPropertyActionListener”,我得到相同的结果,bean 被重构
example.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:cc="http://java.sun.com/jsf/composite">
<cc:interface componentType="com.bean.ExampleBean">
<cc:attribute name="userId" type="java.lang.Integer"/>
<cc:attribute name="name" type="java.lang.String"/>
</cc:interface>
<cc:implementation>
<h:panelGrid id="example_panel" columns="1" width="100%">
<h:outputText value="USERID: #{cc.attrs.userId}" rendered="#{!cc.attrs.renderUserId}"/>
<a4j:commandButton value="SHOW USERID" render="example_panel"
rendered="#{!cc.attrs.renderUserId}">
<f:setPropertyActionListener value="#{true}"
target="#{cc.attrs.renderUserId}"/>
</a4j:commandButton>
<a4j:commandButton value="HIDE USERID" render="example_panel"
rendered="#{cc.attrs.renderUserId}">
<f:setPropertyActionListener value="#{false}"
target="#{cc.attrs.renderUserId}"/>
</a4j:commandButton>
<h:outputText value="NAME: #{cc.attrs.name}" rendered="#{!cc.attrs.renderName}"/>
<a4j:commandButton value="SHOW NAME" render="example_panel"
rendered="#{!cc.attrs.renderName}">
<f:setPropertyActionListener value="#{false}"
target="#{cc.attrs.renderName}"/>
</a4j:commandButton>
<a4j:commandButton value="HIDE NAME" render="example_panel"
rendered="#{cc.attrs.renderName}">
<f:setPropertyActionListener value="#{false}"
target="#{cc.attrs.renderName}"/>
</a4j:commandButton>
</h:panelGrid>
</cc:implementation>
</ui:composition>
ExampleBean.java
import javax.faces.component.FacesComponent;
import javax.faces.component.UINamingContainer;
@FacesComponent("com.bean.ExampleBean")
public class ExampleBean extends UINamingContainer {
private Integer userId;
private String name;
private boolean renderUserId;
private boolean renderName;
}
最佳答案
这里存在一个重大的误解。那不是支持bean。那是一个支持组件。
JSF UI 组件实例不是 View 范围的,而是请求范围的。它们在渲染响应结束时被销毁(在将它们的状态保存到 JSF View 状态之后)并在 View 构建时重新创建(并且它们的状态从 JSF View 状态恢复)。
您已将有状态属性分配为组件的实例变量。这个不对。您应该明确地将它们存储在 JSF 状态中。正确的方法是让 getter 和 setter 委托(delegate)给 UIComponent#getStateHelper()
.任何声明为 <cc:attribute>
的属性已经隐含地这样做了。您绝对不需要将它们重新声明为支持组件的实例变量。
那些没有声明为 <cc:attribute>
的 boolean 值必须像下面这样重新实现:
public Boolean getRenderUserId() {
return (Boolean) getStateHelper().eval("renderUserId", Boolean.FALSE);
}
public void setRenderUserId(Boolean renderUserId) {
getStateHelper().put("renderUserId", renderUserId);
}
在您的 action(listener) 方法中,只需调用 setRenderUserId(true)
相应地。
不要忘记相应地修复 EL 表达式:
#{cc.renderUserId}
另见:
关于java - 复合组件中的支持 bean 在每次请求时重新创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15923078/