You are on page 1of 36

JavaServer Faces - JSF

Chapitres traits
Introduction

JavaServer Faces, une technologie relativement rcente dans le monde de J2EE, a t conue pour simplififier encore plus le dveloppement des applications Web. Il est facile de mettre en oeuvre des pages Web ainsi que les composants Web avec JSF en permettant une connexion adapte entre ces composants d'interface et la logique mtier donne par les objets distribus. Il permet galement d'automatiser le fonctionnement entre les JavaBeans et la page de navigation Web.

Introduction
Pourquoi JSF ?
Jusqu' prsent nous avons dcouvert plusieurs composants Web que sont les servlets et les pages JSP. Ces composants associs des JavaBeans (ou des EJB) permettent de mettre en oeuvre toutes les applications Web de faon rationnel, surtout si nous respectons l'architecture MVC (Modle-Vue-Contrleur). Rappelons que cette architecture nous offre de bien sparer la prsentation, la gestion des requtes ainsi que le traitement issu de la couche mtier. Alors pourquoi cette nouvelle technologie JSF ? Qu'apporte t-elle de plus ? JSF utilise et rend plus pratique le modle MVC dont je rappelle l'architecture :

Le contrleur que nous avions mis en oeuvre devait rcuprer l'ensemble des requtes, et aprs analyse devait activer le modle correspondant et pour finir proposer l'affichage en sollicitant la bonne page JSP. Le problme, c'est que le code de la servlet devient vite consquent et trs difficile lire. Par ailleurs, chaque fois que vous voulez dfinir une nouvelle page, il est ncessaire de recompiler la servlet contrleur. Avec la technologie JSF bien entendu, le contrleur existe toujours, mais nous n'y avons plus accs (le contrleur se nomme FacesServlet). Le contrleur rcupre toujours les requtes et ragit en consquence. Toutefois, la navigation et le traitement de la requte est dcrit au travers d'un fichier de configuration <facesconfig.xml> qu'il est trs facile crire (et donc lire). Il se complte au moyen de balises XML spcifiques. Grce cette solution, il n'est plus ncessaire de recompiler la servlet contrleur, et par voie de consquence, les modifications ventuelles sont faciles mettre en oeuvre. JSF est diffrent 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 comptences. JSF est avant tout un ensemble de bibliothques de balises personnalises 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 matriser l'laboration de JSF.

Nous avons prcdemment vu que le couple Page JSP et JavaBeans permettait de sparer la logique mtier de la prsentation, mais malheureusement pas totalement. En effet, dans la page JSP, vous tes au moins oblig de dclarer ces JavaBeans avec leurs diffrentes proprits afin que la page JSP puisse les utiliser par la suite. Pourtant cette dmarche ne correspond spcialement un affichage, et c'est pourtant ce qu'est cense 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&eacute;randes :

<select name="valeur"> ${nombre.options} </select> <input type="submit" value="Valider ce choix" /> </form> </h3>

Toute la premire partie de ce fragment de page sert dclarer le JavaBean bean.Nombre, la prsentation visuelle de la page se fait par la suite. En utilisant la technologie JSF, la dclaration 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 comptences de JSF ne se trouve plus que des balises personnalises correspondant uniquement la prsentation. Ainsi, le traitement de la logique mtier est totalement spare de la partie visuelle.

Voici quelques unes des fonctionnalits de JSF :


1. Une sparation nette entre la couche de prsentation et les autres couches. 2. Le mapping HTML/Objet. 3. Un modle riche de composants graphiques rutilisables. 4. Une gestion de l'tat de l'interface entre les diffrentes requtes. 5. Une liaison simple entre les actions ct client de l'utilisateur et le code Java correspondant ct serveur. 6. La cration de composants personnaliss. 7. Le support de diffrents clients (HTML, WML, XML, ...) grce la sparation des problmatiques de construction de l'interface et du rendu de cette interface.

Architecture et principe de fonctionnement


JavaServer Faces est un framework de composants GUI serveur conu pour le dveloppement d'applications Web en langage Java. Il est constitu d'un ensemble de balises spcialement conues pour exprimer les interfaces JSF l'intrieur d'une page JSP.
Les composants principaux de la technologie JSF sont les suivants :

1. Une API pour reprsenter les composants d'interface utilisateur et grer leur tat, intercepter les vnements, effectuer les validations de saisie ct serveur et des conversions de donnes, dfinir la navigation entre les pages, grer l'internationnalisation, etc. 2. Une bibliothque de balises JSP pour construire des composants graphiques au sein d'une page JSP.
Le modle de programmation JSF permet, moindre effort, d'effectuer les tches suivantes :

1. Lier les vnements client gnrs au code serveur. 2. Lier les composants d'interface utilisateur de la page aux donnes du serveur. 3. Construire une interface graphique partir de composants rutilisables. 4. Sauvegarder et restaurer l'tat de l'interface graphique tout au long de la dure de vie des requtes serveur.

L'interface graphique cre avec la technologie JSF s'excute sur le serveur et prsente le rsultat de la gnration sur le poste client. . En ralit, la page JSP inclut des balises spcifiques supportant la technologie JSF et dlgue la gestion de la prsentation une structure interne qui gre les objets rfrencs par la page JSP sur le serveur Web.
Ces objets sont les suivants :

1. Composants GUI, qui mappent les balises des pages JSP. 2. Gestionnaire d'vnements, validateurs et convertisseurs de format, qui sont enregistrs sur les composants. Les validateurs (validators), qui sont fournis en standard dans les implmentation JSF, sont des objets qui permettent de valider les champs de saisie, comme la longueur d'un libell ou le type de donne. Les convertisseurs (converters) permettent de transformer les donnes avant de les transmettre aux composants dans la page. Plusieurs converters sont fournis en standard. Vous pouvez les utiliser ou en crer de nouveaux, comme les validators. 3. Objets qui encapsulent les donnes et les traitements spcifiques des composants.

Notre premire page JSF - Message de bienvenue


Aprs toute cette petite thorie, nous allons mettre en oeuvre notre premire page JSF. Elle est volontairement modeste et de peu d'utilit. Elle nous permettra, par contre, de dcouvrir toute l'ossature ncessaire 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).

Modle MVC
Comme nous l'avons l'ossature de JSF respecte l'architecture Modle-Vue-Contrleur. Par contre, pour cet exemple, le Modle n'existe pas. Pour toutes les applications Web qui utilise la technologie JSF, le contrle est toujours assure par la servlet FacesServlet. Cette servlet n'est pas directement accessible. Tous les rglages ncessaires 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>.

Constitution de l'application Web


Notre application Web comporte : 1. La page d'accueil : Bienvenue.jsp 2. Les deux fichiers de configurations : web.xml (descripteur de dploiement) et faces-config.xml (Contrle de navigation entre les pages Web et mise en place de la communication entre ces pages Web et les JavaBeans qui assurent le traitement de la couche mtier). 3. Ensemble des bibliothques ncessaires au bon fonctionnement de la technologie JSF : deux sont indispensables jsfapi.jar et jsf-impl.jar. Il est souvent ncessaire de possder en plus les librairies standard de la JSTL qui se nomment jstl.jar et standard.jar. Enfin quelques librairies optionnelles peuvent s'avrer intressantes, elles commencent alors par commons-***.jar.

Descripteur de dploiement <web.xml>


Notre descripteur de dploiement doit activer le contrleur FacesServlet qui se trouve dans le paquetage javax.faces.webapp. Ce contrleur doit systmatiquement tre activ quelque soit les requtes venant du client. Il faut donc que l'URL de connexion cette servlet utilise le jocker (*). Par contre, pour que ce contrleur soit oprationnel par rapport la technologie JSF, l'URL doit tre systmatiquement prfix 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 considrations, pour accder la page d'accueil, nous devons donc crire au niveau de la balise <welcome-file> faces/Bienvenue.jsp. .

Fichier de configuration <faces-config.xml>


Ce fichier permet de spcifier la navigation que vous dsirez suivre entre les diffrentes pages de votre application Web. Par ailleurs, ce fichier permet de mettre en relation les pages JSP avec les composants JavaBeans correspondant la logique mtier. C'est l'aide de ce fichier que les JavaBeans sont crs. Ce n'est plus la page JSP qui le fait. Ainsi, nous avons bien une sparation 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'lment racine de ce fichier est <faces-config>. Nous remarquons que cet lment racine ne comporte aucun autre lment. Effectivement, une seule page est affiche, il n'y a donc pas de navigation possible. Par ailleurs, nous n'avons pas de logique mtier, donc pas de JavaBean mettre en oeuvre. Notre page propose juste un affichage basique sans calcul intermdiaire.

Page d'accueil de l'application Web <Bienvenue.jsp>


Comme je l'ai dj 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 prsentation visuelle, il va de soit qu'il faut prendre alors une page JSP.
Bienvenue.jsp

1 2 3 4 5 6 7 8 9 10 11

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <f:view> <html> <body> <h1><h:outputText value="Bienvenue tout le monde" /></h1> </body> </html> </f:view>

JSF utilise en fait un ensemble de balises personnalises de hauts niveaux. Je rappelle que dans ce cas l, il est ncessaire d'importer les bibliothques correspondantes afin de pouvoir les utiliser. C'est ce que ralisent les deux premires lignes.

Souvent, le prfixe de la biblothque core de JSF est f plutt que c. En effet, ce dernier prfixe est souvent utilis par la JSTL standard. .
Les deux biblothques de balises sont spcialises et permettent de grer deux situations que nous trouvons frquemment dans les pages Web dynamiques.

1. La bibliothque html qui s'interesse plus particulirement la gestion de l'affichage et qui intgre donc des balises personnalises qui reprsentent, en les bonnifiant, des balises classiques que nous connaissons dj avec le HTML. 2. La bibliothque core qui s'intresse plus particulirement des traitements prliminaires comme la gestion globale d'une page ou d'une partie de page, la validation des donnes saisies, la conversion des valeurs saisies, la gestion des vnements, etc.
Dans les lignes suivantes (4-10), nous retrouvons du code HTML classique avec quelque balises personnalises JSF. Pour que la page Web puisse grer convenablement les balises visuelles de JSF, il faut qu'elles soient entoures des balises <h:view>. La ligne 7 utilise la balise <h:outputText> qui permet d'afficher des valeurs que nous dsirons. Ici, nous proposons un texte fixe "en dur" au moyen du paramtre value. Il est possible, et c'est plutt l'intrt d'utiliser JSF, de placer du texte variable, issu d'un calcul ralis par un JavaBean, au travers des expressions EL.

Bibliothques de balises JSF


Comme nous venons de le voir, les deux biblothques de balises JSF sont spcialises et permettent de grer deux situations que nous trouvons frquemment dans les pages Web dynamiques. 1. La bibliothque html qui s'interesse plus particulirement la gestion de l'affichage et qui intgre donc des balises personnalises qui reprsentent, en les bonnifiant, des balises classiques que nous connaissons dj avec le HTML. 2. La bibliothque core qui s'intresse plus particulirement des traitements prliminaires comme la gestion globale d'une page ou d'une partie de page, la validation des donnes saisies, la conversion des valeurs saisies, la gestion des vnements, etc.
Voici ci-dessous, deux tableaux qui nous donnent la plupart des balises JSF utilises pour permettre la construction d'une page JSP avec une prsentation et une gestion de haut niveau.

Actions personnalises de la bibliothque html

Catgories

Balises

Desciption

h:inputHidden h:inputSecret Zone de saisie h:inputText h:inputTextArea h:message h:messages h:outputFormat Affichage en sortie h:outputLabel h:outputLink h:outputText h:selectBooleanCheckbox h:selectManyCheckbox h:selectManyListbox Slection h:selectManyMenu h:selectOneListbox h:selectOneMenu h:selectOneRadio

Champ cach Mot de passe Saisie de texte Zone de texte sur plusieurs lignes Message d'erreur associ un champ Messages d'erreur pour l'ensemble de la page Sortie formate ... Zone de texte en sortie avec lien Zone de texte en sortie Une seule case cocher Cases cocher en multislection Zone de liste multislection Menu droulant en multislection Zone de liste droulante Menu droulant Bouton radio

h:commandButton Navigation h:commandLink h:dataTable h:form h:graphicImage Divers h:panelGrid h:panelGroup h:column

Bouton de soumission Lien vers une autre page Tableau de zone de texte Formulaire Image Gestion de disposition Gestion de disposition avec mise en commun des boutons radio Colonne de table

Actions personnalises de la bibliothque core

Catgories

Balises

Desciption

f:convertDateTime Conversions f:convertNumber f:converter f:actionListener Evnements f:valueChangeListener f:attribute f:loadBundle Divers f:param f:verbatim f:selectedItem Slection f:selectedItems f:validateDoubleRange f:validateLenght Validateurs f:validateLongRange f:validator f:facet Vues f:view f:subview

Conversion de la date Conversion des nombres Conversion personnalise Gestion des vnements de type Validation Gestion des vnements de type Changement de valeurs Positionner un attribut d'une balise parente Gestion de l'internationalisation Prise en compte d'un paramtre Zone de texte brute sans interprtention du compilateur Un lment de slection parmi d'autres (dans une liste par exemple) Ensemble d'lments de slection Validation des valeurs relles par rapport une limite choisie Validation du nombre de caractres que la chane peut comporter Validation des valeurs entires par rapport une limite choisie Validation personnalise Gestion d'une zone dlimit de la page Web Gestion de la page Web en entier. Gestion d'une partie de la page Web.

Grer les JavaBeans


Nous allons faire une autre application Web qui cette fois-ci fera un minimum de traitement. Cette application Web devra permettre d'excuter un tout petit jeu qui tire automatiquement un nombre alatoire 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 mme page qui doit tre affiche aprs la saisie de chacune des valeurs par le client.

Remarquez bien que dans cette page Web, nous n'avons pas intgr de bouton de soumission. .

Modle MVC
Cette fois-ci, nous avons besoin d'un modle qui s'occupera des diffrents traitements. En effet, nous avons besoin de fabriquer un nombre alatoire de 1 10. Par ailleurs, il faut rcuprer la saisie propos par l'utilisateur et la contrler suivant le tirage ralis. Il faut galement comptabiliser le nombre de coup effectus avant de trouver le bon chiffre. Pour finir, il faut prvoir un certain nombre de messages adapts la situation afin d'orienter l'utilisateur pour son prochain choix.
Afin de respecter le modle Modle-Vue-Contrleur, le traitement est ralis sparment, 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 prsentera une information adapte la situation suivant les vnements proposs par l'oprateur.

Constitution de l'application Web et descripteur de dploiement


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</servletclass> <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>

Fichier de configuration <faces-config.xml>


Je rappelle que ce fichier permet de spcifier les navigations possibles qui peut exister entre les diffrentes pages Web prsentes dans l'application. Ce fichier permet galement de spcifier l'ensemble des JavaBeans mettre en oeuvre afin qu'il soient correctements crs par le contrleur, et ensuite utiliss directement par les pages JSP concernes.
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 spcifier 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'intrieur de l'lment racine <faces-config>, nous devons ajouter autant de balise <managed-bean> qu'il y a de JavaBean. <managed-bean>, il suffit d'indiquer le nom de l'objet (le bean) qui sera cr au travers de l'lment <managed-bean-name>, la classe l'lment <managed-bean-class>, et enfin sa dure de vie (sa porte) grce l'lment <managed-bean-scope>. Nous retrouvons ici dmarche que lorsque nous dclarions des beans directement l'intrieur des pages JSP. L'avantage ici, c'est que la page JSP utilisant trouvera grandement alge. Je rappelle que le scope d'un bean permet d'indiquer la dure de vie du bean, et qu'il peut prendre 4 valeurs :

Ensuite, dans chaque qu'il reprsente avec exactement la mme la technologie JSF se

1. session : Certainement, le scope le plus courant. L'objet existe tant que le client consulte l'application Web. L'objet est dtruit lorsqu'il quitte le navigateur. 2. request : Cette fois-ci, l'objet existe juste pour mettre en relation deux pages Web entre elles, et rcupre ainsi les paramtres de la requte.

3. application : Dure de vie la plus longue. L'objet existe tant que le serveur Web est en activit. Nous pouvons ainsi comptabiliser, par exemple, le nombre de personne qui se connecte sur le site. 4. none : Cette fois-ci, aucun objet n'est visible dans aucune des pages. Cette dsignation est toutefois utile lorsqu'un autre bean (visible) utilise celui-ci. Nous dcouvrirons ce type d'utilisation ultrieurement.

Attention, le scope page n'existe pas avec les JSF. .

JavaBean alea.Nombre
Je rappelle que pour avoir le statut de JavaBean, une classe Java doit respecter juste quelques critres. Sinon, mise part cela, il s'agit d'une classe des plus conventionnelles. Un JavaBean doit : 1. Possder au moins un constructeur par dfaut parmi les autres constructeurs ventuels. Ou bien la classe ne possde aucun constructeur, ce qui revient avoir un constructeur par dfaut qui ne fait rien par dfaut. 2. Possder des proprits. Les attributs doivent tre privs. L'accs ces attributs se fait au travers de mthodes dont la signature est spcifique. Ce principe de connexion s'appelle une proprit. Pour accder l'attribut qui vous intresse, vous devez passer par la mthode dont le nom commence par set suivi du mme nom que l'attribut, avec toutefois, la premire lettre en majuscule. Pour une lecture de l'attribut, nous appliquons la mme dmarche, mais cette fois-ci, la mthode commence par get, sauf si le type est boolen, auquel cas, la mthode commence alors par is. Nous pouvons avoir des proprits qui sont en lecture/criture ou bien en lecture seule ou criture seule.

En ralit, dans une proprit, l'attribut peut ne pas exister. Il suffit alors de respecter la signature de ces mthodes particulires pour raliser 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 getRsultat() { 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 possde quatre proprits qui seront directement accessibles par la page alea.jsp. Il s'agit des proprits :

1. valeur : (lecture/criture) qui correspond la valeur saisie par l'oprateur. 2. tentative : (lecture seule) qui enregistre le nombre de coup effectu par l'oprateur depuis le dbut de la session. 3. rsultat : (lecture seule) qui propose un message adapt la situation suivant si on dbute la session ou suivant le rsultat du tirage. 4. progression : (lecture seule) qui indique l'oprateur, aprs avoir fait au moins une tentative, vers quel type de choix de nombre il faut s'orienter.

Remarquer au passage que les proprits rsultat et progression ne possdent pas d'attributs correspondants. .
Par ailleurs, le JavaBean possde des attributs supplmentaires qui ne sont pas accessibles de l'extrieur mais qui sont toutefois bien utiles pour la bonne marche du composant. Ces attributs sont :

1. nombreARechercher : qui est le nombre que l'oprateur doit retrouver. Ce nombre est calcul par le constructeur par dfaut. Ce nombre existe donc ds la cration de l'objet. Pour cela, nous faisons appel la mthode random() de la classe Math. Cette mthode renvoie une valeur alatoire comprise entre la valeur relle 0.0 (non comprise) et 1.0 (comprise). 2. test : attribut boolen qui indique le rsultat entre la valeur saisie par l'oprateur et le nombre rechercher. Ce test est effectu par la proprit valeur, et le rsultat est valid si l'oprateur trouve le bon chiffre.

Tous les calculs correspondant aux diffrents traitements sont donc raliss l'intrieur du JavaBean. Ainsi, nous sparons bien la logique du traitement Java de la partie visuelle qui sera mise en oeuvre par la page JSP.

Page d'accueil alea.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 trs rduite. Par rapport une page JSP classique, nous n'avons pas besoin de dclarer le bean nombre puisqu'il est dj ralis par le fichier de configuration <faces-config.xml>. Par ailleurs, l'accs aux

diffrentes proprits se fait systmatiquement au travers des expressions EL que nous avons dj renconts dans les chapitres prcdents. Avec ces deux considrations, nous pouvons constater que la page Web s'en trouve extrmement allge.
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&eacute;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.rsultat}" style="color: blue"/></h3> </body> </html> </f:view>

Attention, les EL JSF sont diffrents des EL JSP. En effet, ces dernires utilisent la notation ${expression} alors qu'ici, avec la technologie JSF, il faut plutt prendre la notation #{expression}. Le comportement de ces deux syntaxes est trs diffrent. Dans le cas de l'criture ${...}, l'expression est valu au moment de la compilation, alors qu'avec l'criture #{...}, l'expression est value au moment ou JSF effectue le rendu de la page (expression retarde). Je rappelle que dans le cas d'une connexion avec un bean au travers d'une expression EL, vous spcifier d'abord le nom du bean et ensuite la proprit qui vous intresse, et vous placez enfin un point de sparation entre ces deux lments. Ainsi, pour accder la proprit valeur du bean nombre, vous crivez # {nombre.valeur}.

Oprateurs utilisables dans les expressions JSF


Je rappelle qu'il est possible de faire du traitement directement l'intrieur des expressions jSF. Voici d'ailleurs les oprateurs que vous pouvez utiliser :
Catgorie Oprateurs Exemple

Arithmtique Relationnel Logique Conditionnel Vide

+, -, *, / (ou div), % (ou mod) == (ou eq), != (ou ne ), < (ou lt), > (ou gt), <= (ou le ), >= (ou ge) && (ou and), || (ou or), ! (ou not)
A?B:C

#{nombre.valeur div 2} #{nombre.valeur eq 3} #{not nombre.existe} #{nombre.existe ? nombre.valeur : 10} #{empty nombre.tableau}

