JSF2 - 使用视图范围托管bean在导航之间传递值

时间:2011-01-02 14:03:03

标签: java jsf jsf-2

我正在解决如何在不使用会话范围托管bean的情况下将值从一个页面传递到另一个页面的问题。对于大多数托管bean,我希望只有Request scope。

我创建了一个非常非常简单的计算器示例,它将来自第5阶段的请求bean(CalculatorRequestBean)上的操作产生的 Result 对象作为初始化值传递给下一阶段生命周期中初始化的请求bean的新实例。

事实上 - 在生产环境中,我们需要传递更复杂的数据对象,这不像下面定义的结果那样原始。

您对此解决方案的看法是什么,它考虑了两种可能性 - 我们保持相同的观点或导航到新的观点。但在这两种情况下,我都可以使用视图范围的托管bean来传递先前存储的值。

计算器页面:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html">
<h:head>
    <title>Calculator</title>
</h:head>
<h:body>
    <h:form>
        <h:panelGrid columns="2">
            <h:outputText value="Value to use:"/>
            <h:inputText value="#{calculatorBeanRequest.valueToAdd}"/>

            <h:outputText value="Navigate to new view:"/>
            <h:selectBooleanCheckbox value="#{calculatorBeanRequest.navigateToNewView}"/>

            <h:commandButton value="Add" action="#{calculatorBeanRequest.add}"/>
            <h:commandButton value="Subtract" action="#{calculatorBeanRequest.subtract}"/>

            <h:outputText value="Result:"/>
            <h:outputText value="#{calculatorBeanRequest.result.value}"/>

            <h:commandButton value="Calculator2" action="calculator2"/>

            <h:outputText value="DUMMY" rendered="#{resultBeanView.dummy}"/>
        </h:panelGrid>
    </h:form>
</h:body>

计算器2页面,操作乘法和除法:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>Calculator 2</title>
    </h:head>
    <h:body>
        <h:form>
            <h:panelGrid columns="2">
                <h:outputText value="Value to use:"/>
                <h:inputText value="#{calculatorBeanRequest2.valueToAdd}"/>

                <h:outputText value="Navigate to new view:"/>
                <h:selectBooleanCheckbox value="#{calculatorBeanRequest2.navigateToNewView}"/>

                <h:commandButton value="Multiply" action="#{calculatorBeanRequest2.multiply}"/>
                <h:commandButton value="Divide" action="#{calculatorBeanRequest2.divide}"/>

                <h:outputText value="Result:"/>
                <h:outputText value="#{calculatorBeanRequest2.result.value}"/>

                <h:commandButton value="Calculator" action="calculator"/>

                <h:outputText value="DUMMY" rendered="#{resultBeanView.dummy}"/>
            </h:panelGrid>
        </h:form>
    </h:body>
</html>

要通过生命周期传递的对象:

package cz.test.calculator;

import java.io.Serializable;

/**
 * Data object passed among pages.
 * Lets imagine it holds something much more complicated than primitive int
 */
 public class Result implements Serializable {

    private int value;

    public void setValue(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }   
}

请求在视图“calculator.xhtml”上使用的作用域托管bean,其中包含操作添加和减去

package cz.test.calculator;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;


@ManagedBean
@RequestScoped
public class CalculatorBeanRequest {

    @ManagedProperty(value="#{resultBeanView}")
    ResultBeanView resultBeanView;

    private Result result;

    private int valueToAdd;

    /**
     *  Should perform navigation to 
     */
    private boolean navigateToNewView;

    /** Creates a new instance of CalculatorBeanRequest */
    public CalculatorBeanRequest() {        
    }


    @PostConstruct
    public void init() {       
        // Remember already saved result from view scoped bean
        result = resultBeanView.getResult();
    }

    // Dependency injections
    public void setResultBeanView(ResultBeanView resultBeanView) {
        this.resultBeanView = resultBeanView;
    }

    public ResultBeanView getResultBeanView() {
        return resultBeanView;
    }

    // Getters, setter
    public void setValueToAdd(int valueToAdd) {
        this.valueToAdd = valueToAdd;
    }

    public int getValueToAdd() {
        return valueToAdd;
    }

    public boolean isNavigateToNewView() {
        return navigateToNewView;
    }

    public void setNavigateToNewView(boolean navigateToNewView) {
        this.navigateToNewView = navigateToNewView;
    }

