简体   繁体   English

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

[英]JSF2 - use view scope managed bean to pass value between navigation

I am solving how to pass values from one page to another without making use of session scope managed bean. 我正在解决如何在不使用会话范围托管bean的情况下将值从一个页面传递到另一个页面的问题。 For most managed beans I would like to have only Request scope. 对于大多数托管bean,我希望只有Request范围。

I created a very, very simple calculator example which passes Result object resulting from actions on request bean (CalculatorRequestBean) from 5th phase as initializing value for new instance of request bean initialized in next phase lifecycle. 我创建了一个非常非常简单的计算器示例,它将来自第5阶段的请求bean(CalculatorRequestBean)上的操作产生的Result对象作为初始化值传递给下一阶段生命周期中初始化的请求bean的新实例。

In fact - in production environment we need to pass much more complicated data object which is not as primitive as Result defined below. 事实上 - 在生产环境中,我们需要传递更复杂的数据对象,这不像下面定义的结果那样原始。

What is your opinion on this solution which considers both possibilities - we stay on the same view or we navigate to the new one. 您对此解决方案的看法是什么,它考虑了两种可能性 - 我们保持相同的观点或者我们导航到新的观点。 But in both cases I can get to previous value stored passed using view scoped managed bean. 但在这两种情况下,我都可以使用视图范围的托管bean获取传递的先前值。

Calculator page: 计算器页面:

<?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 page with operations multiply and divide: 带有运算乘法和除法的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>

Object to be passed through lifecycle: 要通过生命周期传递的对象:

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

Request scoped managed bean used on view "calculator.xhtml" with actions add and subtract 请求在视图“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;
    }
}

Request scoped managed bean used on view "calculator2.xhtml" with actions divide and multiply: 请求视图“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;
    }    
}

and finally view scoped managed bean to pass Result variable to new page: 最后查看作用域托管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;
    }

}

Your question asks about how to pass values from one page to another without making use of session scope managed bean , but in your example I don't actually see different pages. 您的问题询问如何在不使用会话范围托管bean的情况下将值从一个页面传递到另一个页面 ,但在您的示例中,我实际上看不到不同的页面。

You stay on the same page (view) all the time. 你一直都在同一页(查看)。 JSF components automatically retain their values in the so-called view state, so there is no need for you to pass anything along manually here. JSF组件自动将其值保留在所谓的视图状态中,因此您无需在此处手动传递任何内容。

If you really wanted to pass information between completely different pages (eg from a calculator.xthml to a result_overview.xhtml) then one possible solution would be using the conversation scope from Java EE 6. If you are only using the JSF 2.0 libs on eg Tomcat, you can't use this scope, but if you added a CDI implementation or deployed to a full Java EE AS like Glassfish V3 or Jboss AS 6 then you could use this. 如果你真的想在完全不同的页面之间传递信息(例如从calculator.xthml到result_overview.xhtml),那么一个可能的解决方案是使用Java EE 6中的conversation scope 。如果你只使用JSF 2.0库,例如Tomcat,您不能使用此范围,但如果您添加了CDI实现或部署到完整的Java EE AS(如Glassfish V3或Jboss AS 6),那么您可以使用它。

The conversation scope really works between pages, but there is a small catch in that you have to change your managed beans from @ManagedBean to @Named and have to realize you would be using CDI beans and not JSF managed beans. 对话范围确实在页面之间起作用,但是有一个小问题,你必须将托管bean从@ManagedBean更改为@Named,并且必须意识到你将使用CDI bean而不是JSF托管bean。 They mostly interoperate, but there are a number of caveats. 他们大多数都是互操作的,但有一些警告。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM