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

发布于 2021-01-30 17:07:11

我有两个变量“ 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;

}
关注者
0
被浏览
68
1 个回答
  • 面试哥
    面试哥 2021-01-30
    为面试而生,有面试问题,就找面试哥。

    这里有一个主要的误解。那不是支持豆。这是一个支持组件。

    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);
    }
    

    在您的action(listener)方法中,只需进行相应的调用即可setRenderUserId(true)

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

    #{cc.renderUserId}
    


推荐阅读
知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看