empty A (A est soit une chane String, soit un tableau d'objets, soit une collection de type Map ou List).

Lorsque nous consultons cette page Web, nous retrouvons la mme ossature que la premire page que nous avions cre. Ici toutefois, nous avons rajouter des lments JSF :

1. <h:inputText> : Cet lment est une zone d'entre de texte classique. Cette zone d'entre doit tre en relation avec une proprit en mode lecture/criture d'un bean. Bien qu'il s'agisse d'une saisie venant de l'oprateur, nous pouvons nous poser la question pourquoi le mode lecture ? Cela permet de proposer automatiquement des valeurs par dfaut et surtout de restituer la valeur conserve lorsque la page est raffiche. Ici, nous utilisons la proprit valeur du bean nombre qui au dpart est gale 0, ceci au travers de l'attribut value. Remarquez au passage la conversion automatique d'une chane de caractres vers un entier. L'attribut size permet de spcifier la largeur du champ de saisie. En rsum, lorsque le formulaire est soumis, JSF utilise la mthode setValeur() du JavaBean alea.Nombre pour injecter la valeur du champ <h:inputText> dans l'objet nombre (mapping HTML/Objet !). 2. <h:form> : Lorsque nous dsirons soumettre une valeur, nous devons passer systmatiquement par un formulaire. C'est la cas ici avec cette balise <h:form> qui reprsente effectivement les formulaires. C'est une balise que nous connaissons dj. Toutefois, la grande nouveaut ici, c'est que nous ne spcifions aucun attribut. En effet, la navigation se fait uniquement dans le fichier de configuration prvu a cet effet <faces-config.xml>. Le gros avantage de ce systme, c'est que la page Web devient encore plus claire et qu'il est facile de faire des changements ultrieurs. Tout se trouve dans le mme fichier de configuration.

Remarquons ici qu'il n'existe pas de bouton de soumission pour valider notre requte. La validation se fait lorsque l'oprateur appuie sur la touche entre aprs avoir saisie la valeur souhaite. Le gestionnaire de navigation, intgr dans le contrleur FacesServlet, cherche une rgle de navigation applicable au contexte courant, dcrite dans le fichier de configuration <faces-config.xml> : - Si une correspondance est trouve, alors la page suivante est affiche. - Sinon la page courante est recharge. Nous n'avons pas dfini de rgle de navigation, c'est donc toujours la mme page Web qui se raffiche avec des informations adaptes l'volution de la session. Lorsque vous avez besoin de plusieurs zones de saisie pour un mme formulaire, cette fois-ci, il est ncessaire d'utiliser un bouton de soumission. En effet, les proprits relatives ces zones de texte rcuprent juste les valeurs. Le bouton de soumission fait lui appel la bonne mthode du bean qui s'occupe uniquement du traitement de l'ensemble des valeurs rcupres.
Nous avons galement rutilis les balises <h:outputText> que nous connaissons dj. 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 proprits adapte au message requis. Ainsi, nous affichons respectivement les proprits progression, tentative et rsultat au endroits idoines.

Remarquez au passage que ces balises JSF acceptent des attributs que nous connaisons dj 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 personnalise.
Nous avons encore beaucoup de chose dire sur la gestion des beans au travers du fichier de configuration <faces-config.xml> comme :

1. Proposer des valeurs par dfaut, 2. Faire appel un autre bean, 3. Proposer une liste de valeur, 4. etc.

Ces aspects seront traits ultrieurement.

Rgles de navigation - navigation statique


Au travers d'un exemple simplissime, nous allons maintenant passer la navigation entre les pages Web. Dans un premier temps, nous nous intressons la navigation statique, c'est--dire que le choix des pages est dfini dans l'intitul du bouton et demeure fig. Notre application Web ralise des oprations de base, comme l'addition et la soustraction, sur deux oprandes. Une fois que les oprandes sont dfinis, il suffit de choisir l'opration traiter l'aide du bouton concern, et une nouvelle page Web apparat alors, avec le traitement correspondant l'action souhaite.

Modle MVC
Notre modle doit prendre en compte la navigation entre plusieurs pages. Par ailleurs, le traitement et le stockage des informations est toujours ralis par un bean que nous nommons ici calcul.Opration. La gestion de ce bean ainsi que la navigation entre les diffrentes pages Web sont dcrites dans le fichier prvu cet effet <facesconfig.xml>.

Constitution de l'application Web et descripteur de dploiement


Cette application Web comporte trois pages jsp avec calcul.jsp comme page d'accueil. Ensuite, le bean calcul.Opration 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>

JavaBean calcul.Opration
En ralit, vu le choix de l'organisation de notre application Web, nous nous servons de ce JavaBean uniquement pour stocker la valeur des oprandes. Le traitement est plutt ralis par la page Web appele. (Ce n'est certainement pas le meilleur choix, mais c'est une solution pour valider la navigation statique).
calcul.Opration

package calcul; public class Opration { private int premier; private int deuxime; public int getPremier() { return premier; } public void setPremier(int premier) { this.premier = premier; } public int getDeuxime() { return deuxime; } public void setDeuxime(int deuxime) { this.deuxime = deuxime; } }

Page d'accueil calcul.jsp


Deux balises JSF dclenchent des actions lorsque l'utilisateur clique sur leur reprsentation graphique. Il s'agit de la balise <h:commandButton> qui reprsente un bouton de soumission, et la balise <h:commandLink> qui reprsente un lien HTML. Lorsque l'utilisateur clique sur l'un ou sur l'autre, une clef de navigation ou outcome est renvoye. Cette clef peut tre statique, en dur dans le code de la page JSP, ou dynamique, calcule par une EL. Vous prcisez 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>Oprande 1 : <h:inputText value="#{opration.premier}" /></h4> <h4>Oprande 2 : <h:inputText value="#{opration.deuxime}" /></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 reprsenter les actions raliser. Les actions sont exprimes directement "en dur" sous forme de chanes de caractres, respectivement "plus" et "moins". Il s'agit bien d'une navigation statique. L'intitul du bouton est spcifi 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 renvoye au gestionnaire de navigation JSF. Le gestionnaire de navigation, intgr dans le contrleur FacesServlet, cherche une rgle de navigation applicable au contexte courant, dcrite dans le fichier de configuration <faces-config.xml> :

- Si une correspondance est trouve, alors la page suivante est affiche. - Sinon la page courante est recharge.

Fichier de configuration <faces-config.xml>


Je rappelle que ce fichier permet de spcifier les navigations possibles qui peut exister entre les diffrentes pages Web prsentes dans l'application. Ce fichier permet galement de spcifier l'ensemble des JavaBeans mettre en oeuvre afin qu'il soient correctements crs par le contrleur, et ensuite utiliss directement par les pages JSP concernes.
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>opration</managed-bean-name> <managed-bean-class>calcul.Opration</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> </faces-config>

Cette fois-ci, nous avons besoin de dcrire les deux types d'lments : la navigation entre les diffrentes pages et le JavaBean.

1. Description du bean : Nous connaissons dj sa structure. Toutefois, je ferais juste remarquer que nous avons choisi un scope request. En effet, nous ne restons pas sur la page d'accueil, elle n'existe qu'une fois. Il faut juste conserver les valeurs des oprandes, le temps de passage d'une page Web l'autre, c'est--dire le temps de la requte. 2. Navigation entre les pages : Les rgles de navigation sont spcifies au travers de la balise <navigation-rule>. Vous indiquez ensuite la page source au moyen de la balise <from-view-id>. Vous prcisez alors la ou les pages Web atteindre depuis cette source avec la balise <navigation-case>. Si plusieurs pages peuvent tre atteintes depuis cette source, il faut alors spcifier la clef de navigation qui nous orientera sur la bonne page Web atteindre. C'est la balise <from-outcome> qui rcupre la clef de navigation, et c'est la balise <to-view-id> qui indique la page Web afficher.

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'ambigut possible. Tentez l'exprience, et vous remarquerez que cela fonctionne correctement.

Les pages Web de destination plus.jsp et moins.jsp


Ces pages servent uniquement la visualisation du rsultat. 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 ralis ici avec une des oprations, + 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 rsultat est : </h2> <hr /> <h4> <h:outputText value="#{opration.premier}" /> + <h:outputText value="#{opration.deuxime}" /> = <h:outputText value="#{opration.premier + opration.deuxime}" /> </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 rsultat est : </h2> <hr /> <h4> <h:outputText value="#{opration.premier}" /> - <h:outputText value="#{opration.deuxime}" /> = <h:outputText value="#{opration.premier - opration.deuxime}" /> </h4> </body> </html> </f:view>

Navigation dynamique - Gestion de tableau - Liens


Nous allons reprendre l'application Web qui permet de tirer automatiquement un nombre alatoire 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 apparat 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 mme session, il sera possible maintenant de tout rinitialiser au niveau du bean nombre, et ainsi de tout recommencer. Cela va nous permettre de grer une navigation dynamique.

Sur la page fin.jsp, nous voyons apparatre deux nouveauts : 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 systmatiquement de trois. Nous ferons en sorte ultrieurement 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, reprsentant le traitement des calculs raliser, doivent tre galement rinitiliss.

Modle MVC
Notre modle doit prendre en compte la navigation entre les deux pages. Par ailleurs, le traitement des informations est toujours ralis par le bean alea.Nombre qui comportera toutefois des attributs et des mthodes supplmentaires, vu que notre site s'est enrichi.

Constitution de l'application Web et descripteur de dploiement


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</servletclass> <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 dploiement <web.xml> est totalement identique celui que nous avions dj dfini. Effectivement, nous faisons appel la mme page d'accueil. Par ailleurs le contrleur est toujours le mme lorsque nous dveloppons un systme JSF. Je rappelle que c'est l'aide du fichier de configuration <facesconfig.xml> que nous dcrivons la navigation entre les deux pages Web alea.jsp et fin.jsp.

Gestion de l'ensemble du traitement l'aide du bean alea.Nombre


Nous devons rajouter un certain nombre d'lments dans notre bean alea.Nombre afin de rpondre ces nouvelles attentes. Nous devons notamment mettre en place le systme d'historique, c'est--dire les valeurs que l'oprateur choisi durant ses phases de test. Par ailleurs, nous devons implmenter une navigation dynamique. Effectivement, lorsque l'oprateur 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 troisime coup et que nous n'avons toujours pas trouv la bonne valeur. Par ailleurs, il faut penser rinitialiser les valeurs des attributs lorsque l'oprateur 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 ractiver 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 getRsultat() { 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; } }

1. Pour la gestion de l'historique, nous prenons un ArrayList qui gre les tableaux dynamiques de type quelconque. Par dfinition, il est donc de taille variable. JSF utilise plusieurs type de conteneurs : un conteneur squenciel qui hrite de la classe anctre List, comme c'est le cas avec ArrayList, et un conteneur associatif qui hrite de la classe anctre Map. Il permet galement, tout simplement, de grer des tableaux statiques. Attention toutefois, il s'agit systmatiquement de tableaux d'objets (nous excuterons le mme exemple avec un tableau statique tout l'heure). 2. Puisque les attributs du bean peuvent tre initialiss de plusieurs manires, j'ai prfr mettre en place une mthode prive spcifique init(). Cette mthode est lance partir du constructeur, mais aussi par la mthode recommencer(). 3. La navigation dynamique est assure respectivement par les mthodes fini() et recommencer(). La mthode fini() value le rsultat du test avec le nombre de tentative ralise. Si le nombre de tentative atteint 3 et que le test n'est pas bon, la mthode renvoie la chane de caractres "finir". Dans le cas contraire, la mthode fini() renvoie la chane de caractres "continuer". La mthode recommencer() initialise les attributs du bean avant de renvoyer la chane de caractre "recommencer" qui sera utile pour revenir sur la page d'accueil au cas o.

Page d'accueil du site alea.jsp


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&eacute;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="#{nombre.fini}" value="Valider votre choix" /> <h:commandButton action="#{nombre.recommencer}" value="Tout recommencer" /> </p> </h:form> <hr /> <h3><h:outputText value="#{nombre.rsultat}" style="color: blue"/></h3> </body> </html> </f:view>

Cette fois-ci, dans l'attribut action de la balise <h:commandButton>, nous ne plaons plus directement une chane de caractres, mais nous passons par une expression EL JSF, qui en ralit fait appel une mthode spcifique du bean nombre, et qui dlivre galement une chane de caractres. La navigation dpend maintenant essentiellement du rsultat de cette expression et n'est donc pas fige. C'est ce qui dfini la navigation dynamique.

Notons au passage qu'une expression peut faire appel une mthode d'un objet qui ne fait pas parti d'une proprit. Pour cela, la mthode ne doit pas prendre de paramtres et doit retourner une chane de caractres qui prcise la navigation suivre. En ralit, nous pouvons solliciter une mthode qui ne retourne rien partir de l'attribut action de cette balise <h:buttonCommand> dans le cas o vous ne souhaitez pas de navigation particulire.
Lorsque nous utilisons l'expression #{nombre.fini}, nous lanons en ralit la mthode fini() du bean nombre. Cette mthode, aprs son test, nous renvoie une chane de caractres qui est soit "finir" soit "continuer". Vu que nous sommes sur l'attribut action de la balise <h:commandButton>, je rappelle que la chane renvoye correspond alors une rgle de navigation qui va tre interprte par le fichier de configuration <faces-config.xml>.

Fichier de configuration <faces-config.xml>


Ce fichier de configuration dispose de trois lments. Effectivement, nous le savons dj, nous devons grer le bean nombre. Par ailleurs, nous disposons de deux pages Web qui sont sources, partir desquelles, nous pouvons voluer vers une autre page.
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> <navigation-case> <from-outcome>finir</from-outcome> <to-view-id>/fin.jsp</to-view-id> <redirect /> </navigation-case> </navigation-rule> <navigation-rule> <navigation-case> <from-outcome>recommencer</from-outcome> <to-view-id>/alea.jsp</to-view-id> <redirect /> </navigation-case> </navigation-rule> <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>

1. Dans ce contexte, nous devons mettre en place une rgle de navigation pour chaque page Web qui propose d'voluer ventuellement vers une autre page. Vu que nous avons deux pages Web sources, nous devons donc mettre en place deux balises <navigation-rule>. 2. Nous l'avons vu, vous pouvez spcifier la valeur de vos source au moyen de la balise <from-view-id>, ce que je n'ai pas fait ici, puisqu'il n'existe pas d'ambigut possible. Et puis de toute faon, la page d'accueil peut aussi bien tre sollicit par elle-mme que par la page fin.jsp. 3. Je rappelle que la balise <to-view-id> spcifie la page atteindre et que la condition pour atteindre cette page est dfinie au moyen de la balise <from-outcome>. A l'intrieur de ces dernires balises, nous voyons les chane de caractres "finir" et "recommencer" qui servent de condition d'volution. Ces chanes de caractres sont dlivres respectivement par les mthodes fini() et recommencer() du bean nombre. 4. La mthode fini() propose ventuellement une autre chane de caractres "continuer" qui n'est pas value ici. Je rappelle que si la rgle de navigation n'est pas rsolue, c'est la page dj en activit qui est recharge. Dans notre cas, c'est le bouton "Valider votre choix" de la page d'accueil qui sollicite cette mthode fini(), et donc si cette mthode renvoie la chane de caractres "continuer", c'est de nouveau la page d'accueil qui est recharge. Nous voyons l l'intrt de la navigation dynamique. 5. Remarquez la prsence de la balise optionnelle <redirect />. Elle n'est pas d'un grand intrt (nous pouvons nous en passer). Toutefois, dans le cas o nous l'utilisons, nous demandons explicitement remettre jour l'URL du navigateur, qui du coup montre qu'elle est la page actuellement en activit. Dans le cas contraire, nous voyons toujours apparatre le mme nom d'URL, correspondant la page d'accueil du site, donc ici alea.jsp. 6. Pour finir, vous avez la possibilit d'utiliser des joker ( * ) sur la balise <from-view-id> afin de spcifier qu'un ensemble de source peut activer une mme page Web. Voici quelques exemples : <from-view-id>*</from-view-id> <from-view-id>/*</from-view-id> <from-view-id>/enregistrement/*</from-view-id>

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> <navigation-case> <from-action>#{nombre.fini}</from-action> <from-outcome>finir</from-outcome> <to-view-id>/fin.jsp</to-view-id> <redirect /> </navigation-case> </navigation-rule> <navigation-rule> <navigation-case> <from-action>#{nombre.recommencer}</from-action> <from-outcome>recommencer</from-outcome> <to-view-id>/alea.jsp</to-view-id> <redirect /> </navigation-case>

</navigation-rule> <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>

Ce n'est pas le cas ici, mais il peut arriver que plusieurs mthodes dlivrent exactement le mme message qui sert de rgle de navigation. Il faut alors savoir d'o vient le message. Dans ce cas de figure, vous devez alors rajouter une balise supplmentaire <from-action> qui spcifie quelle est la mthode qui a propose ce message.

La page fin.jsp
Il ne reste plus qu'a dfinir la page fin.jsp. Je profite de cette page pour montrer comment mettre en oeuvre un lien JSF et surtout comment prsenter un tableau dynamique avec un nombre de lignes variable suivant l'information afficher (Ici normalement, nous n'aurions pas besoin de cette fonctionnalit particulire, vu que la taille est fixe).
fin.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><h:outputText value="C'est fini : le test est limit trois coups" /></h2> <hr /> <h:dataTable value="#{nombre.historique}" var="historique" border="1" cellpadding="5" > <h:column> <f:facet name="header"><h:outputText value="Historique" /></f:facet> <h:outputText value="#{historique}" /> </h:column> </h:dataTable> <hr /> <h2><h:outputText value="Nombre trouver : #{nombre.nombreARechercher}" /></h2> <hr /> <h:form> <h3><h:commandLink action="#{nombre.recommencer}" value="Recommencer" /></h3> </h:form> </body> </html> </f:view>

1. Pour la mise en oeuvre d'un lien, la technique est simple et tout fait similaire celle utilise pour un bouton. En ralit, la seule diffrence est le nom de la balise utilise. Dans le cas d'un bouton, c'est la balise <h:commandButton> qu'il faut choisir, dans le cas d'un lien, c'est la balise <h:commandLink>. 2. Pour mettre en place un tableau dynamique (avec donc un nombre de lignes variable), il suffit de prendre la balise <h:dataTable>. A l'aide de l'attribut value de cette balise, vous spcifier ensuite le tableau dynamique qui possde l'ensemble des informations afficher. En ralit, l'attribut value attend un objet correspondant la classe List ou un de ses decendants, comme ArrayList. Il faut ensuite pouvoir rcuprer une valeur parmi cette liste qui est propose. Vous spcifiez alors un lment de cette liste au travers de l'attribut var. Les attributs border et cellpadding sont des attributs que nous connaissons dj en HTML. 3. A l'intrieur de ce tableau dynamique, vous spcifiez le nombre de colonnes en utilisant, tout simplement, la balise <h:column> autant de fois qu'il y a de colonnes afficher dans le tableau. 4. Vous pouvez, pour chacune de ces colonnes, proposer un titre. Dans ce cas, vous devez utiliser une balise <f:facet>. D'une faon gnrale, cette balise <f:facet> permet d'associer un composant un autre sans qu'il y ait une relation de filiation entre les deux composants (Nous retrouverons cette balise dans d'autres situations qui n'ont rien voir avec les tableaux). Le composant qui doit tre mis en relation, doit tre spcif au moyen de l'attribut name. Ainsi, dans notre cas, la balise <f:facet> se trouve l'intrieur de la balise <h:colomn>. Cette balise doit donc tre en relation avec l'lment "header", qui est donn par l'attribut name. Avec cette dmarche, nous indiquons finalement que la colonne doit disposer d'un titre (header dans les tableaux). 5. Pour finir, vous n'avez plus qu' afficher une valeur particulire de l'ensemble des valeurs proposes par la liste, en faisant rfrence directement la variable qui a t dclare au moment de la dfinition du tableau, ici #{historique}.

Tableau statique
Pour conclure, je vous propose de revoir le bean alea.Nombre afin que ce dernier gre l'historique l'aide d'un tableau statique. Seul ce bean est modifier, les pages JSP n'ont pas subir de changements.
alea.Nombre

package alea; import java.util.*; public class Nombre { private int valeur; private int nombreARechercher; private int tentative; private boolean test; private Integer[] historique = new Integer[3]; public Nombre() { init(); } private void init() { nombreARechercher = (int)(Math.random()*10)+1; tentative = 0; valeur = 0; } public void setValeur(int valeur) { this.valeur = valeur; historique[tentative++] = valeur; test = nombreARechercher == valeur; }

public int getValeur() { return valeur; } public int getTentative() { return tentative; } public String getRsultat() { 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 Integer[] getHistorique() { return historique; } public int getNombreARechercher() { return nombreARechercher; } }

Puisque nous manipulons des entiers (int) dans la gestion des historiques, vous devez travailler avec la classe enveloppe reprsentative des entiers, savoir la classe Integer. En effet, la gestion des tableaux dans JSF se fait systmatiquement avec des tableaux d'objets. Par contre, une fois que la dclaration est faite, vous pouvez travailler directement avec des int, ceci depuis la version 5 de java.

Gestionnaire de disposition, les radio-boutons, les styles


Nous allons reprendre l'application Web sur le calcul des oprations de base. Nous en profiterons pour faire une prsentation plus agrable en mettant en oeuvre un panneau qui reprsente toutes les informations sous la forme d'une grille. Nous en profiterons galement pour voir comment mettre en oeuvre les radio-boutons et donc comment mettre en place une liste prdfinie de valeurs.

Modle MVC
Le modle est plus simple que lors de notre dernire application Web. En effet, cette fois-ci, tout l'affichage s'excute sur la mme page calcul.jsp, qui est la page d'accueil du site. Du coup, notre bean calcul.Opration devra s'occuper de plus de choses. Il devra grer l'affichage du rsultat et rcuprer le type d'opration afin de pouvoir calculer le rsultat correctement.

Constitution de l'application Web et descripteur de dploiement


Cette fois-ci, seule la page d'accueil calcul.jsp existe dans l'application Web. Sinon, le descripteur de dploiement demeure identique.
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>

Traitement de l'application Web l'aide du bean calcul.Opration


Ce composant dispose d'un certain nombre d'lments qui n'existaient pas la dernire fois :
calcul.Opration

package calcul; public class Opration { private int premier; private int deuxime; private int troisime; private char type = '+'; private int rsultat; public void setType(String type) { this.type = type.charAt(0); } public String getType() { return ""+type; } public int getPremier() { return premier; } public void setPremier(int premier) { this.premier = premier; } public int getDeuxime() {

return deuxime; } public void setDeuxime(int deuxime) { this.deuxime = deuxime; } public int getTroisime() { return troisime; } public void setTroisime(int troisime) { this.troisime = troisime; } private void calcul() { switch (type) { case '+' : rsultat = premier + deuxime + troisime; break; case '-' : rsultat = premier - deuxime - troisime; break; case '*' : rsultat = premier * deuxime * troisime; break; } } public String getRsultat() { calcul(); if (premier==0) return "Aucun rsultat"; return premier+" "+type+" "+deuxime+" "+type+" "+troisime+" = "+rsultat; } }

1. Il faut connatre le type d'opration afin que le calcul s'effectue correctement. Pour cela, j'utilise la proprit type. Attention toutefois, l'attribut est de type char alors que les mthodes manipulent le type String. Effectivement, les informations que nous plaons dans les balises relatives aux radio-boutons sont des chanes de caractres. Par contre, le calcul est plus facile raliser si nous travaillons directement avec le caractre correspondant l'opration traiter. Du coup, nous sommes oblig d'effectuer une conversion entre ces deux types. 2. Nous devons prsenter le rsultat dans la page d'accueil. Nous fabriquons donc une proprit rsultat (en lecture seule) qui retourne une chane de caractres prsentant la simulation de l'opration. Au pralable, cette proprit fait appel la mthode prive calcul() qui ralise le traitement demande. Si jamais le premier oprande n'est pas dfini, la proprit rsultat retourne la chane de caractres "Aucun rsultat".

Page d'accueil du site calcul.jsp


Notre page d'accueil s'occupe de la saisie des diffrents oprandes. Elle permet de choisir le type d'opration raliser. Elle propose enfin le rsultat en consquence. La mise en page est relativement soigne, grce l'utilisation des styles CSS. La disposition des lments est galement pris en compte au moyen d'un panneau JSF.
calcul.jsp

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <style type="text/css"> .un {background-color: #00CC00; } .deux {background-color: #009900; } .gnral {background-color: #006633; font-weight: bold; } h2 { background-color: #006633; padding: 5px; border : groove; } body {font-family: verdana, Arial; color: yellow; background-color: green; } </style> <f:view> <html> <body> <h2><h:outputText value="Calcul sur des oprations de base" /></h2> <hr /> <h:form> <h:panelGrid columns="2" cellpadding="3" styleClass="gnral" rowClasses="un, deux"> <f:facet name="header"><h:outputText value="Liste des oprandes" /></f:facet> <h:outputText value="Oprande 1 : " /> <h:inputText value="#{opration.premier}" size="30" maxlength="10" /> <h:outputText value="Oprande 2 : " /> <h:inputText value="#{opration.deuxime}" size="30" maxlength="10" /> <h:outputText value="Oprande 3 : " /> <h:inputText value="#{opration.troisime}" size="30" maxlength="10" /> <f:facet name="footer"> <h:selectOneRadio value="#{opration.type}" style="font-weight: bold" > <f:selectItem itemLabel="Addition" itemValue="+" /> <f:selectItem itemLabel="Soustraction" itemValue="-" /> <f:selectItem itemLabel="Multiplication" itemValue="*" /> </h:selectOneRadio> </f:facet> </h:panelGrid> <hr /> <p><h:commandButton action="valider" value="Valider l'opration" /></p> </h:form> <hr /> <h2><h:outputText value="#{opration.rsultat}" /></h2> </body> </html> </f:view>

1. Les styles CSS : il est gnralement prfrable de sparer la partie "agrment visuel" de l'organisation des lment sur la page. Le rglage de l'aspect visuel se ralise au moyen des styles CSS. Vous les dfinissez l'intrieur de la balise <style> en rglant l'attribut type avec la valeur "text/css". Ensuite, au sein de cette balise, vous pouvez dfinir de nouveaux lments qui vont correspondre une prsentation spcifique et personnalise. Dans le monde de CSS, ces lments s'appellent des classes. Pour qu'un lment soit considr comme une classe personnalise, vous pouvez choisir le nom que vous voulez condition que ce mot soit prfix du point. Ensuite, vous placez l'intrieur de la dfinition de la classe, dlimite par des accolades, tous les lments qui correspondent une prsentation spcifique. Chaque lment doit tre ponctu par le point-virgule. Ainsi, il est possible pour une classe, de proposer plusieurs traitements de

prsentation, et d'avoir ainsi un affichage vraiment personnalis. Avec les CSS, il est galement possible de changer le comportement par dfaut des balises du HTML. Il suffit pour cela de redfinir la balise concerne et de prendre des lments qui modifient uniquement certains aspects de la balise. 2. Panneau avec placement des composant suivant une grille : JSF intgre des panneaux qui permettent de placer les composants de faon organiss suivant des lignes et des colonnes. La balise correspondante est <h:panelGrid>. Dans cette balise, vous rglez un certain nombre d'attributs. Le plus important tant, bien entendu celui qui gre les colonnes. Il s'agit donc de l'attribut columns. Une fois que vous avez choisi le nombre de colonne, vous pouvez placer tout ce que vous voulez dans ce panneau, quelque soit le type de composant. Il suffit de les mettre la suite les uns des autres et le nombre de ligne sera grer en consquence. Ainsi, dans notre exemple, nous plaons six lments, et comme nous avons rgl le nombre de colonne 2, nous aurons en finalit un panneau avec six lments placs dans une grille de trois lignes et de deux colonnes. La balise <h:panelGrid> dispose de bien d'autres attributs qui permettent de grer spcialement l'apparence au moyen des styles CSS, comme bien d'autres balises d'ailleurs. Dans ce cas l, toutes se terminent pas le terme Class si un seul style est requis ou Classes dans le cas o vous intgrez plusieurs styles pour le mme lment. Ainsi vous avez les attributs styleClass (style gnral), rowClasses (style pour les lignes), columnClasses (style pour les colonnes), headerClass (style pour l'en-tte - le titre de votre panneau), footerClass (style pour le pied du panneau). Dans notre exemple, j'ai juste rgl le style pour l'aspect gnral (styleClass) qui va donc tre vrai pour l'en-tte et pour le pied du panneau. Je rgle ensuite la couleur des lignes du panneau (rowsClasses) avec une alternance de deux couleurs (donc deux classes CSS), ce qui donne un aspect trs agrable. 3. En-tte (titre) et pied du panneau : Comme le tableau de type <h:dataTable>, le panneau <h:panelGrid> intgre la fois une partie en-tte et une partie pied. Pour cela, vous pouvez utiliser la technique que nous avons dj mis en oeuvre au moyen de la balise <f:facet> qui permet d'accder une proprit d'une balise, alors que nous sommes l'intrieur de cette dernire. Cette balise <f:facet> sollicite des informations de la balise parente, il suffit alors de prciser lesquelles au moyen de son seul attribut name. Ici, nous spcifions d'une part "header" et d'autre part "footer" pour mettre en place respectivement la zone d'en-tte et la zone du pied du panneau. 4. Attributs supplmentaires de <h:inputText> : Nous connaissons bien cette balise. Toutefois, il peut tre intressant d'utiliser des attributs spcifiques de cette balise, afin d'imposer une dimension du composant correspondant, l'aide de l'attribut size. Ensuite, d'un point de vue pratique, il peut tre intressant de faire en sorte que le nombre de chiffres saisis soit limit une certaine valeur que vous spcifiez au moyen de l'attribut maxlenght. 5. Les boutons radio : La mise en oeuvre d'un ensemble de boutons radio se ralise avec la balise <h:selectOneRadio>. Vous spcifiez ensuite toutes les rubriques qui font parties du choix l'aide des balises <f:selectItem>. Dans une de ces balises, vous disposez ensuite de deux attributs. Le premier, itemLabel, permet d'indiquer le texte qui va apparatre dans la page Web, le second, itemValue, est la valeur qui va tre envoye la proprit spcifie dans l'attribut value de <h:selectOneRadio>. Attention, la valeur envoye, partir de l'attribut itemValue d'un <f:selectItem> est toujours considre comme une chane de caractres. Si vous dsirez travailler avec d'autres types, comme ici avec un simple caractre, vous devez effectuer un transtypage l'intrieur de vos proprits.

La balise <f:selectItems>
Afin d'viter le dsagrment de devoir transtyper avec les balises de type <f:selectItem>, il est possible d'utiliser une autre technique. Vous pouvez en effet, prendre une balise <f:selectItems> plutt que la balise <f:selectItem>. Remarquez la prsence du "s" qui fait la diffrence. Cette fois-ci, vous spcifiez une seule balise qui reprsente l'ensemble des lments du choix raliser. Voici, d'ailleurs la page d'accueil avec cette nouvelle dmarche :
calcul.jsp

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <style type="text/css"> .un {background-color: #00CC00; } .deux {background-color: #009900; } .gnral {background-color: #006633; font-weight: bold; } h2 { background-color: #006633; padding: 5px; border : groove; } body {font-family: verdana, Arial; color: yellow; background-color: green; } </style> <f:view> <html> <body> <h2><h:outputText value="Calcul sur des oprations de base" /></h2> <hr /> <h:form> <h:panelGrid columns="2" cellpadding="3" styleClass="gnral" rowClasses="un, deux" > <f:facet name="header"><h:outputText value="Liste des oprandes" /></f:facet> <h:outputText value="Oprande 1 : " /> <h:inputText value="#{opration.premier}" size="30" maxlength="10" /> <h:outputText value="Oprande 2 : " /> <h:inputText value="#{opration.deuxime}" size="30" maxlength="10" /> <h:outputText value="Oprande 3 : " /> <h:inputText value="#{opration.troisime}" size="30" maxlength="10" /> <f:facet name="footer"> <h:selectOneRadio value="#{opration.type}" style="font-weight: bold" > <f:selectItems value="#{opration.oprations}"/> </h:selectOneRadio> </f:facet> </h:panelGrid> <hr /> <p><h:commandButton action="valider" value="Valider l'opration" /></p> </h:form> <hr /> <h2><h:outputText value="#{opration.rsultat}" /></h2> </body> </html> </f:view>

La page devient plus courte. Vous devez juste prciser, dans l'attribut value de <h:selectItems>, quelle est la proprit qui gre l'ensemble des lments constituant votre choix. Finalement, la description des lments se retrouve dans le bean calcul.Opration. calcul.Opration

package calcul; import javax.faces.model.SelectItem; public class Opration { private int premier; private int deuxime; private int troisime; private char type = '+'; private int rsultat; private SelectItem[] oprations = { new SelectItem('+', "Addition"), new SelectItem('-', "Soustraction"), new SelectItem('*', "Multiplication") };

public SelectItem[] getOprations() { return oprations; } public void setType(char type) { this.type = type; } public char getType() { return type; }

Pour cela, vous devez crer une proprit qui est un tableau de SelectItem. Cette classe SelectItem fait partie de la bibliothque fournie par la technologie JSF. Elle est issue du paquetage javax.faces.model. Gnralement, dans l'objet de type SelectItem, nous utilisons le constructeur qui possde deux arguments. Le premier argument de ce constructeur est de type Object et permet de spcifier quel est la valeur de l'lment prendre en compte. La valeur doit tre exprime dans le type qui vous intresse. Remarquez au passage, qu'ici nous utilisons le type char qui se transforme en ralit, par sa classe enveloppe Character. Vous spcifiez ensuite, dans le deuxime argument du constructeur, le libell qui apparatra finalement dans la page Web.

La proprit type a t revue. Nous pouvons travailler directement avec le type de base char. . Le choix de prendre <h:selectItems> plutt <h:selectItem> parat plus judicieux dans ce cas l. En ralit, il est souvent prfrable de prendre presque systmatiquement cette balise <h:selectItems>. En effet, le jour o vous devez faire des modifications, seul le JavaBean est revoir. Dans le cas contraire, vous devez changer la fois la page JSP ainsi que le JavaBean correspondant.

Initialisation des proprits dans le fichier <faces-config.xml>


Lors d'une tude prcdente, nous avons vu comment grer les beans dans une structure JSF, au moyen du fichier de configuration <faces-config.xml>. Nous allons reprendre cet aspect, mais en s'intressant plus particulirement cette foisci, l'initialisation des proprits.
Nous allons reprendre l'application Web sur le calcul des oprations de base, qui va nous servir de support pour cette tude. Nous allons rajouter un certain nombre de fonctionnalits supplmentaires. En effet, cette fois-ci, nous pourrons choisir le nombre d'oprandes. Nous traitons galement, dans cette application Web, la gestion d'un historique des calculs dj raliss dans la session courante, c'est--dire pour chaque utilisateur.

Cette tude va nous permettre galement de voir comment mettre en place des menus droulants style ComboBox, de grer plusieurs beans dans la mme page Web, et de visualiser des lments suivant certaines conditions.

Constitution de l'application Web


Cette fois-ci, dans l'application Web, nous disposons de trois beans qui grent le comportement global de la seule page d'accueil calcul.jsp. Sinon, le descripteur de dploiement demeure identique.

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>

Modle MVC

Dans ce modle, nous disposons toujours d'une seule page Web calcul.jsp, qui est la page d'accueil du site. Par contre, la partie traitement de l'information est ralis par trois beans spars, tout ceci pour la mme page Web. Du coup, nous avons une relation forte entre ces diffrents beans, puisque le bean calcul.Opration est compos d'un bean calcul.Oprandes qui est lui-mme compos d'un ensemble de calcul.Oprande.

Nous aurions tout pu trait partir d'un seul bean, mais c'est l'occasion de voir comment faire lorsque nous dcoupons notre traitement avec diffrents composants. Attention : si vous dcidez de prendre plusieurs beans, il faut que les objets correspondants soient crs. C'est ce que ralise le contrleur FacesServlet par le moyen de la description labore dans le fichier de configuration <faces-config.xml> qui doit donc tre correctement rempli. Il est galement possible, pour les objets composites, d'tre dclars et initialiss directement par l'objet conteneur, sans passer par ce fichier de configuration.

Traitement de l'application Web l'aide des diffrents bean - calcul.Opration - calcul.Oprandes - calcul.Oprande
Le premier bean calcul.Oprande est juste compos de deux proprits : numro qui indique quel est l'indice de l'oprande (valeur 1 pour le premier oprande), et valeur qui reprsente tout simplement la valeur qui va servir au calcul des oprations.
calcul.Oprande

package calcul; public class Oprande { private int numro; private int valeur; public Oprande() {} public Oprande(int numro, int valeur) { this.numro = numro; this.valeur = valeur; } public int getNumro() { return numro; } public void setNumro(int numro) { this.numro = numro; } public int getValeur() { return valeur; } public void setValeur(int valeur) { this.valeur = valeur; } }

Le deuxime bean calcul.Oprandes est largement plus toff. Voici d'ailleurs l'ensemble des proprits le constituant :
calcul.Oprandes

package calcul; import javax.faces.model.SelectItem; public class Oprandes { private int valeur = 2; private SelectItem[] choix; private Oprande[] liste; public int getValeur() { return valeur; } public int getOprande(int indice) { return liste[indice].getValeur(); } public Oprande[] getListe() { return liste; } public void setListe(Oprande[] liste) { this.liste = liste; } public void setValeur(int valeur) { liste = new Oprande[this.valeur = valeur]; for (int i=0; i<liste.length; i++) liste[i] = new Oprande(i+1, 0); } public void setMaxi(int maxi) { choix = new SelectItem[maxi-1]; for (int i=2; i<=maxi; i++) choix[i-2] = new SelectItem(i, ""+i); } public SelectItem[] getChoix() { return choix; } }

1. liste (lecture-criture) : cette proprit permet de stocker l'ensemble des oprandes qui seront ncessaires la ralisation des oprations requises. 2. valeur (lecture-criture) : cette proprit indique quel est le nombre d'oprandes qui seront ncessaires pour effectuer le calcul. Au dpart, le nombre d'oprandes est fix 2, directement initialis par l'attribut lui-mme. Nous aurions pu initialiser ce nombre partir du fichier de configuration <faces-config.xml>. Lorsque nous dcidons de changer le nombre d'oprandes, une nouvelle liste est cre, et la valeur de chacun des oprandes est initialise 0. 3. choix (lecture seule) : cette proprit permet de construire un menu droulant de type ComboBox sur la page d'accueil du site. La constitution du menu est, en ralit, cre par la proprit maxi. 4. maxi (criture seule) : Cette proprit est sollicit une seule fois. Elle correspond la valeur maximum d'oprandes que nous pouvons traits dans nos calculs. La valeur maxi est spcifie dans le fichier de configuration <faces-config.xml>. C'est cette proprit qui fabrique le menu droulant, en proposant les valeurs requises, en partant de 2 jusqu' la valeur maxi. 5. getOprande() : cette mthode, utilise par le bean calcul.Opration, retourne tout simplement la valeur de l'oprande choisi.

Nous retrouvons notre bean calcul.Opration dans lequel nous retrouvons un certain nombre de proprits que nous avons dj mis en oeuvre lors des tudes antrieures. Nous remarquons toutefois, un certain nombre de nouvelles proprits et de mthodes que nous allons dcrire ici.
calcul.Opration

package calcul; import java.util.ArrayList; import javax.faces.model.SelectItem; public class Opration { private char type = '+'; private int rsultat; private Oprandes oprandes; private ArrayList<String> historique = new ArrayList<String>(); private boolean montrerHistorique = false; private SelectItem[] oprations = { new SelectItem('+', "Addition"), new SelectItem('-', "Soustraction"), new SelectItem('*', "Multiplication") }; public SelectItem[] getOprations() { return oprations; } public ArrayList<String> getHistorique() { return historique; } public boolean isMontrerHistorique() { return montrerHistorique; } public void validerHistorique() { montrerHistorique = !montrerHistorique;

} public Oprandes getOprandes() { return oprandes; } public void setOprandes(Oprandes oprandes) { this.oprandes = oprandes; } public void setType(char type) { this.type = type; } public char getType() { return type; } private void calcul() { switch (type) { case '+' : rsultat = 0; for (int i=0; i<oprandes.getValeur(); i++) rsultat+=oprandes.getOprande(i); break; case '-' : rsultat = oprandes.getOprande(0); for (int i=1; i<oprandes.getValeur(); i++) rsultat-=oprandes.getOprande(i); break; case '*' : rsultat = 1; for (int i=0; i<oprandes.getValeur(); i++) rsultat*=oprandes.getOprande(i); break; default : rsultat = 0; } } public String getRsultat() { calcul(); if (oprandes.getOprande(0)==0) return "Aucun rsultat"; String sortie = oprandes.getOprande(0)+" "+type+" "; for (int i=1; i<oprandes.getValeur()-1; i++) sortie = sortie + oprandes.getOprande(i)+" "+type+" "; sortie = sortie+oprandes.getOprande(oprandes.getValeur()-1)+" = "+rsultat; if (!historique.contains(sortie)) historique.add(sortie); return "Rsultat : "+ sortie; } }

1. oprandes (lecture-criture) : Cette proprit correspond l'ensemble des oprandes qui servirons pour le traitement des calculs raliser. Attention, dans le code, nous remarquons qu'en apparence, l'objet n'est jamais cr. Ne vous inquietez pas. En ralit, l'objet est cr par le contrleur FacesServlet, dont la procdure de mise en oeuvre est dfinie dans le fichier de configuration <faces-config.xml>. Du coup, l'criture ne se fait qu'une seule fois, et c'est le contrleur qui l'effectue au tout dpart. 2. historique (lecture seule) : Cette proprit permet de recenser l'ensemble des calculs qui sont raliss successivement dans la session. Par contre, c'est l'aide de la proprit rsultat que l'historique volue. 3. rsultat (lecture seule) : Cette proprit a t revue afin de prendre en compte un nombre d'oprandes variable. Cette proprit gre galement l'historique. 4. calcul() : Cette mthode a t revue afin d'intgrer le nombre d'oprandes variable. 5. montrerHistorique (lecture seule) : Cette proprit va servir dterminer si l'historique doit tre visible ou pas sur la page d'accueil. 6. validerHistorique() : Cette mthode permet de changer l'tat de visibilit de l'historique. Cette mthode va tre sollicit par l'attribut action de la balise <h:commandButton> qui gre l'apparence de l'historique. Remarquer au passage que cette mthode ne renvoie pas de chane de caractres. Cela n'est pas utile puisqu'il n'a pas de rgle de navigation prvue. En tout cas, vous avez donc la possibilit de lancer des mthodes partir de cet attribut action sans qu'il y ait spcialement un retour sous la forme d'une chane de caractres.

Initialisation des beans au travers du fichier de configuration <faces-config.xml>


Nous connaissons dj les trois balises qui sont systmatiquement utilises lors de la dfinition d'un bean l'intrieur de la balise <managed-bean>. Il s'agit : 1. <managed-bean-name> : le nom de l'objet qui sera cr. 2. <managed-bean-class> : la classe correspondant cet objet. 3. <managed-bean-scope> : la dure de vie de cet objet.
Il existe une quatrime balise <managed-property> qui permet d'initialiser les attributs, si ncessaire.

Nous pouvons bien entendu initialiser nos attributs directement dans notre code source. Toutefois, le jour o vous dcidez de changer de valeur d'initialisation, vous serez oblig de recompiler la classe. L'avantage d'avoir un fichier de configuration, c'est qu'il est trs facile de faire des changements sans qu'il soit ncessaire de tout recompiler. Attention, pour que notre initialisation puisse tre pris en compte, il est impratif que les proprits correspondantes soient mises en oeuvre. il faut qu'il y ait au moins la proprit en criture, c'est--dire la mthode d'criture correspondante l'attribut concern.
Nous avons la possibilit d'initialiser les attributs, suivant leur nature, de quatre faons diffrentes :

1. Proposer tout simplement une valeur unique, 2. Proposer une liste de valeurs. L'attribut doit alors tre compatible avec un type List, ou tout simplement, avec un tableau d'objets. 3. Proposer un conteneur associatif qui utilise le systme cl/valeur, compatible avec un Map. 4. Proposer une interconnexion entre les beans.

Initialisation avec une valeur simple

Pour spcifier une valeur particulire pour une proprit donne, vous utilisez la balise <property-name> pour indiquer de quelle proprit il s'agit, et ensuite vous utilisez la balise <value> pour prciser la valeur d'initialisation.
Soit la dclaration de la classe suivante : public class Nombre { private int valeur; ... public void setValeur(int valeur) { this.valeur = valeur; } ... } Si vous dsirez que la proprit valeur soit initialise avec la valeur entire 5, voici ce que vous devez mettre dans votre fichier de configuration <facesconfig.xml> : <managed-bean> <managed-bean-name>nombre</managed-bean-name> <managed-bean-class>Nombre</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> <managed-property> <property-name>valeur</property-name> <value>5</value> </managed-property> </managed-bean>

Dans le cas o votre proprit est un objet, comme par exemple la chane de caractre String, il est galement possible de dire que nous ne voulons pas de valeur par l'intermdiaire de la balise <null-value /> en lieu et place de la balise <value>. Attention, la balise <null-value /> ne doit pas tre utilise pour les types primitifs. .

Initialisation avec une liste de valeurs


Il est possible d'initialiser une proprit qui possde un tableau ou une liste de valeurs. Pour cela, vous utilisez la balise <list-entries>. Ensuite, vous spcifier chaque valeur particulire du tableau, de nouveau avec la balise <value>. Si vous initialisez un tableau de chane de caractres, vous n'avez rien d'autre spcifier. Par contre, si votre tableau est d'une autre nature, vous devez indiquer le type de chaque case au moyen de la balise <value-class>.
Soit la dclaration de la classe suivante : public class Nombre { private String[] messages; private Integer[] valeurs; ... public void setMessages(String[] messages) { this.messages = messages; } public void setValeurs(Integer[] valeurs) { this.valeurs = valeurs; } } Voici un exemple d'initialisation dans le fichier de configuration correspondant ces proprits : <managed-bean> <managed-bean-name>nombre</managed-bean-name> <managed-bean-class>Nombre</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> <managed-property> <property-name>messages</property-name> <list-entries> <value>Bonjour</value> <value>Salut</value> <value>Bienvenue</value> </list-entries> </managed-property> <managed-property> <property-name>valeurs</property-name> <list-entries> <value-class>java.lang.Integer</value-class> <value>5</value> <value>3</value> <value>18</value> </list-entries> </managed-property> </managed-bean>

Initialisation avec l'aide d'une Map


Il est galement possible d'initialiser un certain nombre d'lments structurs suivant le systme cl/valeur que nous appelons des Map. Il s'agit l d'un conteneur associatif. Ce type de conteneur permet de retrouver facilement une valeur par rapport la cl choisi.
Soit la dclaration de la classe suivante : import java.util.HashMap; public class Nombre { private HashMap messages; public void setMessages(HashMap messages) { this.messages = messages; } } Voici un exemple d'initialisation dans le fichier de configuration correspondant cette proprit : <managed-bean> <managed-bean-name>nombre</managed-bean-name> <managed-bean-class>Nombre</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> <managed-property> <property-name>messages</property-name> <map-entries> <key-class>java.lang.Integer</key-class> <value-class>java.lang.String</value-class> <map-entry>

<key>5</key> <value>Le nombre est trop grand</value> </map-entry> <map-entry> <key>-1</key> <value>Erreur dans votre systme</value> </map-entry> </map-entries> </managed-property> </managed-bean> </faces-config

Vous remarquez qu'il est possible de spcifier le type de la cl et de la valeur. Toutefois, si le type est une chane de caractre, il n'est pas alors ncessaire de le prciser.

Cration d'un bean qui est un tableau (une liste) ou un Map


Nous avons mme la possibilit de crer un bean, uniquement partir du fichier de configuration, qui est tout simplement une liste (tableau) ou une Map. Ce bean n'existe pas dans un quelconque code d'un JavaBean, mais il est par contre utilisable pour les pages JSP au travers des balises JSF.
En voici un exemple : <managed-bean> <managed-bean-name>sports</managed-bean-name> <managed-bean-class>java.util.ArrayList</managed-bean-class> <managed-bean-scope>none</managed-bean-scope> <list-entries> <value>Tennis</value> <value>Football</value> <value>Ski</value> </list-entries> </managed-bean> </faces-config>

Remarquez au passage que notre bean n'a pas de scope. Il dpend d'autres lments. .

Interdpendance entre les beans


Le fichier de configuration est l pour permettre la cration des beans. C'est l'aide de ce fichier que nous avons rellement l'existance des objets. C'est le seul moyen. Nous avons des situations o un bean n'existe que pour un autre bean. Du coup, dans ce cas l, nous avons plutt une relation de type composition. Vous pouvez crer votre bean composite dans le code source, au moment de la dclaration de l'attribut, ou bien partir du fichier de configuration. Dans ce cas l, il faut bien spcifier l'interdpendance. Lorsque vous avez une relation de composition, l'objet composite n'existe que par rapport son conteneur. Du coup, il n'a pas d'existance propre, ce qui signifie que cet objet ne doit pas avoir sa propre dure de vie. Ainsi, ce type d'objet aura systmatiquement un scope none. Par contre, deux beans peuvent coexister sans avoir spcialement une relation de composition. Dans ce cas l, nous pouvont proposer une interdpendance, chacun ayant son propre scope.
Voici un exemple de cration d'un bean et d'utilisation par un autre bean. Soit la dclaration suivante : package educ; import communication.Adresse; public class Personnel { private Adresse monAdresse; public void setMonAdresse(communication.Adresse monAdresse) { this.monAdresse = monAdresse; } } Voici les dclaration suivantes dans le fichier de configuration : <managed-bean> <managed-bean-name>adresse</managed-bean-name> <managed-bean-class>communication.Adresse</managed-bean-class> <managed-bean-scope>none</managed-bean-scope> </managed-bean> <managed-bean> <managed-bean-name>utilisateur</managed-bean-name> <managed-bean-class>educ.Personnel</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> <managed-property> <property-name>monAdresse</property-name> <value>#{adresse}</value> </managed-property> </managed-bean>

Remarquez au passage l'utilisation d'une expression EL JSF. .


Voici un autre exemple d'interdpendance qui utilise la dclaration ralise plus haut : <managed-property> <list-entries> <value>Rugby</value> <value>Vol voile</value> <value>#{sports[0]}</value> <value>#{sports[1]}</value> </list-entries> </managed-property>

Fichier de configuration <faces-config.xml>


Aprs toute cette petite thorie, revenons notre application Web et consultons notre fichier de configuration <faces-config.xml>.
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>opration</managed-bean-name> <managed-bean-class>calcul.Opration</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> <managed-property> <property-name>oprandes</property-name> <value>#{oprandes}</value> </managed-property> </managed-bean> <managed-bean> <managed-bean-name>oprandes</managed-bean-name> <managed-bean-class>calcul.Oprandes</managed-bean-class> <managed-bean-scope>none</managed-bean-scope> <managed-property> <property-name>maxi</property-name> <value>7</value> </managed-property> <managed-property> <property-name>liste</property-name> <list-entries> <value-class>calcul.Oprande</value-class> <value>#{oprande1}</value> <value>#{oprande2}</value> </list-entries> </managed-property> </managed-bean> <managed-bean> <managed-bean-name>oprande1</managed-bean-name> <managed-bean-class>calcul.Oprande</managed-bean-class> <managed-bean-scope>none</managed-bean-scope> <managed-property> <property-name>numro</property-name> <value>1</value> </managed-property> <managed-property> <property-name>valeur</property-name> <value>2</value> </managed-property> </managed-bean> <managed-bean> <managed-bean-name>oprande2</managed-bean-name> <managed-bean-class>calcul.Oprande</managed-bean-class> <managed-bean-scope>none</managed-bean-scope> <managed-property> <property-name>numro</property-name> <value>2</value> </managed-property> <managed-property> <property-name>valeur</property-name> <value>3</value> </managed-property> </managed-bean> </faces-config>

Dans notre application Web, nous avons trois types de JavaBean qui sont, en ralit, associs par une relation de composition. Dans la plupart des cas, il suffit juste de faire les dclarations ncessaires directement dans le code source des beans respectifs en montrant bien cette relation. Vous crez les diffrents objets au niveau des attributs, sauf bien entendu, pour l'objet conteneur qui doit tre imprativement dclar dans le fichier de configuration.

Ici, chacun des protagonistes ont besoin d'avoir des rglages personnaliss sur certaines des proprits. Ces rglages tant raliss par configuration, nous devons bien exprimer les interdpendances aprs avoir spcifi les valeurs des proprits prendre en compte.
Nous indiquons, par exemple que notre liste d'oprandes comporte deux oprandes qui sont crs de toute pice, avec des valeurs particulires, et qui permettent de dmarrer notre application Web dans un tat dtermin. Dans cette situation, je suis oblig grer l'ensemble des beans prsents dans l'application Web.

La page d'accueil calcul.jsp


Il ne nous reste plus qu' consulter notre page d'accueil qui prend en compte les diffrents lements crs plus haut.
calcul.jsp

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <style type="text/css"> .un {background-color: #00CC00; } .deux {background-color: #009900; } .gnral {background-color: #006633; font-weight: bold; } .gras {font-weight: bold; } h2, h3 { background-color: #006633; padding: 5px; border : groove; } body {font-family: verdana, Arial; color: yellow; background-color: green; } </style> <f:view> <html> <body> <h2><h:outputText value="Calcul sur des oprations de base" /></h2> <h:form> <h3> <h:outputText value="Nombre d'oprandes : " /> <h:selectOneMenu value="#{opration.oprandes.valeur}"> <f:selectItems value="#{opration.oprandes.choix}" /> </h:selectOneMenu>

<h:commandButton value="Changer le nombre" action="changer"/> </h3> </h:form> <h:form> <h:dataTable value="#{opration.oprandes.liste}" var="oprande" cellpadding="3" styleClass="gnral" rowClasses="un, deux" > <f:facet name="header"><h:outputText value="Liste des oprandes" /></f:facet> <h:column> <h:outputText value="Oprande : #{oprande.numro}" /> </h:column> <h:column> <h:inputText value="#{oprande.valeur}" size="30" maxlength="10" /> </h:column> <f:facet name="footer"> <h:selectOneRadio value="#{opration.type}" styleClass="gras" > <f:selectItems value="#{opration.oprations}"/> </h:selectOneRadio> </f:facet> </h:dataTable> <p><h:commandButton action="valider" value="Valider l'opration" /></p> </h:form> <h2><h:outputText value="#{opration.rsultat}" /></h2> <h3> <h:form> <h:outputText value="Historique" /> <h:commandButton value="Montrer" action="#{opration.validerHistorique}" rendered="#{not opration.montrerHistorique}"/> <h:commandButton value="Cacher" action="#{opration.validerHistorique}" rendered="# {opration.montrerHistorique}"/> </h:form> <h:dataTable value="#{opration.historique}" var="historique" rendered="#{opration.montrerHistorique}"> <h:column> <h:outputText value="#{historique}" styleClass="gras"/> </h:column> </h:dataTable> </h3> </body> </html> </f:view>

Je ne ferais pas trop de remarque sur ce code, puisque nous avons dj pris connaissance de pas mal d'lments. Toutefois, nous allons regarder un peu plus en dtail la visualisation de l'historique. La liste de l'historique est tout simplement gr, encore une fois, par une balise <h:dataTable>. Par contre, nous utilisons un nouvel attribut rendered. Cet attribut attend une information boolenne qui stipule si nous dsirons que le rendu soit ralis ou pas. En d'autre terme, doit-on afficher l'information ?
Ici, nous passons par une expression EL JSF, c'est--dire que nous consultons la proprit montrerHistorique. Si cette proprit renvoie la valeur true, alors le tableau est affich. Dans le cas contraire, nous ne voyons rien. La proprit montrerHistorique est elle-mme contrle par la mthode validerHistorique() qui permet d'inverser son tat.

Remarquez au passage que grce cet attribut rendered, vous pouvez par exemple rendre un bouton visible et l'autre pas. C'est ce que nous avons ralis ici. Nous aurions pu procder autrement, en proposant un seul bouton avec l'attribut value qui fait appel une mthode du bean qui renvoie le bon libell.

Petite vue d'ensemble des balises de JSF


Dans ce chapitre, nous allons recenser l'ensemble des balises visuelles de JSF, issue de la bibliothque HTML. Cette tude n'est pas exhaustive, mais je pense qu'il est bon de connatre les balises que nous avons notre disposition, afin d'tre mme de les utiliser ultrieurement. Par ailleurs, nous connaissons dj quelques unes d'entre elles. Je vais quand mme en reparler afin de prendre connaisance des attributs qui peuvent tre utiles. Pour une fois, je ne mets pas en oeuvre une application Web. Du moins, je ne m'intresse qu' la partie visuelle de la page JSP avec les balises JSF correspondantes. Aucun JavaBean n'est donc cr. Du coup, il ne sera pas possible de rcuprer les valeurs issues de l'attribut value de chacune de ces balises JSF. La plupart du temps, cet attribut sera vide, ou n'existera mme pas.

Rsultat sur le navigateur

Cette page Web, malgr son apparence, utilise la plupart des balises JSF. Nous allons par la suite dcrire chacune d'entre-elles. Voici d'ailleurs ci-dessous le code correspondant. .

Codage JSF de la page Web correspondante


1 <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> 2 <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> 3 4 <style type="text/css"> 5 .erreur { color: red; font-family: verdana; } 6 </style> 7 8 <f:view> 9 <html> 10 <body bgcolor="yellow"> 11 <h:form> 12 <h:messages layout="table" errorClass="erreur" /> 13 <h:panelGrid columns="4" style="font-weight: bold" cellpadding="3" width="100%" rules="all" frame="box"> 14 <f:verbatim>1</f:verbatim> 15 <h:outputText value="Loggin : " /> 16 <h:panelGroup> 17 <h:inputText value="" size="20" maxlength="20" required="true" id="saisie"/> 18 <f:verbatim><br /></f:verbatim> 19 <h:message for="saisie" errorClass="erreur"/> 20 </h:panelGroup> 21 <h:selectOneRadio value="" layout="pageDirection" border="1"> 22 <f:selectItem itemLabel="rouge" itemValue="r" /> 23 <f:selectItem itemLabel="vert" itemValue="v" /> 24 <f:selectItem itemLabel="bleu" itemValue="b" /> 25 </h:selectOneRadio> 26 <f:verbatim>2</f:verbatim> 27 <h:outputText value="Mot de passe : " /> 28 <h:inputSecret value="" size="20" maxlength="10" redisplay="true" required="true"/> 29 <h:panelGroup> 30 <h:selectBooleanCheckbox value="" /><h:outputText value="Contactez-moi" /> 31 </h:panelGroup> 32 <f:verbatim>3</f:verbatim> 33 <h:graphicImage value="chouette.jpg" style="border : groove"/> 34 <h:inputTextarea cols="15" rows="5" value="" /> 35 <h:selectManyCheckbox layout="pageDirection" border="1"> 36 <f:selectItem itemLabel="rouge" itemValue="r" /> 37 <f:selectItem itemLabel="vert" itemValue="v" /> 38 <f:selectItem itemLabel="bleu" itemValue="b" /> 39 </h:selectManyCheckbox> 40 <f:verbatim>4</f:verbatim> 41 <h:outputText value="Message : " /> 42 <h:inputText value="Un message" size="20" maxlength="20" readonly="true"/> 43 <h:outputFormat value="{0} un {1}"> 44 <f:param value="Voici"/> 45 <f:param value="message" /> 46 </h:outputFormat> 47 <f:verbatim>5</f:verbatim> 48 <h:commandButton action="valider" image="chouette.jpg" /> 49 <h:commandButton value="Effacer" type="reset" /> 50 <h:commandButton value="Valider" type="submit" disabled="true" />

51 <f:verbatim>6</f:verbatim> 52 <h:inputHidden value="Valeur secrte" /> 53 <h:commandLink value="Bienvenue" title="Retour la page d'accueil" /> 54 <h:selectOneListbox size="4"> 55 <f:selectItem itemLabel="rouge" itemValue="r" /> 56 <f:selectItem itemLabel="vert" itemValue="v" /> 57 <f:selectItem itemLabel="bleu" itemValue="b" /> 58 <f:selectItem itemLabel="jaune" itemValue="j" /> 59 <f:selectItem itemLabel="noir" itemValue="n" /> 60 </h:selectOneListbox> 61 <f:verbatim>7</f:verbatim> 62 <h:commandLink title="C'est chouette"> 63 <h:graphicImage value="chouette.jpg"/> 64 </h:commandLink> 65 <h:commandLink title="Page d'accueil"> 66 <f:verbatim><h2>Bienvenue</h2></f:verbatim> 67 </h:commandLink> 68 <h:selectManyListbox size="4"> 69 <f:selectItem itemLabel="rouge" itemValue="r" /> 70 <f:selectItem itemLabel="vert" itemValue="v" /> 71 <f:selectItem itemLabel="bleu" itemValue="b" /> 72 <f:selectItem itemLabel="jaune" itemValue="j" /> 73 <f:selectItem itemLabel="noir" itemValue="n" /> 74 </h:selectManyListbox> 75 <f:verbatim>8</f:verbatim> 76 <h:outputLink value="http://UnSite"> 77 <h:outputText value="Site extrieur" /> 78 </h:outputLink> 79 <f:verbatim /> 80 <h:selectOneMenu value=""> 81 <f:selectItem itemLabel="rouge" itemValue="r" /> 82 <f:selectItem itemLabel="vert" itemValue="v" /> 83 <f:selectItem itemLabel="bleu" itemValue="b" /> 84 </h:selectOneMenu > 85 </h:panelGrid> 86 </h:form> 87 </body> 88 </html> 89 </f:view>

1. <h:panelGrid> : Ligne 13 : Cette balise permet de placer tous les lments internes d'une certaine faon. Cela fait penser, dans le monde de Java, la gestion de disposition. Comme son nom l'indique, il s'agit d'une disposition sous forme de grille. Toutefois, le nombre de lignes dpend du contenu que nous plaons l'intrieur de ce panneau. Par contre, systmatiquement, vous devez indiquer le nombre de colonnes que va comporter votre panneau par le moyen de l'attribut columns. Nous avons dj pris connaissance avec les attributs qui grent les classes CSS, je n'en reparlerais donc pas ici. Vous pouvez rgler la largeur de votre panneau avec l'attribut width. Il est mme possible de choisir entre une taille en pixels et une dimension relative la largeur du navigateur en spcifiant la valeur en %. L'attribut rules permet de tracer des lignes entre chacune des cellules du panneau. Plusieurs valeurs sont possibles : rows - seules les lignes de sparation entre chaque ligne du panneau sont traces ; columns - seule les lignes de sparations des colonnes sont traces ; alls - toutes les lignes de sparation entre chaque cellule sont traces. L'attribut frame s'occupe galement d'un trac de lignes, mais cette fois-ci autour du panneau, frame veut d'ailleurs dire cadre. Egalement, plusieurs valeurs sont possibles : above - seule la ligne du dessus du panneau est trace ; below - seule la ligne du dessous du panneau est trace ; lhs - seule la ligne gauche du panneau est trace ; rhs - seule la ligne droite du panneau est trace ; hsides - les lignes horizontales du cadre du panneau sont traces ; vsides - les lignes verticales du cadre du panneau sont traces ; box et all : le cadre du panneau est trac en entier. Attention, pour que vous puissiez placer quelque chose, ne serait-ce qu'un texte, l'intrieur d'une cellule d'un panneau <h:panelGrid>, vous devez systmatiquement passer par une balise JSF. En ralit, chaque balise JSF permet de savoir combien il existe de cellules dans le panneau. 2. <h:panelGroup> : Lignes 16 et 29 : Quelque fois, il peut tre intressant de placer plusieurs informations l'intrieur d'une mme cellule. Il faut donc regrouper l'ensemble des lments (des balises JSF) l'intrieur d'une balise <h:panelGroup> qui sera finalement considre comme un seul lment, donc comme une seule cellule de la par du panneau <h:panelGrid>. 3. <f:verbatim> : Lignes 66 et 79 (plus quelques autres) : Tout ce qui est crit l'intrieur de cette balise n'est pas interprt comme un comportement JSF. Le contenu de cette balise sera plutt interprt comme du code HTML classique, ce qui peut tre intressant lorsque vous dsirez un formatage particulier. Ainsi, je peux utiliser des balises en-ttes comme la balise <h2>. Par ailleurs, puisque chaque cellule du panneau doit systmatiquement comporter une balise JSF, vous pouvez utiliser la syntaxe <f:verbatim />, lorsque vous dsirez avoir une cellule vide. 4. <h:outputFormat> : Lignes 43 46 : L'affichage de l'information se ralise trs souvent partir de la balise <h:outputText>. Nous pouvons ventuellement passer par la balise <h:outputFormat> qui permet de placer un texte avec un contenu paramtrable. Le ou les paramtres doivent alors tre spcifis au moyen des balises <f:param> l'intrieur de cette balise <h:outputFormat>. La valeur de chacun de ces paramtres est ensuite place dans l'ordre, suivant le nombre indiqu entre accolades. Ainsi, lorsque vous avez la syntaxe suivante "{0} un {1}" dans l'attribut value de <h:outputFormat>, la premire valeur du paramtre inscrite dans l'attribut value de la premire balise <f:param> se met la place de {0} et la valeur du deuxime paramtre la place de {1}. Du coup, si les paramtres sont respectivement "Voici" et "Message", le texte de sortie devient "Voici un message". 5. <h:graphicImage> : Lignes 33 et 63 : Pour afficher une image dans votre navigateur, il suffit de prendre cette balise <h:graphicImage>. Encore une fois, il suffit de renseigner l'attribut value pour indiquer l'image que vous souhaitez prendre. Ici, comme l'image se situe au mme niveau que la page JSP, vous spcifier juste le nom du fichier, sinon il peut tre souhaitable de prciser, en plus, le chemin suivre. 6. <h:commandButton> : Lignes 48 50 : Nous connaissons bien ces boutons aprs les avoir utiliser de nombreuses fois. Il existe toutefois des attributs que nous ne connaissons pas encore. Effectivement, dans certaines situations, les attributs type, image et disabled peuvent s'avrer intressants. Le premier attribut : type est le mme que celui que nous utilisons avec les balises du formulaire HTML classiques. Les valeurs sont "submit" et "reset". La deuxime valeur est souvant pratique lorsque nous dsirons effacer les champs des zones de saisie. La premire est mois utile, mais elle peut s'avrer intressante dans le cas o nous n'avons pas besoin de spcifier l'attribut action. Quant- lui, l'attribut image permet tout simplement d'utiliser une image comme bouton plutt que l'apparence classique. Pour le reste, le comportement demeure identique. Pour finir, dans certaines situations, il convient de dsativer momentanment un bouton, cela se ralise au travers de l'attribut disabled l'intrieur duquel vous placez une valeur boolenne, gnralement calcul partir d'une expression EL JSF. 7. <h:commandLink> : Lignes 62 67 : Cette balise ragit de la mme manire que la balise prcdente <h:commandButton>. La seule diffrence tient son apparence qui correspond au lien d'une page Web et fait donc rfrence la navigation. Toutefois, cette navigation, je le rappelle, est gre comme pour le bouton, par le fichier de configuration <faces-config.xml>. Nous pouvons grer l'affichage du lien un peu diffremment de ce qui est propos par dfaut. Ainsi, par exemple, nous pouvons tablir un lien partir d'une image. Egalement, nous pouvons faire en sorte que le lien soit afficher en plus grand. Pour cela, vous placez les balises qui vous intressent l'intrieur de cette balise <h:commandLink>. Remarquez la prsence de l'attribut title qui permet d'afficher une petite info-bulle lorsque le curseur se trouve au dessus du lien et qu'il a l'apparence d'une main. L'info-bulle s'affiche aprs une attente d'une seconde juste au dessous de la main. 8. <h:outputLink> : Lignes 76 78 : Encore une balise de lien. Attention, le comportement est cette fois-ci totalement diffrente de la prcdente. Effectivement, elle n'est jamais interprte par le contrleur FacesServlet. Il s'agit d'un lien direct, totalement similaire celui d'une page Web statique. Elle peut s'avrer utile dans le

cas o nous dsirons faire rfrence une page extrieure notre site. 9. <h:selectOneRadio> : Lignes 21 25 : Balise qui gre un ensemble de Radio-Boutons. Vous spcifiez vos choix au travers d'une liste propose par une suite de balises <f:selectItem> ou par la seule balise <f:selectItems>. Dans ce dernier cas, la liste est fabriqu dans le JavaBean correspondant, qui gre galement les traitements de cette page. Lorsque vous exprimez clairement la liste directement dans la page Web, vous prenez donc une liste de balise <f:selectItem>. Vous spcifier alors la valeur affiche au travers de l'attribut itemLabel et la valeur envoyer dans la requte au moyen de l'attribut itemValue. Le choix est ainsi rcup par l'intermdiaire de l'attribut value de <h:selectOneRadio>. Vous pouvez indiquer comment doit s'afficher la suite des Radio-Boutons par l'intermdiaire de l'attribut layout qui peut prendre deux valeurs ; soit "lineDirection" (mode par dfaut), soit "pageDirection" qui correspondent respectivement un affichage horizontal ou un affichage vertical. Si le coeur vous en dit, vous pouvez mme afficher des bordures par l'intermdiaire de l'attribut border. 10. <h:selectBooleanCheckBox> : Ligne 30 : Case cocher unique. Dans l'attribut value, vous spcifer la proprit du bean qui doit prendre en compte la validation ou pas. Vous placez ensuite l'intrieur de cette balise, le texte qui doit tre affich sur la page Web. 11. <h:selectManyCheckBox> : Ligne 35 39 : Une suite de cases cocher. Nous retrouvons la fois la mme dmarche et les mmes attributs que la balise <h:selectOneRadio>. 12. <h:selectOneListBox> : Lignes 54 60 : Une suite d'lements prendre en compte affiche sous la forme d'une liste. Un seul choix est possible parmi cette liste de valeur. Il est par contre possible de n'afficher qu'un certain nombre d'lments si la liste est trop longue par l'intermdiaire de l'attribut size. Sinon, le comportement et le rglage s'effectuent de la mme faon que pour la balise <h:selectOneRadio>. 13. <h:selectManyListBox> : Lignes 68 74 : Mme type de balise que la prcdente. Toutefois ici, vous avez plusieurs choix possibles parmi une liste de valeurs. 14. <h:selectOneMenu> : Lignes 80 84 : Menu droulant de type ComboBox que nous avons dj mis en oeuvre. Pas de commentaire particulier. 15. <h:inputText> : Ligne 17 et 42 : Certainement une des balises que nous avons beaucoup utilis. Malgr tout, il reste quelques dtails voir. Nous pouvons, par exemple, prciser une dimension grce l'attribut size. Nous pouvons galement contrler la taille maximum de la valeur saisie et empcher d'aller au dela au moyen de l'attribut maxlength. Dans un autre registre, nous pouvons utiliser une de ces balises comme un simple affichage, mais avec une apparence sympatique, en se servant de l'attribut readonly. Cela peut tre galement un moyen de dsactiver momentanment cette zone de saisie. Nous pouvons demander que la saisie soit imprativement ralise en positionnant l'attribut required. Du coup, remarquez la prsence de l'attribut id qui va tre utile pour afficher un message d'alerte dans le cas o l'utilisateur oubli de faire cette saisie. La balise spcialise <h:message> est sollicit dans ce cas l. Ce dernier sujet sera largement trait lors d'une tude ultrieure. 16. <h:inputSecret> : Ligne 28 : Il est possible de saisir des mots de passe au moyen de cette balise. A la session suivante, vous pouvez mme retrouver votre dernier mot de passe saisie en validant, tout simplement, l'attribut redisplay. 17. <h:inputHidden> : Ligne 52 : Comme pour le HTML, vous pouvez envoyer des valeurs de requte sans que cela soit visible sur la page Web. Cette balise permet de faire ce genre d'opration. 18. <h:messages> : Ligne 12 : Lorsque vous demandez imprativement certaines validations dans les zones de saisie, il peut s'avrer utile de prvenir l'utilisateur lorsque une ou plusieurs de ces contraintes ne sont pas ralises. Cette balise recense l'ensemble de toutes les erreurs possibles, soit sur une mme ligne, soit les unes en dessous des autres. Cet affichage particulier se rgle au moyen de l'attribut layout. Il est noter que l'affichage ne s'effectue que si l'oprateur n'a pas respecter les consignes. 19. <h:message> : Ligne 19 : Cette balise possde un comportement similaire la prcdente, mais elle est lie une seule contrainte spcifie par une des zones de saisie. La liaison se fait, d'une part dans la balise qui propose la contrainte, qui doit alors s'identifier au moyen de l'attribut id, et d'autre part en rglant l'attribut for de la balise <h:message> o l'on dsigne l'identificateur mis en oeuvre. Cette technique est vraiment gniale. La validation des donnes sera d'ailleurs largement traite dans une autre tude puisque c'est un domaine extrmement important.

Gestion de l'internationalisation - fichiers de messages


Lorsque nous mettons en oeuvre une application Web, il est souvent judicieux de centraliser l'ensemble du texte que va constituer vos diffrentes pages du site, dans une mme ressource, en dehors des pages Web. Ainsi, si vous dsirez, par exemple, revoir certains titres, il ne sera plus ncessaire de retoucher et de recompiler les pages Web, vous allez directement dans votre ressource. Grce cette technique, vous pouvez galement fabriquer plusieurs ressources qui correspondront chacune une langue du pays que vous dsirez mettre en oeuvre.

Mise en oeuvre des ressouces


Ceci dit, nous connaissons dj ce type de ressources. Il s'agit des fichiers de proprits qui portent donc l'extension "*.properties" et dont l'ossature interne est bien spcifique. Dans un premier temps, vous identifiez votre message, et la suite du signe "=", vous placez le texte correspondant. Vous procderez ainsi successivement pour tous les messages intgrer dans l'ensemble de vos pages.
messages_en.properties messages_fr.properties

# ressources en anglais titre=Calculation on basic operations titreOprande=A number of operands boutonOprande=To change the number listeOprande=List operands oprande=Operand boutonValider=To validate the operation boutonEffacer=To erase the operands rsultat=Result historique=History montrer=Show cacher=Hide

# ressources en franais titre=Calcul sur des oprations de base titreOprande=Nombre d'oprande boutonOprande=Changer le nombre listeOprande=Liste des oprandes oprande=Oprande boutonValider=Valider l'opration boutonEffacer=Effacer les oprandes rsultat=Rsultat historique=Historique montrer=Montrer cacher=Cacher

Le nom de vos fichiers ressources importent peu. Toutefois, il faut respecter une certaine syntaxe. Ainsi, si vous dcidez d'appeler l'ensemble de vos ressources messages, elles devront donc dbuter par ce nom en plaant ensuite un suffixe supplmentaire qui commence par le soulign ( _ ) suivi de l'indicatif du pays. Ainsi pour le franais, l'indicatif est "fr", pour l'anglais, l'indicatif est "en".

Exploitation des ressources sur la page Web


La balise <f:loadBundle> permet ensuite d'exploiter ces ressources dans votre page Web. Cette balise localise l'endroit o se situe l'ensemble de vos ressources grce l'attribut basename. Vous ne devez pas spcifier le pays dsir, mais uniquement le nom de la ressource globale (bien entendu si vous avez respect la syntaxe prconise plus haut). Ensuite, cette balise associe une variable l'ensemble des resources par l'intermdiaire de l'attribut var.
<f:loadBundle basename="ressources.messages" var="msgs" /> Ensuite, il suffit d'utiliser les expressions EL JSF pour rcuprer l'lment qui vous intresse dans la ressource. Ainsi, si vous dsirez placer votre titre, voici ce que vous devez crire : <h2><h:outputText value="#{msgs.titre}" /></h2> Suivant le choix de la langue dsire par l'utilisateur, soit nous avons Calcul sur des oprations de base soit Calculation on basic operations

Comment l'oprateur choisi sa langue ?


En ralit, cela se fait automatiquement suivant le pays o vous vous situez, puisque l'ordinateur est configur en consquence. En effet, le navigateur est lui-mme rgl suivant ce qui est indiqu par le systme d'exploitation. Il est quand mme bon d'aider le navigateur dans sa dmarche, et de prciser que notre application Web possde plusieurs versions linguistiques. Nous rglons et plaons cette information dans le fichier de configuration <faces-config.xml>.
<faces-config xmlns="http://java.sun.com/JSF/Configuration"> <application> <locale-config> <default-locale>fr</default-locale> <supported-locale>en</supported-locale> </locale-config> </application>

... </faces-config>

Pour cela, dans la balise <application> qui reprsente l'application Web, vous placez la balise <config-locale>. A l'intrieur de cette dernire, vous dfinissez quelle est la langue par dfaut l'aide de la balise <default-locale>. Ensuite, toujours dans la balise <config-locale>, vous prcisez la liste des langues prises en compte par l'application Web, par l'intermdiaires d'une suite de balises <supported-locale>.

Rglage du navigateur pour imposer une langue


Vous avez ci-dessous la procdure suivre pour rgler votre navigateur de telle sorte que vous puissiez choisir librement la langue que vous dsirez voir apparatre sur votre page d'accueil.
D'une part avec Firefox :

D'autre part avec Internet Explorer :

Spcifier directement dans la page Web la langue que vous dsirez


Vous pouvez imposer directement dans la page Web, la langue que vous dsirez prendre momentanment. Cette technique s'labore partir de la balise <f:view>, et vous spcifiez ensuite votre langue par l'intermdiaire de l'attribut locale. Voici un exemple :
<f:view locale="fr">

il n'est plus ncessaire, dans ce cas l, de rgler le fichier de configuration. .

L'oprateur peut choisir sa langue dans la page Web


Nous pouvons aller encore plus loin dans notre dmarche et faire en sorte que la valeur de l'attribut locale de la balise <f:view> soit variable et interprte par une expression EL JSF. Il suffit alors dans la page Web de proposer des icnes ou des liens qui permettent l'oprateur de choisir sa langue. Il faut que le bean qui gre le traitement de la page Web propose des proprits en consquence.
Voici ci-dessous le code complet du bean calcul.Opration qui prend en compte la gestion des langues, ainsi que la page d'accueil du site calcul.jsp : calcul.Opration

package calcul; import java.util.ArrayList; import javax.faces.model.SelectItem; public class Opration { private char type = '+'; private int rsultat; private Oprandes oprandes; private ArrayList<String> historique = new ArrayList<String>(); private boolean montrerHistorique = false; private SelectItem[] oprations = { new SelectItem('+', "Addition"), new SelectItem('-', "Soustraction"), new SelectItem('*', "Multiplication") }; private String langue = "fr"; public String getLangue() { return langue; } public void franais() { langue = "fr"; oprations = new SelectItem[] { new SelectItem('+', "Addition"), new SelectItem('-', "Soustraction"), new SelectItem('*', "Multiplication") }; }

public void anglais() { langue = "en"; oprations = new SelectItem[] { new SelectItem('+', "Addition"), new SelectItem('-', "Substraction"), new SelectItem('*', "Multiplication") }; } public SelectItem[] getOprations() { return oprations; } public ArrayList<String> getHistorique() { return historique; } public boolean isMontrerHistorique() { return montrerHistorique; } public void validerHistorique() { montrerHistorique = !montrerHistorique; } public Oprandes getOprandes() { return oprandes; } public void setOprandes(Oprandes oprandes) { this.oprandes = oprandes; } public void setType(char type) { this.type = type; } public char getType() { return type; } private void calcul() { switch (type) { case '+' : rsultat = 0; for (int i=0; i<oprandes.getValeur(); i++) rsultat+=oprandes.getOprande(i); break; case '-' : rsultat = oprandes.getOprande(0); for (int i=1; i<oprandes.getValeur(); i++) rsultat-=oprandes.getOprande(i); break; case '*' : rsultat = 1; for (int i=0; i<oprandes.getValeur(); i++) rsultat*=oprandes.getOprande(i); break; default : rsultat = 0; } } public String getRsultat() { calcul(); if (oprandes.getOprande(0)==0) return langue.equals("fr") ? "Aucun" : "None"; String sortie = oprandes.getOprande(0)+" "+type+" "; for (int i=1; i<oprandes.getValeur()-1; i++) sortie = sortie + oprandes.getOprande(i)+" "+type+" "; sortie = sortie+oprandes.getOprande(oprandes.getValeur()-1)+" = "+rsultat; if (!historique.contains(sortie)) historique.add(sortie); return sortie; } }

calcul.jsp

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <style type="text/css"> .un {background-color: #00CC00; } .deux {background-color: #009900; } .gnral {background-color: #006633; font-weight: bold; } .gras {font-weight: bold; } h2, h3 { background-color: #006633; padding: 5px; border : groove; } body {font-family: verdana, Arial; color: yellow; background-color: green; } </style> <f:view locale="#{opration.langue}"> <f:loadBundle basename="ressources.messages" var="msgs" /> <html> <body> <h:form> <h:commandButton action="#{opration.franais}" image="francais.png" /> <h:commandButton action="#{opration.anglais}" image="anglais.png" /> <h2><h:outputText value="#{msgs.titre}" /></h2> <h3> <h:outputText value="#{msgs.titreOprande} : " /> <h:selectOneMenu value="#{opration.oprandes.valeur}"> <f:selectItems value="#{opration.oprandes.choix}" />

</h:selectOneMenu> <h:commandButton value="#{msgs.boutonOprande}" action="changer"/> </h3> </h:form> <h:form> <h:dataTable value="#{opration.oprandes.liste}" var="oprande" cellpadding="3" styleClass="gnral" rowClasses="un, deux" > <f:facet name="header"><h:outputText value="#{msgs.listeOprande}" /></f:facet> <h:column> <h:outputText value="#{msgs.oprande} : #{oprande.numro}" /> </h:column> <h:column> <h:inputText value="#{oprande.valeur}" size="30" maxlength="10" /> </h:column> <f:facet name="footer"> <h:selectOneRadio value="#{opration.type}" styleClass="gras" > <f:selectItems value="#{opration.oprations}"/> </h:selectOneRadio> </f:facet> </h:dataTable> <p> <h:commandButton value="#{msgs.boutonValider}" type="submit" /> <h:commandButton action="effacer" value="#{msgs.boutonEffacer}" type="reset"/> </p> </h:form> <h2><h:outputText value="#{msgs.rsultat} : #{opration.rsultat}" /></h2> <h3> <h:form> <h:outputText value="#{msgs.historique}" /> <h:commandButton value="#{msgs.montrer}" action="#{opration.validerHistorique}" rendered="#{not opration.montrerHistorique}"/> <h:commandButton value="#{msgs.cacher}" action="#{opration.validerHistorique}" rendered="# {opration.montrerHistorique}"/> </h:form> <h:dataTable value="#{opration.historique}" var="historique" rendered="#{opration.montrerHistorique} "> <h:column> <h:outputText value="#{historique}" styleClass="gras"/> </h:column> </h:dataTable> </h3> </body> </html> </f:view>

Nous remarquons que dans le bean, nous avons d grer galement la langue puisque certains textes sont issus de ce composant. Il faut viter au maximum ce genre d'oprations. Normalement, la partie visuelle du site doit tre gre essentiellement par la page JSP elle-mme, et non par le bean correspondant. Ceci dit, il se trouve des cas o nous ne pouvont pas faire autrement.

Conclusion
Nous avons termin cette premire partie. Je dis bien cette premire partie puisqu'il y a encore pas mal de chose dcouvrir. Rien qu'avec les connaissances que nous venons d'apprendre, je dirais que cette technologie JSF est vraiment intressante. La mise en oeuvre est simple, rapide et surtout trs structure, en permettant cette foisci, une sparation trs nette entre la partie visuelle, le traitement de l'information, et la configuration de l'ensemble des intervenants. Il nous reste voir encore pas mal de choses, nottamment la validation des saisies ralises par l'oprateur, les conversions des donnes ventuelles, la fabrication de nouveaux composants, etc.
Dans l'tude suivante, vous allez donc dcouvrir des aspects de JSF qui font que cette technologie est de tout premier ordre.

You might also like