4

我有两个变量“userId”和“name”。例如,当我单击“SHOW USERID”按钮时,它可以正常工作并设置“renderUserId=true”,并使用“render”显示它,但是如果我单击另一个“SHOW”按钮,Bean 会重建并且我会松动“renderUserId=true”,它变成“false”和“renderName=true”,所以它显示正常,但 USERID 是隐藏的。

我的问题是,如何避免在渲染 xhtml 时丢失 bean 值?

这是我的代码的简单模拟。

注意:如果我在“h:commandButton”中使用“actionListener”而不是“f:setPropertyActionListener”,我会得到相同的结果,bean 是重构的

例子.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;

}
4

2 回答 2

12

There's a major misconception going here. That's not a backing bean. That's a backing component.

JSF UI component instances are not view scoped, instead they are request scoped. They are destroyed by end of render response (after having saved their state into JSF view state) and recreated during view build time (and their state is restored from JSF view state).

You've assigned the stateful properties as instance variables of the component. This is not right. You should be explicitly storing them in the JSF state. The correct approach for that is to let the getter and setter delegate to UIComponent#getStateHelper(). Any attributes which are declared as <cc:attribute> already implicitly do that. You do absolutely not need to redeclare them as instance variables of the backing component.

Those booleans which are not declared as <cc:attribute> must be reimplemented like follows:

public Boolean getRenderUserId() {
    return (Boolean) getStateHelper().eval("renderUserId", Boolean.FALSE);
}

public void setRenderUserId(Boolean renderUserId) {
    getStateHelper().put("renderUserId", renderUserId);
}

In your action(listener) method, just invoke setRenderUserId(true) accordingly.

Don't forget to fix the EL expressions accordingly:

#{cc.renderUserId} 

See also:

于 2013-04-10T13:07:08.887 回答
1

您的 FacesComponent 不保持状态,每次调用它时它都是一个新实例。对于您的用例,您似乎应该至少使用具有视图范围的 ManagedBean。这意味着只要您在带有按钮的页面上,就会保留该实例。

于 2013-04-10T11:09:17.440 回答