TP2 2015-2016 JSF2

De $1

Introduction

Dans cette séance :

Ressources :

En plus du support de cours JSF disponible sur la page du cours, je vous propose les ressources suivantes :

Etude du modèle de navigation PRG (Post Redirect Get)

NOTE : un projet contenant les corrections de cette section (navigation) + de la section suivante (templating) est donnée vers la fin de ce TP.

Objectifs de cette partie :

  1. Présenter les problèmes du POST utilisé par défaut par JSF, vus dans le TP1,
  2. Présenter le modèle PRG qui permet d'éviter la double soumission des formulaires et de pouvoir garder un marque-page des pages affichées.
  3. Introduction au templating avec Facelets

Important : dans ce TP vous utiliserez des backing bean de portée "Requête". Il faut toujours essayer de limiter au maximum la portée des beans pour éviter l'encombrement de la mémoire (ce qui peut être un problème pour les sites Web très fréquentés). Evidemment dans certains cas, les portées "Vue", "Conversation", ou même "Session" sont plus indiquées (par ex la portée "Session" pour un backing bean qui gère les connexions par login/password).

Création d'un projet de type Web Application, activation de CDI

  1. Cette fois-ci vous créerez un nouveau projet de type Web Application en choisissant "Java Web", puis "Web Application", pas besoin de faire un projet "JavaEE/entreprise" comme dans le TP1, nous n'utilisons pas d'EJBs aujourd'hui.
     
  2. N'oubliez pas de cocher le Framework "Java Server Faces" lors de la création du projet. Pas d'utilisation de PrimeFaces non plus pour ce TP.
     
  3. Ajoutez dans le projet un fichier beans.xml (click droit / new / Context and dependency injection / fichier beans.xml), sans ce fichier certaines injections de code ne fonctionnent pas.
     
  4. ATTENTION : Netbeans a "oublié" d'inclure la librairie permettant certaines injections de code, nécessaire aux projets utilisant le scope "SessionScoped", vous ajouterez donc à votre projet, manuellement, la librairie : cdi-api.jar
  • Allez dans le menu Tools / Outil de NetBeans, puis choisissez "Libraries"
     
  • Faites "Nouvelle librairie / New Library...", et donnez comme nom "CDI". Clic sur "Add Jar/Folder..." et indiquez le fichier cdi-api.jar qui se trouve dans glassfish/modules dans le répertoire d'installation de glassfish (sous Windows, il peut être, par exemple, dans C:\Program Files\glassfish-4.1\glassfish\modules). Voilà, dorénavant vous pourrez utiliser cette librairie avec vos projets.
     
  • Dans le nouveau projet, click droit sur "Libraries" (dans la fenêtre Projects à gauche) et choisissez "Add Library..." pour ajouter la nouvelle librairie "CDI".

Vous êtes prêts à travailler...

Exemple 1 : analyse d'un post tout simple

Nous allons étudier une application qui contient 2 pages JSF qui se référencent :

  • formulaire_1.xhtml qui contient un formulaire avec champ de saisie d'un entier ; la soumission du formulaire passe la main à affichage_1.xhtml,
  • affichage_1.xhtml qui affiche les 5 nombres qui suivent le nombre saisi et qui contient un lien pour revenir vers la page fomulaire_1.html

Utilisez simplement le menu "new/JSF Page" pour créer les pages. 

Voici le code des deux pages en question :

formulaire_1.xhtml 

<?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://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">

    <h:head>
        <title>Application&gt;formulaire_1</title>
    </h:head>
    <h:body>

     <h1>Application&gt;formulaire_1</h1>

     <h:form>
        <h:outputLabel value="Entrez un nombre" for="nombre"/>
        <h:inputText id="nombre" value="#{bean.nombre}"/>
        <h:commandButton value="Valider" action="affichage_1"/>
      </h:form>

    </h:body>
</html>

affichage_1.xhtml

Vous comprenez à quoi sert l'attribut varstatus de <ui:repeat>, utilisé dans l'expression EL #{! status.last ? ', ' : ''} ?

<?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://xmlns.jcp.org/jsf/html"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
    <h:head>
        <title>Application&gt;affichage_1</title>
    </h:head>

    <h:body>
        <h1>Application&gt;affichage_1</h1>
        Les nombres : <br/>
        <ui:repeat value="#{bean.nombresSuivants}" var="n" varStatus="status">
            #{n + 1}#{! status.last ? ', ' : ''}
        </ui:repeat>
        <h:form>
        <h:commandLink action="formulaire_1" value="Saisir un autre nombre"/>
        </h:form>
    </h:body>
