JSF查看scoped bean的寿命

时间:2013-03-08 06:30:51

标签: jsf-2 managed-bean view-scope

我必须在3页流中保留信息,该流程在所有三个页面中使用ajax功能。所以这就是我设计结构的方式

1)一个视图范围的bean(@ViewScoped)包含动作方法,Ajax方法以及三个页面所需的属性

2)        Wizard.xhtml 
          |_  Step1.xhtml
          |_  step2.xhtml
          |_  step3.xhtml 

Wizard xhtml包含这三个facelets,它们基于用户当前正在操作的页面进行条件渲染。所以基本上从第1步导航到第2步时,我会提到wizard.xhtml。所以我怀疑bean实例是如何生活在这里的。它是否存在于整个流程中(如果是,它会导致任何性能问题),还是会被破坏然后再次重新创建?

使用这种方法,我能够保留所有页面的值,但我想知道这是否真的是一种好的设计方法,以及它可能给表带来什么影响/缺点。在此先感谢:)

2 个答案:

答案 0 :(得分:2)

您基本上有2个构建向导类型流的选项。第一个选项是在一个视图中显示所有步骤,另一个选项是拥有视图数量,因为向导中有步骤。

一个视图中的所有向导步骤

正如Xtreme Biker正确地提到设计视图最自然的方法是将条件渲染组件中的每一步分开,例如<h:panelGroup>并在进入不同的向导步骤时更新bean的属性currentStep。

基本视图设置:

<h:panelGroup id="step1">
    <h:panelGroup rendered="#{bean.currentStep eq 1}">
        <ui:include src="step1.xhtml"/>
    </h:panelGroup>
</h:panelGroup>
...

包含的页面(step2.xhtml):

...
<h:commandButton value="Back" action="#{bean.back}">
    <f:ajax execute="step2" render="step1 step2"/>
</h:commandButton>
<h:commandButton value="Forward" action="#{bean.forward}">
    <f:ajax execute="step2" render="step1 step2"/>
</h:commandButton>
...

支持bean:

@ManagedBean
@ViewScoped
public class Bean implements Serializable {

    ...
    private int currentStep = 1;//getter+setter

    public String forward() {
        ...
        if(currentStep == 2) {
             doSomethingWithValues();
             currentStep++;
        }
        ...
    }

    public String back() {
        ...
        if(currentStep == 2) {
             clearNecessaryValues();
             currentStep--;
        }
        ...
    }

}

如果您想在视图中嵌入自定义内容,这种方法很有用。如果你对“标准”方法很好,你宁愿不重新发明轮子并使用Primefaces库的<p:wizard> tag,这在封面上基本相同。

每个向导步骤在不同的视图中

如果您要通过回调/前进按钮导航到不同的视图,并在每次通过使用flash对象将所需数据传输到下一个视图来完成作业时返回不同的导航案例结果。

因此,设置将是:wizard/step2.xhtml(每步一个视图)和一个视图范围的bean Bean

其中一个观点(第二个观点)

...
<h:commandButton value="Back" action="#{bean.back}">
</h:commandButton>
<h:commandButton value="Forward" action="#{bean.forward}">
</h:commandButton>
...

支持bean:

@ManagedBean
@ViewScoped
public class Bean implements Serializable {

    ...
    private int currentStep = 1;//getter+setter

    @ManagedProperty("#{flash}")
    private Flash flash;//getter+setter

    private Data step1Data;
    private Data step2Data;
    private Data step3Data;
    ...

    @PostConstruct
    public void init() {
        int step = Integer.parseInt(flash.get("newStep"));
        Data step1 = (Data)flash.get("step1");
        Data step2 = (Data)flash.get("step2");
        Data step3 = (Data)flash.get("step3");
        this.currentStep = step;
        this.step1Data = step1;
        this.step2Data = step2;
        this.step3Data = step3;
        ...
    }

    public String forward() {
        ...
        if(currentStep == 2) {
             doSomethingWithValues();
             currentStep++;
             flash.put("step", currentStep);
             flash.put("step1", step1Data);
             flash.put("step2", step2Data);
             return "wizard/step3?faces-redirect=true"
        }
        ...
    }

    public String back() {
        ...
        if(currentStep == 2) {
             clearNecessaryValues();
             currentStep--;
             flash.put("step", currentStep);
             flash.put("step1", step1Data);
             return "wizard/step1?faces-redirect=true"
        }
        ...
    }

}

答案 1 :(得分:1)

如果您的流程基于 ajax ,则使用@ViewScoped bean没有问题。那种bean is going to be destroyed only when a navigation result is returned,所以,只要你的ajax调用内容之间的切换返回null或空字符串值,你就没有问题。基本上,您应该使用基于组件渲染的流,使用变量来控制它们:

<h:outputPanel rendered="#{bean.screen eq 'first'}">
    //your first screen
</h:outputPanel>
<h:outputPanel rendered="#{bean.screen eq 'second'}">
    //your second screen
</h:outputPanel>
<h:outputPanel rendered="#{bean.screen eq 'third'}">
    //your third screen
</h:outputPanel>

请注意,您必须注意使用<ui:include>标记来包含您的xhtml,因为它是tag handler并且正在组件本身之前进行评估。因此,如果您将其中一个放入上面的组件中,它们将被评估所有这些组件,无论它们是否将被渲染都无关紧要。有一个look to a similar problem我以前经历过。