1

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

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

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

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

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

4

2 回答 2

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>
...

支持豆:

@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>标签,它在幕后基本上是相同的。

每个向导步骤都有不同的视图

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

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

一种观点(第二种观点)

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

支持豆:

@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"
        }
        ...
    }

}
于 2013-03-09T07:14:53.553 回答
1

如果您的流程将基于ajax@ViewScoped ,则使用bean没有问题。只有当导航结果返回时,这种 bean才会被销毁,因此,只要您在内容之间切换的 ajax 调用返回 null 或空 String 值,您就没有问题。基本上,您应该使用基于组件渲染的流程,使用变量来控制它们:

<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,因为它是一个标签处理程序,并且在组件本身之前被评估。因此,如果您将其中一个放入上面的组件中,它们将被全部评估,不管它们是否要被渲染。看看我之前遇到的类似问题

于 2013-03-08T08:51:09.297 回答