</html>

Ces pages utilisent un Backing Bean (son nom est "bean") pour stocker la propriété correspondant au champs de formulaire "nombre". C'est la ligne suivante dans formulaire_1.html qui correspond à la propriété :

<h:inputText id="nombre" value="#{bean.nombre}"/>

Voici donc le code du backing bean (que nous avons, dans cet exemple, mis dans le package "jsf") :

Bean.java :

package jsf;

import java.util.ArrayList;
import java.util.List;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;

@Named(value = "bean")
@RequestScoped
public class Bean {

    private int nombre;

    public int getNombre() {
        return nombre;
    }

    public void setNombre(int nombre) {
        this.nombre = nombre;
    }

    public List<Integer> getNombresSuivants() {
        int nb = 5;
        List<Integer> t = new ArrayList<>(nb);
        for (int i = nombre; i < nombre + nb; i++) {
            t.add(i);
        }
        return t;
    }
}

Regardez déjà comment cet exemple s'articule. Notez dans les pages JSF l'utilisation de <ui:repeat ... /> qui correspond au tag JSTL vu l'an dernier <c:foreach... />. Notez que la collection sur laquelle on itère, donnée par :

#{bean.nombresSuivants}

...correspond encore à un accès à une propriété, la propriété "nombresSuivants" qui existe puisqu'une méthode getNombresSuivants() existe. Rappelons que ce sont les getters et setters qui définissent une propriété et non pas l'existence d'une variable d'instance dans la classe. En particulier ici on a pas de variable d'instance.

Exécutez cet exemple :

  • Testez en entrant autre chose qu'un nombre entier (un message doit s'afficher si vous avez bien écrit votre application) 
     
  • Essayez de faire afficher au début dans la zone de saisie le nombre entré précédemment quand vous saisissez un nouveau nombre.

ATTENTION, si le message d'erreur: /formulaire_1.xhtml @17,58 value="#{bean.nombre}": Target Unreachable, identifier 'bean' resolved to null apparaît, c'est surement que vous n'avez pas activé CDI ("Context and Dependency Injection"). Pour résoudre cette erreur, il suffit j'ajouter un fichier nommé beans.xml dans le répertoire WEB-INF qui contient seulement les quelques lignes suivantes :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

Remarquez-vous des anomalies quant à l'URL affiché par le navigateur ?

Rechargez la page qui affiche les 5 nombres. Que fait le navigateur ? Expliquez.

Est-ce possible de mettre un bookmark sur la page affichage pour un certain nombre. Par exemple 5 ; la page affichage affichera les nombres 6 à 10 qui sont censés représenter une information importante sur le nombre 5...

Et oui, cela ne marche pas ! Ce TP étudie un modèle, appelé PRG, pour ne plus avoir ce genre de problème.

Exemple 2 : utilisation de la redirection (modèle PRG)

Dans cet exemple nous allons faire une implémentation du modèle PRG vu en cours : la page résultat est affiché par une redirection (GET) après le POST.

On va commencer par régler le problème de l'URL. Pour cela, on va changer le comportement par défaut de JSF qui utilise le "forward" pour faire afficher les pages JSF (voir cours). Pour utiliser une redirection il suffit d'ajouter aux URLs dans les pages JSF "?faces-redirect=true", regardez le passage du cours à ce sujet.

  • Créez deux nouvelles pages JSF, appelez-les formulaire_2.xhtml et affichage_2.xhtml.
  • Recopiez le contenu des pages formulaire.xhtml et affichage.xhtml dans les nouvelles pages, en modifiant les 1 en 2 là où c'est pertinent, ainsi vous pourrez comparer.
  • Modifiez ces pages pour que JSF utilise une redirection à la place d'un forward : lorsqu'on va de formulaire_2.xhtml à affichage_2.xhtml et vice-versa.

Pour tester, lancez l'application et, à la main, tapez le bon URL pour faire afficher la page JSF formulaire_2.xhtml:

  • Editez la page index.html et faites un petit menu avec des liens vers les différentes pages formulaire_1.xhtml, formulaire_2.xhtml etc....

Est-ce que les URL sont corrects maintenant ?

Rechargez la page qui affiche les nombres. Avez-vous toujours le problème de l'exercice précédent ?

Est-ce que les bons nombres sont bien affichés ? Expliquez. 

Nous allons maintenant voir une méthode un élégante pour arriver à nos fins tout en résolvant le problème du bookmark/marque page. 

Exemple 3 : utilisation des paramètres de vue

Dans cet exercice nous allons utiliser une toute autre façon pour résoudre le problème du passage de la valeur tout en permettant l'affichage synchronisé de l'URL dans le navigateur.

Nous allons aussi régler le dernier problème : il sera possible de conserver les informations dans un marque-page du navigateur.

Reprenez le code de l'exercice sur la redirection. Mettez le suffixe 3 aux pages utilisées par cet exercice : formulaire_3.xhtml et affichage_3.xhtml

Comment passer la valeur de la propriété nombre d'une instance du bean à une autre (n'oubliez pas que la portée du bean est la requête et ce sont donc 2 instances différentes de la classe Bean qui sont utilisées par les 2 pages JSF) ? Nous allons utiliser un paramètre de vue (comme dans le TP 1) :

  • Dans la page affichage_3.xhtml, ajoutez un "paramètre de vue" nommé "nb" (lisez le listing ci-dessous). La valeur du paramètre "nb" de la requête GET sera ainsi conservé dans la propriété "nombre" du bean. Ceci se fait à l'aide des tags <f:metadata> et <f:viewParam ... />.
     
  • Dans la page formulaire_3.xhtml ajoutez un paramètre includeViewParams=true dans l'action du formulaire pour indiquer que vous voulez que les paramètres de vue de la page de destination soient des paramètres de la requête GET ajoutés à l'URL. 

Ainsi la page qui affiche les nombres sera bookmarkables/ajoutable dans le marque page.

Remarque : includeViewParams simplifie les choses lorsque les paramètres sont nombreux ; pour ce cas, avec un seul paramètre, vous auriez aussi pu ajouter plus simplement le passage du paramètre nb en appelant une méthode action du bean (une méthode est obligatoire car il est interdit de mélanger dans l'attribut action une destination avec la valeur d'un paramètre) qui retourne la valeur "affichage_3?faces-redirect=true&amp;nb=" + nombre 

formulaire_3.xhtml :

<?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://xmlns.jcp.org/jsf/html">

    <h:head>
        <title>Application&gt;formulaire_3</title>
    </h:head>
    <h:body>

     <h1>Applicationformulaire_3</h1>

     <h:form>
        <h:outputLabel value="Entrez un nombre" for="nombre"/>
        <h:inputText id="nombre" value="#{bean.nombre}"/>
        <h:commandButton value="Valider" action="affichage_3?faces-redirect=true&amp;includeViewParams=true"/>
      </h:form>
    </h:body>
</html>

Dans affichage_3.xhtml qui affiche les 5 nombres on ajoutera un paramètre de vue pour récupérer le nombre saisi par l'utilisateur :

affichage_3.xhtml :

<?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://xmlns.jcp.org/jsf/html"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:f="http://xmlns.jcp.org/jsf/core">

    <f:metadata>
        <f:viewParam name="nb" value="#{bean.nombre}"/>
    </f:metadata>

    <h:head>
        <title>Applicationaffichage_3</title>
    </h:head>
    <h:body>

     <h1>Application&gt;affichage_3</h1>

        Les nombres : <br/>
        <ui:repeat value="#{bean.nombresSuivants}" var="n" varStatus="status">
            #{n + 1}#{! status.last ? ', ' : ''}
        </ui:repeat>
        <h:form>
        <h:commandLink action="formulaire_3?faces-redirect=true" value="Saisir un autre nombre"/>
        </h:form>
    </h:body>     
</html>

Testez votre application. Etudiez en particulier les URL affichés par le navigateur.

Est-ce possible de garder un marque-page pour garder, par exemple, les 5 nombres qui suivent le nombre 34 ?

Exemple 4 : idem mais...

Modification très simple de l'exercice 3: Reprenez le code de l'exercice 3, mettez le suffixe 4 aux pages utilisées par cet exercice : formulaire_4.xhtml et affichage_4.xhtml
Montrez que vous avez compris: ajoutez simplement le fait que le nombre précédemment saisi apparaisse par défaut dans le formulaire lorsqu'on veut saisir un autre nombre !
 

Templating: mise en place de templates de présentation

Ressources http://www.coreservlets.com/JSF-Tutorial/jsf2/#Templating ce site contient tout un ensemble de cours sur JSF. Mais le PDF sur le templating, rien que la page 8, montre le principe général des includes.

Prenez le temps de remarquer dans les pages jsf tout le code qui se répète... dans les titres et les h1, et dans la structure des pages... De plus, j'imagine que la plupart d'entre vous doit encore modifier les urls à la main pour essayer une page formulaire_X au démarrage de l'application.

Nous allons maintenant mettre en place des templates de présentation, pour alléger tout ce code et rendre la navigation pratique.

