【问题标题】:JSF2 - use view scope managed bean to pass value between navigationJSF2 - 使用视图范围托管 bean 在导航之间传递值
【发布时间】:2011-06-02 11:54:51
【问题描述】:

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

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

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

您对这种考虑两种可能性的解决方案有何看法 - 我们保持相同的观点,或者我们导航到新的观点。但在这两种情况下,我都可以使用视图范围的托管 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>

具有乘除运算的Calculator2页面:

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

}

【问题讨论】:

    标签: java jsf jsf-2


    【解决方案1】:

    您的问题询问如何在不使用会话范围托管 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。它们大多是互操作的,但有一些注意事项。

    【讨论】:

    • 是的,你是对的,在这个例子中我没有导航到新页面。抱歉,我误用了“页面”一词。无论如何,我导航到垃圾视图范围 bean 的新“视图”(这就是为什么我让它使用 重新实例化的原因。另外看看ResultBeanView.init()。我可以添加新页面calculator2.xhtml,其中包含操作除法和乘法,这可能会使用先前操作产生的结果。我应该这样组成我的例子吗?关于对话范围 - 我会看看它,但是现在我们只有 Tomcat 和 Mojarra。
    • 我将示例更改为由共享 Result 对象的相同数据的两个页面组成。
    • 它似乎应该可以工作 ;) 但请注意,您会遭受 one-page-behind-syndrome 的困扰(浏览器的地址栏仍然显示“计算器”的 URL '而实际上它正在显示'Calculator2')。您创建了一些粗略的解决方法,这也可以在 JSF 中通过 The Flash 范围或在 Java EE 中通过已经提到的会话范围来完成。
    • 其实我试过 Flash 范围,但它只能使用一次。重复使用是不可能的,因为 Flash 范围“东西”仅在一轮生命周期中存活:-( 如果您有任何线索如何在我的示例中使用它,请向我展示。
    • 我看过文章ibm.com/developerworks/java/library/j-jsf2fu-0710/?ca=drs- 是的,这是我想要的,但是如何在没有应用服务器的情况下实现呢?
    猜你喜欢
    • 2012-03-30
    • 2012-12-29
    • 1970-01-01
    • 2012-07-22
    • 2013-07-09
    • 2012-02-07
    • 2016-09-02
    • 2014-08-29
    相关资源
    最近更新 更多