每个请求都会重新创建复合组件中的支持bean

dav*_*dml 3 java composite-component jsf-2 managed-bean

我有两个变量"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>
Run Code Online (Sandbox Code Playgroud)

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;

}
Run Code Online (Sandbox Code Playgroud)

Bal*_*usC 8

这里有一个重大的误解.那不是支持bean.这是一个支持组件.

JSF UI组件实例不是视图范围,而是请求范围.它们在渲染响应结束时被破坏(在将状态保存到JSF视图状态之后)并在视图构建期间重新创建(并且它们的状态从JSF视图状态恢复).

您已将有状态属性指定为组件的实例变量.这个不对.您应该明确地将它们存储在JSF状态中.正确的方法是让getter和setter委托给UIComponent#getStateHelper().声明为<cc:attribute>已隐式的任何属性都会这样做.您绝对不需要将它们重新声明为支持组件的实例变量.

那些未声明的布尔值<cc:attribute>必须重新实现如下:

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

public void setRenderUserId(Boolean renderUserId) {
    getStateHelper().put("renderUserId", renderUserId);
}
Run Code Online (Sandbox Code Playgroud)

在您的action(侦听器)方法中,只需相应地调用setRenderUserId(true).

不要忘记相应地修复EL表达式:

#{cc.renderUserId} 
Run Code Online (Sandbox Code Playgroud)

也可以看看: