JavaServer Faces, une technologie relativement récente dans le monde de J2EE, a été conçue pour simplififier encore plus le développement des applications Web. Il est facile de mettre en oeuvre des pages Web ainsi que les composants Web avec JSF en permettant une connexion adaptée entre ces composants d'interface et la logique métier donnée par les objets distribués. Il permet également d'automatiser le fonctionnement entre les JavaBeans et la page de navigation Web.
Jusqu'à présent nous avons découvert plusieurs composants Web que sont les servlets et les pages JSP. Ces composants associés à des JavaBeans (ou des EJB) permettent de mettre en oeuvre toutes les applications Web de façon rationnel, surtout si nous respectons l'architecture MVC (Modèle-Vue-Contrôleur). Rappelons que cette architecture nous offre de bien séparer la présentation, la gestion des requêtes ainsi que le traitement issu de la couche métier.
Alors pourquoi cette nouvelle technologie JSF ? Qu'apporte t-elle de plus ?
JSF utilise et rend plus pratique le modèle MVC dont je rappelle l'architecture :

Le contrôleur que nous avions mis en oeuvre devait récupérer l'ensemble des requêtes, et après analyse devait activer le modèle correspondant et pour finir proposer l'affichage en sollicitant la bonne page JSP. Le problème, c'est que le code de la servlet devient vite conséquent et très difficile à lire. Par ailleurs, à chaque fois que vous voulez définir une nouvelle page, il est nécessaire de recompiler la servlet contrôleur.
Avec la technologie JSF bien entendu, le contrôleur existe toujours, mais nous n'y avons plus accès (le contrôleur se nomme FacesServlet). Le contrôleur récupère toujours les requêtes et réagit en conséquence. Toutefois, la navigation et le traitement de la requête est décrit au travers d'un fichier de configuration <faces-config.xml> qu'il est très facile à écrire (et donc à lire). Il se complète au moyen de balises XML spécifiques. Grâce à cette solution, il n'est plus nécessaire de recompiler la servlet contrôleur, et par voie de conséquence, les modifications éventuelles sont faciles à mettre en oeuvre.
JSF est différent parce qu'il a besoin d'un autre composant Web qui lui sert de support. Il ne peut pas exister tout seul.JSF est donc une surcouche qui se place au dessus des autres composants Web en utilisant pleinement toutes leurs compétences. JSF est avant tout un ensemble de bibliothèques de balises personnalisées qui sont capables d'être mise en oeuvre par les pages JSP.

Finalement, la connaissance des autres composants Web comme les JSP et les servlets est requise pour bien maîtriser l'élaboration de JSF.
Nous avons précédemment vu que le couple Page JSP et JavaBeans permettait de séparer la logique métier de la présentation, mais malheureusement pas totalement. En effet, dans la page JSP, vous êtes au moins obligé de déclarer ces JavaBeans avec leurs différentes propriétés afin que la page JSP puisse les utiliser par la suite. Pourtant cette démarche ne correspond spécialement à un affichage, et c'est pourtant ce qu'est censée faire une page JSP. Voici d'ailleurs un exemple de code :
| nombre.jspf |
|---|
<jsp:useBean id="nombre" class="bean.Nombre" scope="session" /> <jsp:setProperty name="nombre" property="valeur" param="valeur" /> <jsp:setProperty name="nombre" property="maxi" value="${initParam.NombreMaxi}" /> <h3> <form action="Operation.jsp"> Nombre d'opérandes : <select name="valeur"> ${nombre.options} </select> <input type="submit" value="Valider ce choix" /> </form> </h3> |
Toute la première partie de ce fragment de page sert à déclarer le JavaBean bean.Nombre, la présentation visuelle de la page se fait par la suite.
En utilisant la technologie JSF, la déclaration des JavaBeans ne se fait plus sur la page JSP mais dans le fichier de configuration <faces-config.xml> que nous avons évoqué plus haut. Dans la page JSP qui utilise les compétences de JSF ne se trouve plus que des balises personnalisées correspondant uniquement à la présentation. Ainsi, le traitement de la logique métier est totalement séparée de la partie visuelle.
JavaServer Faces est un framework de composants GUI serveur conçu pour le développement d'applications Web en langage Java. Il est constitué d'un ensemble de balises spécialement conçues pour exprimer les interfaces JSF à l'intérieur d'une page JSP.
Les composants principaux de la technologie JSF sont les suivants :
Le modèle de programmation JSF permet, à moindre effort, d'effectuer les tâches suivantes :
L'interface graphique créée avec la technologie JSF s'exécute sur le serveur et présente le résultat de la génération sur le poste client.
.
En réalité, la page JSP inclut des balises spécifiques supportant la technologie JSF et délègue la gestion de la présentation à une structure interne qui gére les objets référencés par la page JSP sur le serveur Web.
Ces objets sont les suivants :
Après toute cette petite théorie, nous allons mettre en oeuvre notre première page JSF. Elle est volontairement modeste et de peu d'utilité. Elle nous permettra, par contre, de découvrir toute l'ossature nécessaire à l'élaboration d'une page JSF. Cette page va tout simplement afficher un message de bienvenue (Bien entendu, nous aurions pu nous passer de JSF pour cela).

