web-dev-qa-db-fra.com

Comprendre la portée de Flash dans JSF2

D'après ce que je comprends, les objets placés à l'intérieur de la portée Flash dans un cycle de vie de demande de faces seront disponibles pour le cycle de vie de demande de faces suivant, puis effacés.

Supposons que j'ai deux pages:

page01.xhtml:

<h:form>
    <h:commandButton  action="#{page01Bean.action}" />
</h:form>

Page01Bean:

@ManagedBean
@RequestScoped
public class Page01Bean {

        public void action(){
            FacesContext.getCurrentInstance().getExternalContext().getFlash().put("fooKey", "fooValue");
        }

}

page02.xhtml:

<h:outputText value="#{flash.fooKey}"/> 

Ainsi, lorsque le bouton dans page01.xhtml est cliqué, une demande de faces cycle de vie (disons cycle de vie A) démarre et définit la valeur du flash sous la touche appelée fooKey

Ensuite, j'ouvre un autre onglet de navigateur et je parcours page02.xhtml. Un autre visages demande le cycle de vie (disons cycle de vie B) commence à rendre cette page. Je m'attendais à ce que le cycle de vie B puisse accéder à la portée flash de son cycle de vie précédent (c'est-à-dire le cycle de vie A) et afficher fooValuein page02.xhtml. Cependant, il n'affiche rien.

Veuillez me corriger ce que je comprends mal sur la portée du flash dans cet exmaple. Merci beaucoup

30
Ken Chan

En bref, les variables stockées dans la portée flash survivront à une redirection et elles seront supprimées par la suite. Ceci est vraiment utile lors de l'implémentation d'un modèle Post-Redirect-Get.

Si vous essayez de naviguer vers une autre page en redirigeant et d'accéder aux attributs lors du chargement, ils seront là. Une fois cette demande effectuée, les valeurs du flash seront ignorées. Par exemple:

Vous êtes dans page1.xhtml et vous avez un lien de commande qui redirige vers une nouvelle page avec une méthode comme celle-ci (Remarque: je vais utiliser la navigation implicite).

public String navigateToPageB() {
    FacesContext.getCurrentInstance().getExternalContext().getFlash().put("param1", "Hello World!");
    return "pageB?faces-redirect=true";
}

Lorsque pageB.xhtml est rendu, vous pouvez accéder à ces valeurs par des expressions EL telles que

<h:outputLabel value="#{flash['param1']}" />

qui affichera le "Bonjour tout le monde!" chaîne que nous avons enregistrée plus tôt dans navigToPageB.

Quant à votre question, en ouvrant un nouvel onglet dans votre explorateur, vous n'accédez pas au même contexte que celui auquel vous accédiez sur votre onglet précédent, de sorte que votre variable n'y sera pas disponible.

33
Fritz

La réponse précédente est correcte, mais pour être complet, je voudrais dire qu'il y a eu beaucoup de problèmes dans les implémentations de Mojarra avec tout cela, mais finalement ils ont réussi à le faire fonctionner correctement dans Mojarra 2.1.27 et versions 2.2.5.

Comme le dit @Gamb, l'objectif de la portée flash est de maintenir un paramètre vivant en le mappant en interne à travers la redirection. Nous pouvons également conserver le paramètre actif plus longtemps si nous en avons besoin. En dehors de la manière mentionnée, FacesContext#getCurrentInstance#getExternalContext#getFlash#put, il est également possible de définir le paramètre via l'expression EL, en utilisant <c:set /> . J'ai implémenté un test de base suivant SSCCE qui montre une plus large gamme d'options, en utilisant deux vues:

Bean1

@ManagedBean
@ViewScoped
public class Bean1 implements Serializable {

    /**
     * Just takes the given param, sets it into flash context and redirects to
     * page2
     * 
     * @param inputValue
     * @return
     */
    public String goPage2(String inputValue) {
        FacesContext.getCurrentInstance().getExternalContext().getFlash()
                .put("param", inputValue);
        return "page2?faces-redirect=true";
    }

}

page1.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://Java.Sun.com/jsf/html"
    xmlns:ui="http://Java.Sun.com/jsf/facelets"
    xmlns:c="http://Java.Sun.com/jsp/jstl/core">
<h:head />
<h:body>

    <!-- Sets the first flash param at the action method, which redirects to page 2 -->
    <h:form>
        <h:inputText value="#{inputValue}" />
        <h:commandButton action="#{bean1.goPage2(inputValue)}"
            value="Go Page 2" />
    </h:form>

    <!-- Sets the second flash param -->
    <c:set target="#{flash}" property="param2" value="Myparam2" />

    <!-- Tries to retrieve both of the params. 
    Note none of them is displayed at the first page hit.
    If page refreshed, the second param which has been already set 
    using c:set above, will be displayed -->
    <p>Param1: #{flash['param']}</p>
    <p>Param2: #{flash['param2']}</p>
</h:body>
</html>

Bean2

@ManagedBean
@ViewScoped
public class Bean2 implements Serializable {

    public String getParam() {
        /**
         * Takes the parameter from the flash context
         */
        return (String) FacesContext.getCurrentInstance().getExternalContext()
                .getFlash().get("param");
    }

}

page2.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://Java.Sun.com/jsf/html"
    xmlns:ui="http://Java.Sun.com/jsf/facelets"
    xmlns:f="http://Java.Sun.com/jsf/core">
<h:head />
<!-- This page just displays the received params -->
<h:body>
    <!-- Different ways to retrieve the params from the flash scope -->
    <p>Param1: #{bean2.param}</p>
    <p>Param1: #{flash.param}</p>
    <p>Param1: #{flash['param']}</p>
    <p>Param2: #{flash['param2']}</p>

    <!-- Keep the first param for next redirection -->
    #{flash.keep.param}

    <!-- Return to page1 and see how the first param is retained -->
    <h:button outcome="page1?faces-redirect=true" value="return to 1" />
</h:body>
</html>

Voir aussi:

24
Xtreme Biker