Les templates sont des "pages types" dans lesquelles ont peut définir des zones que l'on pourra remplacer dans les pages qui se réfèrent à ces pages types. En outre, dans un modèle on peut définir des paramètres (en gros, des variables qui pourront être remplacées par des valeurs, spécifiées dans les pages qui utilisent ces modèles). Et enfin, un modèle peut lui même réutiliser un autre modèle, l'enrichir etc.

Voici ce que l'on désire obtenir :

snap.jpg

C'est une page avec une zone en haut, qui contient un titre (ici la description de la page affichée dans la partie centrale, dans une pseudo hiérarchie application/menu du tp2). La page qui utilise le modèle est ici index.xhtml comme l'indique l'URL. Dans cette page on a indiqué que l'on utilisé le modèle + on a indiqué que la variable qui décrivait le contenu valait Application/Menu du TP2.

Le même modèle va être repris par deux autres modèles : un pour les formulaires de saisie des nombres, l'autre par les pages qui affichent les nombres qui suivent le nombre entré par l'utilisateur.

Exemples de résultats, ici la page de saisie du nombre du premier exercice (cette page formulaire_1.xhtml utilise le modèle de formulaire, qui utilise le modèle par défaut) :

Snapt1.jpg

et la page d'affichage correspondante (qui utilise un modèle pour l'affichage, qui lui aussi utilise le modèle par défaut) :

Snapt3.jpg