Comme nous l'avons l'ossature de JSF respecte l'architecture Modèle-Vue-Contrôleur. Par contre, pour cet exemple, le Modèle n'existe pas. Pour toutes les applications Web qui utilise la technologie JSF, le contrôle est toujours assurée par la servlet FacesServlet. Cette servlet n'est pas directement accessible. Tous les réglages nécessaires à la bonne gestion de cette servlet se fait au travers du fichier de configuration <faces-config.xml>.
Par ailleurs, la technologie JSF ne peut exister seule puisque, comme nous l'avons vu, c'est une surcouche qui se place sur d'autres composants Web. Nous devons donc prendre une page JSP qui servira de support, ici <Bienvenue.jsp>.


Notre application Web comporte :
Notre descripteur de déploiement doit activer le contrôleur FacesServlet qui se trouve dans le paquetage javax.faces.webapp. Ce contrôleur doit systématiquement être activé quelque soit les requêtes venant du client. Il faut donc que l'URL de connexion à cette servlet utilise le jocker (*). Par contre, pour que ce contrôleur soit opérationnel par rapport à la technologie JSF, l'URL doit être systématiquement préfixé de /faces/.
| web.xml |
|---|
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file> faces/Bienvenue.jsp </welcome-file> </welcome-file-list> </web-app> |
Vu ces considérations, pour accéder à la page d'accueil, nous devons donc écrire au niveau de la balise <welcome-file> faces/Bienvenue.jsp.
.
Ce fichier permet de spécifier la navigation que vous désirez suivre entre les différentes pages de votre application Web. Par ailleurs, ce fichier permet de mettre en relation les pages JSP avec les composants JavaBeans correspondant à la logique métier. C'est à l'aide de ce fichier que les JavaBeans sont créés. Ce n'est plus la page JSP qui le fait. Ainsi, nous avons bien une séparation nette entre l'affichage de l'information d'une part, et le traitement de l'information d'autre part.
| faces-config.xml |
|---|
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN" "http://java.sun.com/dtd/web-facesconfig_1_1.dtd"> <faces-config> </faces-config> |
L'élément racine de ce fichier est <faces-config>. Nous remarquons que cet élément racine ne comporte aucun autre élément. Effectivement, une seule page est affichée, il n'y a donc pas de navigation possible. Par ailleurs, nous n'avons pas de logique métier, donc pas de JavaBean à mettre en oeuvre. Notre page propose juste un affichage basique sans calcul intermédiaire.
Comme je l'ai déjà fait remarquer plus haut, malgré l'utilisation de JSF, nous sommes obligé de prendre un composant Web qui sert de support. Comme il sagit d'une présentation visuelle, il va de soit qu'il faut prendre alors une page JSP.
| Bienvenue.jsp |
|---|
1 <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> 2 <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> 3 4 <f:view> 5 <html> 6 <body> 7 <h1><h:outputText value="Bienvenue à tout le monde" /></h1> 8 </body> 9 </html> 10 </f:view> 11 |
JSF utilise en fait un ensemble de balises personnalisées de hauts niveaux. Je rappelle que dans ce cas là, il est nécessaire d'importer les bibliothèques correspondantes afin de pouvoir les utiliser. C'est ce que réalisent les deux premières lignes.
Souvent, le préfixe de la biblothèque core de JSF est f plutôt que c. En effet, ce dernier préfixe est souvent utilisé par la JSTL standard.
.
Les deux biblothèques de balises sont spécialisées et permettent de gérer deux situations que nous trouvons fréquemment dans les pages Web dynamiques.
Dans les lignes suivantes (4-10), nous retrouvons du code HTML classique avec quelque balises personnalisées JSF.
Pour que la page Web puisse gérer convenablement les balises visuelles de JSF, il faut qu'elles soient entourées des balises <h:view>.
La ligne 7 utilise la balise <h:outputText> qui permet d'afficher des valeurs que nous désirons. Ici, nous proposons un texte fixe "en dur" au moyen du paramètre value. Il est possible, et c'est plutôt l'intérêt d'utiliser JSF, de placer du texte variable, issu d'un calcul réalisé par un JavaBean, au travers des expressions EL.
Comme nous venons de le voir, les deux biblothèques de balises JSF sont spécialisées et permettent de gérer deux situations que nous trouvons fréquemment dans les pages Web dynamiques.
Voici ci-dessous, deux tableaux qui nous donnent la plupart des balises JSF utilisées pour permettre la construction d'une page JSP avec une présentation et une gestion de haut niveau.
| Catégories | Balises | Desciption |
|---|---|---|
| Zone de saisie | h:inputHidden | Champ caché |
| h:inputSecret | Mot de passe | |
| h:inputText | Saisie de texte | |
| h:inputTextArea | Zone de texte sur plusieurs lignes | |
| Affichage en sortie | h:message | Message d'erreur associé à un champ |
| h:messages | Messages d'erreur pour l'ensemble de la page | |
| h:outputFormat | Sortie formatée | |
| h:outputLabel | ... | |
| h:outputLink | Zone de texte en sortie avec lien | |
| h:outputText | Zone de texte en sortie | |
| Sélection | h:selectBooleanCheckbox |
Une seule case à cocher |
| h:selectManyCheckbox | Cases à cocher en multisélection | |
| h:selectManyListbox | Zone de liste multisélection | |
| h:selectManyMenu | Menu déroulant en multisélection | |
| h:selectOneListbox | Zone de liste déroulante | |
| h:selectOneMenu | Menu déroulant | |
| h:selectOneRadio | Bouton radio | |
| Navigation | h:commandButton |
Bouton de soumission |
| h:commandLink | Lien vers une autre page | |
| Divers | h:dataTable |
Tableau de zone de texte |
| h:form | Formulaire | |
| h:graphicImage | Image | |
| h:panelGrid | Gestion de disposition | |
| h:panelGroup | Gestion de disposition avec mise en commun des boutons radio | |
| h:column | Colonne de table |
| Catégories | Balises | Desciption |
|---|---|---|
| Conversions | f:convertDateTime |
Conversion de la date |
| f:convertNumber | Conversion des nombres | |
| f:converter | Conversion personnalisée | |
| Evénements | f:actionListener |
Gestion des événements de type Validation |
| f:valueChangeListener | Gestion des événements de type Changement de valeurs | |
| Divers | f:attribute |
Positionner un attribut d'une balise parente |
| f:loadBundle | Gestion de l'internationalisation | |
| f:param | Prise en compte d'un paramètre | |
| f:verbatim | Zone de texte brute sans interprétention du compilateur | |
| Sélection | f:selectedItem |
Un élément de sélection parmi d'autres (dans une liste par exemple) |
| f:selectedItems | Ensemble d'éléments de sélection | |
| Validateurs | f:validateDoubleRange |
Validation des valeurs réelles par rapport à une limite choisie |
| f:validateLenght | Validation du nombre de caractères que la chaîne peut comporter | |
| f:validateLongRange | Validation des valeurs entières par rapport à une limite choisie | |
| f:validator | Validation personnalisée | |
| Vues | f:facet |
Gestion d'une zone délimité de la page Web |
| f:view | Gestion de la page Web en entier. | |
| f:subview | Gestion d'une partie de la page Web. |
Nous allons faire une autre application Web qui cette fois-ci fera un minimum de traitement. Cette application Web devra permettre d'exécuter un tout petit jeu qui tire automatiquement un nombre aléatoire à la connexion de la session et dont nous devons retrouver la valeur en proposant des saisies successives. Voici ci-dessous, l'apparence de notre unique page Web. En effet, c'est toujours cette même page qui doit être affichée après la saisie de chacune des valeurs par le client.