    public Result getResult() {
        return result;
    }

    // Actions
    public String add() {        
        result.setValue(result.getValue() + valueToAdd);
        return isNavigateToNewView() ? "calculator" : null;
    }    

    public String subtract() {        
        result.setValue(result.getValue() - valueToAdd);
        return isNavigateToNewView() ? "calculator" : null;
    }
}

请求在视图“calculator2.xhtml”上使用的作用域托管bean,其中包含操作除法和乘法:

package cz.test.calculator;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;


@ManagedBean
@RequestScoped
public class CalculatorBeanRequest2 {

    @ManagedProperty(value="#{resultBeanView}")
    ResultBeanView resultBeanView;

    private Result result;

    private int valueToUse;

    /**
     *  Should perform navigation to
     */
    private boolean navigateToNewView;

    /** Creates a new instance of CalculatorBeanRequest2 */
    public CalculatorBeanRequest2() {
    }


    @PostConstruct
    public void init() {
        result = resultBeanView.getResult();
    }

    // Dependency injections
    public void setResultBeanView(ResultBeanView resultBeanView) {
        this.resultBeanView = resultBeanView;
    }

    public ResultBeanView getResultBeanView() {
        return resultBeanView;
    }

    // Getters, setter
    public void setValueToAdd(int valueToAdd) {
        this.valueToUse = valueToAdd;
    }

    public int getValueToAdd() {
        return valueToUse;
    }

    public boolean isNavigateToNewView() {
        return navigateToNewView;
    }

    public void setNavigateToNewView(boolean navigateToNewView) {
        this.navigateToNewView = navigateToNewView;
    }

    public Result getResult() {
        return result;
    }

    // Actions
    public String multiply() {
        result.setValue(result.getValue() * valueToUse);
        return isNavigateToNewView() ? "calculator2" : null;
    }

    public String divide() {
        result.setValue(result.getValue() / valueToUse);
        return isNavigateToNewView() ? "calculator2" : null;
    }    
}

最后查看作用域托管bean以将Result变量传递给新页面:

package cz.test.calculator;

import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;


@ManagedBean
@ViewScoped
public class ResultBeanView implements Serializable {    

    private Result result = new Result();

    /** Creates a new instance of ResultBeanView */
    public ResultBeanView() {        
    }

    @PostConstruct
    public void init() {
        // Try to find request bean ManagedBeanRequest and reset result value
        CalculatorBeanRequest calculatorBeanRequest =  (CalculatorBeanRequest)FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("calculatorBeanRequest");
        if(calculatorBeanRequest != null) {
            setResult(calculatorBeanRequest.getResult());
        }
        CalculatorBeanRequest2 calculatorBeanRequest2 =  (CalculatorBeanRequest2)FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("calculatorBeanRequest2");
        if(calculatorBeanRequest2 != null) {
            setResult(calculatorBeanRequest2.getResult());
        }
    }
    /** No need to have public modifier as not used on view
     *  but only in managed bean within the same package
     */
    void setResult(Result result) {
        this.result = result;
    }

    /** No need to have public modifier as not used on view
     *  but only in managed bean within the same package
     */
    Result getResult() {
      return result;
    }

    /**
     * To be called on page to instantiate ResultBeanView in Render view phase
     */
    public boolean isDummy() {
        return false;
    }

}

1 个答案:

答案 0 :(得分:6)

您的问题询问如何在不使用会话范围托管bean的情况下将值从一个页面传递到另一个页面,但在您的示例中,我实际上看不到不同的页面。

您始终保持同一页面(查看)。 JSF组件自动将其值保留在所谓的视图状态中,因此您无需在此处手动传递任何内容。

如果你真的想在完全不同的页面之间传递信息(例如从calculator.xthml到result_overview.xhtml),那么一种可能的解决方案是使用Java EE 6中的conversation scope。如果你只是使用例如,JSF 2.0库Tomcat,您不能使用此范围,但如果您添加了CDI实现或部署到完整的Java EE AS(如Glassfish V3或Jboss AS 6),那么您可以使用它。

会话范围确实在页面之间起作用,但是有一个小问题,你必须将托管bean从@ManagedBean更改为@Named,并且必须意识到你将使用CDI bean而不是JSF托管bean。它们主要是互操作,但有一些警告。