etc... vous avez compris le principe, normalement on va pouvoir factoriser au maximum le code et le nombre de lignes dans les pages .xhtml devrait être réduit en conséquence (en plus d'avoir une présentation plus jolie).

Comment arriver à ce résultat ?

Travail à faire, choses à remarquer :

  1. Commencez par créer une page de type Facelets Template (clic droit sur le projet, puis New/Java Server Faces/Facelet Template), que vous nommerez template_default. Choisissez un layout avec header et barre latérale pour la navigation.
     
  2. Remarquez la création automatique dans le projet d'un répertoire "resources" qui contient deux feuilles de style css par défaut. Ce répertoire est important car lorsqu'un template ou une page JSF va référencer une feuille de style avec le tag <h:outputStylesheet library="css" name="default.css"/>la "librairie" css doit être située sous le répertoire "resources".

  3. On n'utilisera pas un classique <link href="./resources/css/default.css" rel="stylesheet" type="text/css" /> de HTML pour inclure une feuille de style car ici les liens vont être "calculés" en fonction de l'URL de la page qui va utiliser le template, et qui peut être située ailleurs.Voir lignes 8 et 9 du code de template_default.xhtml, ci-dessous.


  4. De même, dans le menu de gauche on a des liens vers d'autres pages JSF du projet (formulaire_1.xhtml etc.), on n'utilisera pas un classque <a href="formulaire_1.xhtml"/>... de HTML mais un <h:link outcome="formulaire_1.xhtml" value="formulaire_1"/> qui va lui aussi "calculer" le lien vers la page formulaire_1.xhtml en fonction de la position de la page qui inclut le template. Voir lignes 22 et suivantes du code de template_default.xhtml, ci-dessous.

Copiez-donc ce code pour le template par défaut :

template_default.xhtml

<?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:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html">

    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <h:outputStylesheet library="css" name="default.css"/>  
        <h:outputStylesheet library="css" name="cssLayout.css"/> 
        <title>Application&gt;<ui:insert name="complementTitreEtH1"/>#{numEx}</title>
    </h:head>

    <h:body>

        <div id="top" class="top">
             <h1>Application&gt;<ui:insert name="complementTitreEtH1"/>#{numEx}</h1>
        </div>

        <div>
            <div id="left">
                <ul>
                    <li><h:link outcome="index.xhtml" value="accueil"/></li>  
                    <li><h:link outcome="formulaire_1.xhtml" value="formulaire_1"/></li>  
                    <li><h:link outcome="formulaire_2.xhtml" value="formulaire_2"/></li>  
                    <li><h:link outcome="formulaire_3.xhtml" value="formulaire_3"/></li>  
                    <li><h:link outcome="formulaire_4.xhtml" value="formulaire_4"/></li>  
                </ul>
            </div>

            <div id="content" class="left_content">
                <ui:insert name="content">Content</ui:insert>
            </div>
        </div>
    </h:body>

</html>
 

Vous pouvez voir le rendu de ce template en cliquant droit dans le code / view.

Ce template définit trois espaces libres que ses clients pourront spécifier:

  • le champs <ui:insert name="complementTitreEtH1"/> avec aucun contenu par défaut;
     
  • le paramètre #{numEx}
     
  • le champs <ui:insert name="content">Content</ui:insert> avec pour contenu par défaut: Content

Maintenant, nous allons utiliser ce template par défaut :

  • directement pour la page index.xhtml
     
  • pour créer deux nouveaux templates: template_formulaire.xhtml et template_affichage.xhtml.

Pour la page index.xhtml, supprimez l'actuelle page index.xhtml créez une nouvelle page Facelet Template Client (clic droit, New/Java Server Faces/Facelet Template Client), nommée index, qui utilise le template qu'on vient juste de créer, et de type "generate root tag html". remplacez le slot nommé complementTitreEtH1 (il ne doit y en avoir qu'un du même nom !) par "Accueil" ; et remplacez le slot nommé content par une dissertation sur le bonheur que procure la simplicité de programmer avec les facelets.

Pour les autre templates créez deux nouveaux Facelet Templates Clients, nommés template_formulaire et template_affichage, qui utilise le tempate "template_default", et de type generate root tag ui:composition.  Le contenu de ces pages sont les suivants:

 

template_formulaire.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:ui="http://java.sun.com/jsf/facelets"
                xmlns:h="http://java.sun.com/jsf/html"
                template="./template_default.xhtml">

    <ui:define name="complementTitreEtH1">formulaire_</ui:define>

    <ui:define name="content">
        <h:form>
            <h:outputLabel value="Entrez un nombre" for="nombre"/>
            <h:inputText id="nombre" value="#{bean.nombre}"/>
            <h:commandButton value="Valider" action="#{bean.actionString('affichage', numEx, query)}"/>
          </h:form>
    </ui:define>

</ui:composition>

 

template_affichage.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:ui="http://java.sun.com/jsf/facelets"
                xmlns:h="http://java.sun.com/jsf/html"
                template="./template_default.xhtml">

    <ui:define name="complementTitreEtH1">affichage_</ui:define>

    <ui:define name="content">
        Les nombres : <br/>
        <ui:repeat value="#{bean.nombresSuivants}" var="n">
            #{n + 1},
        </ui:repeat>
        <h:form>
            <h:commandLink value="Saisir un autre nombre" action="#{bean.actionString('formulaire', numEx, query)}"/>
        </h:form>
    </ui:define>

</ui:composition>

 
 

Ces deux templates spécifient les champs complementTitreEtH1 et content, donc les pages formulaire_X.xhtml et affichage_X.xhtml n'auront à priori que le paramètre numEx à spécifier, et on fait ça de la manière suivante: 

<param name="numEx" value="2"/>

<ui:param name="numEx" value="X"/>

Mais attention, regardez bien: on est obligé de calculer la valeur de l'attribut action du commandLink et du commandButton ! On doit donc passer par le backing bean de l'application: Bean. Vous implémenterez donc la méthode actionString dans le backingbean, qui doit avoir pour signature:

public String actionString(String base, String numEx, String query);

où:

  • base est spécifié dans les templates template_formulaire.xhtml et template_affichage.xhtml et prendra les valeurs 'affichage' ou 'formulaire' ;
     
  • numEx est le numéro de l'exercice et est spécifié dans les pages formulaire_X.xhtml et affichage_X.xhtml ;
     
  • query est un nouveau paramètre qui correspond à tout ce qui est après le ? dans l'URL qu'on veut appeler (faces-redirect=true par exemple...). Il doit être spécifié de la même manière que numEx  dans les pages formulaire_X.xhtml et affichage_X.xhtml  

Travail à faire:

Maintenant si vous avez bien tout suivi jusque là, et que vous n'avez pas perdu trop de temps avec dissertation sur le bonheur que procure la simplicité de programmer avec les facelets, vous n'avez plus qu'à écrire la méthode actionString dans le backingBean, et vous pourrez réécrire les pages formulaire_X.xhtml comme clientes du template template_formulaire, et les pages affichage_X.xhtml comme clientes du template template_affichage. Vous pourrez constater à quel point elles sont devenues supersimples !!!

Pour les numeros d'exercices 3 et 4, n'oubliez pas d'ajouter les lignes 

<f:metadata>
        <f:viewParam name="nombre" value="#{bean.nombre}"/>
    </f:metadata>

à l'intérieur du tag ui:composition lorsque c'est nécessaire !

          à vous de jouer !!!

Correction des exercices précédents

  • Vous trouverez dans le projet suivant une correction des exercices de navigation, ainsi qu'un rappel des explications sur les divers comportements, et un templating : TP2JSFCorrige.zip 

A FAIRE : comprendre où dans le TP1 on fait des POST, où on fait des GET ?