Remarquez bien que dans cette page Web, nous n'avons pas intégré de bouton de soumission.
.
Cette fois-ci, nous avons besoin d'un modèle qui s'occupera des différents traitements. En effet, nous avons besoin de fabriquer un nombre aléatoire de 1 à 10. Par ailleurs, il faut récupérer la saisie proposé par l'utilisateur et la contrôler suivant le tirage réalisé. Il faut également comptabiliser le nombre de coup effectués avant de trouver le bon chiffre. Pour finir, il faut prévoir un certain nombre de messages adaptés à la situation afin d'orienter l'utilisateur pour son prochain choix.
Afin de respecter le modèle Modèle-Vue-Contrôleur, le traitement est réalisé séparément, à l'aide du JavaBean alea.Nombre. La page d'accueil est cette fois-ci alea.jsp. Encore une fois, c'est la seule page du site. Il n'y aura donc pas de navigation à mettre en oeuvre. Cette page sera en relation directe avec le JavaBean alea.Nombre, ainsi les échanges pourront s'effectuer simplement dans les deux sens. Cette page qui est l'interface visuelle de l'application Web présentera une information adaptée à la situation suivant les événements proposés par l'opérateur.


| web.xml |
|---|
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file> faces/alea.jsp </welcome-file> </welcome-file-list> </web-app> |
Je rappelle que ce fichier permet de spécifier les navigations possibles qui peut exister entre les différentes pages Web présentes dans l'application. Ce fichier permet également de spécifier l'ensemble des JavaBeans à mettre en oeuvre afin qu'il soient correctements créés par le contrôleur, et ensuite utilisés directement par les pages JSP concernées.
Encore une fois, nous n'avons pas besoin de nous occuper de la navigation puisque l'application Web ne dispose que d'une seule page. Par contre, nous devons spécifier la mise en oeuvre du JavaBean alea.Nombre.
| faces-config.xml |
|---|
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN" "http://java.sun.com/dtd/web-facesconfig_1_1.dtd"> <faces-config> <managed-bean> <managed-bean-name>nombre</managed-bean-name> <managed-bean-class>alea.Nombre</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> </faces-config> |
Pour cela, à l'intérieur de l'élément racine <faces-config>, nous devons ajouter autant de balise <managed-bean> qu'il y a de JavaBean. Ensuite, dans chaque <managed-bean>, il suffit d'indiquer le nom de l'objet (le bean) qui sera créé au travers de l'élément <managed-bean-name>, la classe qu'il représente avec l'élément <managed-bean-class>, et enfin sa durée de vie (sa portée) grâce à l'élément <managed-bean-scope>. Nous retrouvons ici exactement la même démarche que lorsque nous déclarions des beans directement à l'intérieur des pages JSP. L'avantage ici, c'est que la page JSP utilisant la technologie JSF se trouvera grandement alégée.
Je rappelle que le scope d'un bean permet d'indiquer la durée de vie du bean, et qu'il peut prendre 4 valeurs :
En réalité, la session est détruite au bout d'une durée d'inactivité. Cette durée est fixée dans le fichier de configuration du serveur.
§
Attention, le scope page n'existe pas avec les JSF.
.
Je rappelle que pour avoir le statut de JavaBean, une classe Java doit respecter juste quelques critères. Sinon, mise à part cela, il s'agit d'une classe des plus conventionnelles. Un JavaBean doit :
En réalité, dans une propriété, l'attribut peut ne pas exister. Il suffit alors de respecter la signature de ces méthodes particulières pour réaliser les traitements qui vous conviennent.
| alea.Nombre |
|---|
package alea; public class Nombre { private long valeur; private long nombreARechercher; private int tentative; private boolean test; public Nombre() { nombreARechercher = Math.round(Math.random()*10)+1; } public void setValeur(long valeur) { this.valeur = valeur; tentative++; test = nombreARechercher == valeur; } public long getValeur() { return valeur; } public int getTentative() { return tentative; } public String getRésultat() { if (tentative==0) return "Tentez votre chance"; if (test) return "Bravo, vous avez trouvé !"; else return "Non, ce n'est pas le bon chiffre, refaites un essai."; } public String getProgression() { if (tentative==0 || test) return ""; return "Le nombre est plus "+(nombreARechercher>valeur ? "grand" : "petit"); } } |
Ce JavaBean alea.Nombre possède quatre propriétés qui seront directement accessibles par la page alea.jsp. Il s'agit des propriétés :
Remarquer au passage que les propriétés résultat et progression ne possèdent pas d'attributs correspondants.
.
Par ailleurs, le JavaBean possède des attributs supplémentaires qui ne sont pas accessibles de l'extérieur mais qui sont toutefois bien utiles pour la bonne marche du composant. Ces attributs sont :
Tous les calculs correspondant aux différents traitements sont donc réalisés à l'intérieur du JavaBean. Ainsi, nous séparons bien la logique du traitement Java de la partie visuelle qui sera mise en oeuvre par la page JSP.
Il ne nous reste plus qu'à s'occuper de notre page Web, la partie visuelle du site. La voici ci-dessous. Remarquez au passage qu'elle est très réduite. Par rapport à une page JSP classique, nous n'avons pas besoin de déclarer le bean nombre puisqu'il est déjà réalisé par le fichier de configuration <faces-config.xml>. Par ailleurs, l'accès aux différentes propriétés se fait systématiquement au travers des expressions EL que nous avons déjà rencontés dans les chapitres précédents. Avec ces deux considérations, nous pouvons constater que la page Web s'en trouve extrêmement allégée.
| alea.jsp |
|---|
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <f:view> <html> <body style="background-color: yellow"> <h2>Recherche d'un nombre aléatoire entre 1 et 10</h2> <hr /> <h:form> <h4> Introduisez votre nombre : <h:inputText value="#{nombre.valeur}" size="2" /> <h:outputText value="#{nombre.progression}" style="color: red" /> </h4> <h4>Tentatives : <h:outputText value="#{nombre.tentative}" style="color: red" /> fois</h4> </h:form> <hr /> <h3><h:outputText value="#{nombre.résultat}" style="color: blue"/></h3> </body> </html> </f:view> |
Attention, les EL JSF sont différents des EL JSP. En effet, ces dernières utilisent la notation ${expression} alors qu'ici, avec la technologie JSF, il faut plutôt prendre la notation #{expression}. Le comportement de ces deux syntaxes est très différent. Dans le cas de l'écriture ${...}, l'expression est évalué au moment de la compilation, alors qu'avec l'écriture #{...}, l'expression est évaluée au moment ou JSF effectue le rendu de la page (expression retardée).
Je rappelle que dans le cas d'une connexion avec un bean au travers d'une expression EL, vous spécifier d'abord le nom du bean et ensuite la propriété qui vous intéresse, et vous placez enfin un point de séparation entre ces deux éléments. Ainsi, pour accéder à la propriété valeur du bean nombre, vous écrivez #{nombre.valeur}.
Je rappelle qu'il est possible de faire du traitement directement à l'intérieur des expressions jSF. Voici d'ailleurs les opérateurs que vous pouvez utiliser :
| Catégorie | Opérateurs | Exemple |
|---|---|---|
| Arithmétique | +, -, *, / (ou div), % (ou mod) | #{nombre.valeur div 2} |
| Relationnel | == (ou eq), != (ou ne), < (ou lt), > (ou gt), <= (ou le), >= (ou ge) | #{nombre.valeur eq 3} |
| Logique | && (ou and), || (ou or), ! (ou not) | #{not nombre.existe} |
| Conditionnel | A ? B : C | #{nombre.existe ? nombre.valeur : 10} |
| Vide | empty A (A est soit une chaîne String, soit un tableau d'objets, soit une collection de type Map ou List). | #{empty nombre.tableau} |
Lorsque nous consultons cette page Web, nous retrouvons la même ossature que la première page que nous avions créée. Ici toutefois, nous avons rajouter des éléments JSF :
Remarquons ici qu'il n'existe pas de bouton de soumission pour valider notre requête. La validation se fait lorsque l'opérateur appuie sur la touche entrée après avoir saisie la valeur souhaitée. Le gestionnaire de navigation, intégré dans le contrôleur FacesServlet, cherche une règle de navigation applicable au contexte courant, décrite dans le fichier de configuration <faces-config.xml> :
- Si une correspondance est trouvée, alors la page suivante est affichée.
- Sinon la page courante est rechargée.
Nous n'avons pas défini de règle de navigation, c'est donc toujours la même page Web qui se réaffiche avec des informations adaptées à l'évolution de la session.
Lorsque vous avez besoin de plusieurs zones de saisie pour un même formulaire, cette fois-ci, il est nécessaire d'utiliser un bouton de soumission. En effet, les propriétés relatives à ces zones de texte récupèrent juste les valeurs. Le bouton de soumission fait lui appel à la bonne méthode du bean qui s'occupe uniquement du traitement de l'ensemble des valeurs récupérées.
Nous avons également réutilisé les balises <h:outputText> que nous connaissons déjà. Par contre cette fois-ci, au lieu de proposer un texte en dur dans l'attribut value, nous proposons des valeurs variables, toujours au moyen des expression EL et qui sollicitent les propriétés adaptée au message requis. Ainsi, nous affichons respectivement les propriétés progression, tentative et résultat au endroits idoines.
Remarquez au passage que ces balises JSF acceptent des attributs que nous connaisons déjà dans des balises HTML classiques. En effet, nous profitons de l'attribut style (mise en oeuvre des CSS) pour proposer un affichage avec une couleur personnalisée.
Nous avons encore beaucoup de chose à dire sur la gestion des beans au travers du fichier de configuration <faces-config.xml> comme :
Ces aspects seront traités ultérieurement.
Au travers d'un exemple simplissime, nous allons maintenant passer à la navigation entre les pages Web. Dans un premier temps, nous nous intéressons à la navigation statique, c'est-à-dire que le choix des pages est défini dans l'intitulé du bouton et demeure figé. Notre application Web réalise des opérations de base, comme l'addition et la soustraction, sur deux opérandes. Une fois que les opérandes sont définis, il suffit de choisir l'opération à traiter à l'aide du bouton concerné, et une nouvelle page Web apparaît alors, avec le traitement correspondant à l'action souhaitée.

Notre modèle doit prendre en compte la navigation entre plusieurs pages. Par ailleurs, le traitement et le stockage des informations est toujours réalisé par un bean que nous nommons ici calcul.Opération. La gestion de ce bean ainsi que la navigation entre les différentes pages Web sont décrites dans le fichier prévu à cet effet <faces-config.xml>.


Cette application Web comporte trois pages jsp avec calcul.jsp comme page d'accueil. Ensuite, le bean calcul.Opération est utilisé pour l'ensemble des trois pages.
| web.xml |
|---|
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file> faces/calcul.jsp </welcome-file> </welcome-file-list> </web-app> |
En réalité, vu le choix de l'organisation de notre application Web, nous nous servons de ce JavaBean uniquement pour stocker la valeur des opérandes. Le traitement est plutôt réalisé par la page Web appelée. (Ce n'est certainement pas le meilleur choix, mais c'est une solution pour valider la navigation statique).
| calcul.Opération |
|---|
package calcul; public class Opération { private int premier; private int deuxième; public int getPremier() { return premier; } public void setPremier(int premier) { this.premier = premier; } public int getDeuxième() { return deuxième; } public void setDeuxième(int deuxième) { this.deuxième = deuxième; } } |
Deux balises JSF déclenchent des actions lorsque l'utilisateur clique sur leur représentation graphique. Il s'agit de la balise <h:commandButton> qui représente un bouton de soumission, et la balise <h:commandLink> qui représente un lien HTML. Lorsque l'utilisateur clique sur l'un ou sur l'autre, une clef de navigation ou outcome est renvoyée. Cette clef peut être statique, en dur dans le code de la page JSP, ou dynamique, calculée par une EL. Vous précisez votre clef de navigation à l'aide de l'attribut action.
| calcul.jsp |
|---|
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <f:view> <html> <body style="color: yellow; background-color: green"> <h2>Calcul de base</h2> <hr /> <h:form> <h4>Opérande 1 : <h:inputText value="#{opération.premier}" /></h4> <h4>Opérande 2 : <h:inputText value="#{opération.deuxième}" /></h4> <hr /> <p> <h:commandButton action="plus" value="+" /> <h:commandButton action="moins" value="-" /> </p> </h:form> </body> </html> </f:view> |
Nous avons donc choisi deux boutons pour représenter les actions à réaliser. Les actions sont exprimées directement "en dur" sous forme de chaînes de caractères, respectivement "plus" et "moins". Il s'agit bien d'une navigation statique. L'intitulé du bouton est spécifié au travers de l'attribut value.
Lorsque l'utilisateur clique sur l'un des boutons, alors la clef de navigation (l'outcome) plus ou moins est renvoyée au gestionnaire de navigation JSF. Le gestionnaire de navigation, intégré dans le contrôleur FacesServlet, cherche une règle de navigation applicable au contexte courant, décrite dans le fichier de configuration <faces-config.xml> :
- Si une correspondance est trouvée, alors la page suivante est affichée.
- Sinon la page courante est rechargée.
Je rappelle que ce fichier permet de spécifier les navigations possibles qui peut exister entre les différentes pages Web présentes dans l'application. Ce fichier permet également de spécifier l'ensemble des JavaBeans à mettre en oeuvre afin qu'il soient correctements créés par le contrôleur, et ensuite utilisés directement par les pages JSP concernées.
| faces-config.xml |
|---|
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN" "http://java.sun.com/dtd/web-facesconfig_1_1.dtd"> <faces-config> <navigation-rule> <from-view-id>/calcul.jsp</from-view-id> <navigation-case> <from-outcome>plus</from-outcome> <to-view-id>/plus.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>moins</from-outcome> <to-view-id>/moins.jsp</to-view-id> </navigation-case> </navigation-rule> <managed-bean> <managed-bean-name>opération</managed-bean-name> <managed-bean-class>calcul.Opération</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> </faces-config> |
Cette fois-ci, nous avons besoin de décrire les deux types d'éléments : la navigation entre les différentes pages et le JavaBean.
Dans cet exemple, nous pouvons éventuellement nous passer de la balise <from-view-id> puisqu'il n'existe qu'une seule source. Il n'y a pas d'ambiguïté possible. Tentez l'expérience, et vous remarquerez que cela fonctionne correctement.
Ces pages servent uniquement à la visualisation du résultat. Nous utilisons donc essentiellement des balises <h:outputText>. Je rappelle toutefois que nous pouvons effectuer des traitements avec les expressions EL. C'est ce que nous avons réalisé ici avec une des opérations, + ou -.
| plus.jsp |
|---|
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <f:view> <html> <body style="color: yellow; background-color: green"> <h2>Le résultat est : </h2> <hr /> <h4> <h:outputText value="#{opération.premier}" /> + <h:outputText value="#{opération.deuxième}" /> = <h:outputText value="#{opération.premier + opération.deuxième}" /> </h4> </body> </html> </f:view> |
| moins.jsp |
|---|
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <f:view> <html> <body style="color: yellow; background-color: green"> <h2>Le résultat est : </h2> <hr /> <h4> <h:outputText value="#{opération.premier}" /> - <h:outputText value="#{opération.deuxième}" /> = <h:outputText value="#{opération.premier - opération.deuxième}" /> </h4> </body> </html> </f:view> |
Nous allons reprendre l'application Web qui permet de tirer automatiquement un nombre aléatoire à la connexion de la session, et dont nous devons retrouver la valeur en proposant des saisies successives. Nous allons l'étoffer un petit peu. Cette fois-ci, vous devez retrouver le nombre en trois coups au maximum. Si vous ne trouvez pas la valeur au bout de ces trois coups, une nouvelle page apparaît donnant la valeur que vous deviez trouver ainsi que l'historique des valeurs saisies.

Vous remarquez que notre page d'accueil alea.jsp dispose cette fois-ci de deux boutons. Ainsi, dans la même session, il sera possible maintenant de tout réinitialiser au niveau du bean nombre, et ainsi de tout recommencer. Cela va nous permettre de gérer une navigation dynamique.

Sur la page fin.jsp, nous voyons apparaître deux nouveautés : d'une part la mise en place d'un lien, ainsi que le tracé d'un tableau dynamique dont le nombre de lignes peut varier suivant le conteneur. Ici toutefois, le nombre de ligne est fixe puisque le nombre de coups est systématiquement de trois. Nous ferons en sorte ultérieurement que ce nombre de coups soit variable.
Le clic sur le lien Recommencer de cette page Web permet de naviger vers la page d'accueil. Attention toutefois, c'est plus qu'une navigation simple, puisque les attributs du bean nombre, représentant le traitement des calculs à réaliser, doivent être également réinitilisés.
Notre modèle doit prendre en compte la navigation entre les deux pages. Par ailleurs, le traitement des informations est toujours réalisé par le bean alea.Nombre qui comportera toutefois des attributs et des méthodes supplémentaires, vu que notre site s'est enrichi.


| web.xml |
|---|
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file> faces/alea.jsp </welcome-file> </welcome-file-list> </web-app> |
Notre descipteur de déploiement <web.xml> est totalement identique à celui que nous avions déjà défini. Effectivement, nous faisons appel à la même page d'accueil. Par ailleurs le contrôleur est toujours le même lorsque nous développons un système JSF. Je rappelle que c'est à l'aide du fichier de configuration <faces-config.xml> que nous décrivons la navigation entre les deux pages Web alea.jsp et fin.jsp.
Nous devons rajouter un certain nombre d'éléments dans notre bean alea.Nombre afin de répondre à ces nouvelles attentes. Nous devons notamment mettre en place le système d'historique, c'est-à-dire les valeurs que l'opérateur à choisi durant ses phases de test. Par ailleurs, nous devons implémenter une navigation dynamique. Effectivement, lorsque l'opérateur clique sur le bouton "Valider votre choix", la page suivante peut aussi bien être de nouveau la page d'accueil comme la page de fin. Cette page de fin est sollicité lorsque nous sommes sur le troisième coup et que nous n'avons toujours pas trouvé la bonne valeur. Par ailleurs, il faut penser à réinitialiser les valeurs des attributs lorsque l'opérateur demande à tout recommencer. Encore une fois, cela impose de mettre en place une navigation dynamique puisque nous devons faire appel à un traitement particulier sur le bean avant de réactiver la page d'accueil.
| alea.Nombre |
|---|
package alea; import java.util.*; public class Nombre { private int valeur; private int nombreARechercher; private int tentative; private boolean test; private ArrayList<Integer> historique; public Nombre() { init(); } private void init() { nombreARechercher = (int)(Math.random()*10)+1; tentative = 0; valeur = 0; historique = new ArrayList<Integer>(); } public void setValeur(int valeur) { this.valeur = valeur; tentative++; test = nombreARechercher == valeur; historique.add(valeur); } public int getValeur() { return valeur; } public int getTentative() { return tentative; } public String getRésultat() { if (tentative==0) return "Tentez votre chance"; if (test) return "Bravo, vous avez trouvé !"; else return "Non, ce n'est pas le bon chiffre, refaites un essai."; } public String getProgression() { if (tentative==0 || test) return ""; return "Le nombre est plus "+(nombreARechercher>valeur ? "grand" : "petit"); } public String fini() { return !test && tentative>=3 ? "finir" : "continuer"; } public String recommencer() { init(); return "recommencer"; } public ArrayList<Integer> getHistorique() { return historique; } public int getNombreARechercher() { return nombreARechercher; } } |
Par rapport à la page d'accueil initiale, nous devons juste mettre en oeuvre les deux boutons "Valider votre choix" et "Tout recommencer" qui vont servir à la navigation.
| alea.jsp |
|---|
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <f:view> <html> <body style="background-color: yellow"> <h2>Recherche d'un nombre aléatoire compris entre 1 et 10</h2> <hr /> <h:form> <h4> Introduisez votre nombre : <h:inputText value="#{nombre.valeur}" size="2" /> <h:outputText value="#{nombre.progression}" style="color: red" /> </h4> <h4>Tentatives : <h:outputText value="#{nombre.tentative}" style="color: red" /> fois</h4> <p> <h:commandButton action=" |