52
JavaServer Faces - JSF Chapitres traités Introduction à JSF Pour afficher graphiquement les informations provenant du serveur, nous avons besoin d'une interface utilisateur. Les applications utilisant les interfaces pour interagir avec l'utilisateur sont de différents types : applications de bureau, applications web s'exécutant dans un navigateur ou applications mobiles sur un terminal portable. Nous nous intéressons ici sur les interfaces web. Initialement, le World Wide Web était un moyen de partager des documents écrits en HTML. Le protocole HTTP a été conçu pour véhiculer ces documents, qui étaient à l'origine essentiellement statiques (leur contenu n'évoluait pas beaucoup au cours du temps). 1. Les pages statiques sont composées de HTML pur contenant éventuellement des graphiques eux aussi statiques (JPG, PNG, par exemple). 2. Les pages dynamiques sont en revanche composées en temps réel (à la volée) à partir de données calculées à partir d'informations fournies par l'utilisateur. Pour créer un contenu dynamique, il faut analyser les requêtes HTTP, comprendre leur signification et créer des réponses dans un format que le navigateur saura traiter. Les servlets simplifie le processus en fournissant une vue orientée objet du monde HTTP (HttpRequest, HttpResponse, etc.). Cependant, le modèle des servlets était de trop bas niveau et c'est la raison pour laquelle, les pages JSP (JavaServer Pages) ont ensuite pris le relais pour simplifier la création des pages web dynamiques. En coulisse, une JSP est une servlet, sauf qu'elle est écrite essentiellement en HTML - avec un peu de Java pour effectuer les traitements. Ceci dit, les servlets peuvent toujours être utiles dans le cas de traitements spécifiques qui ne consistent pas à créer, pour la réponse au navigateur, de page web en format HTML. Nous pourrions, par exemple, fabriquer une vignette correspondant à une photo grand format archivée sur le serveur. JSF (JavaServer Faces , ou simplement Faces ) a été créé en réponse à certaines limitations de JSP et utilise un autre modèle consistant à porter des composants graphiques vers le Web. Inspiré par le modèle Swing, JSF permet aux développeurs de penser en termes de composants, d'événements, de beans gérés et de leur interactions plutôt qu'en termes de requêtes, de réponses et de langages à marqueurs. Son but est de faciliter et d'accélérer le développement des applications web en fournissant des composants graphiques (comme des zones de texte, les listes, les onglets, les grilles, etc.) afin d'adopter une approche RAD (Rapid Application Development). Introduction à JSF Les applications JSF sont des applications web classiques qui interceptent HTTP via la servlet Faces et produisent du HTML. En coulisse, cette architecture permet de greffer n'importe quel langage de déclaration de page (PDL), de l'afficher sur des dispositifs différents (navigateur web, terminaux mobiles, etc.) et de créer des pages au moyen d'événements, d'écouteurs et de composants, comme en Swing. JSF fournit un ensemble de widgets standard (boutons, liens hypertextes, cases à cocher, zone de saisie, tableaux dynamiques, etc.) et facilite son extension par l'ajout de composants tiers. La figure ci-dessous représente les parties les plus importantes de l'architecture JSF qui la rendent aussi riche et aussi souple :

08 - JavaServer Faces 2.0

Embed Size (px)

Citation preview

Page 1: 08 - JavaServer Faces 2.0

JavaServer Faces - JSF

Chapitres traités Introduction à JSF

Pour afficher graphiquement les informations provenant du serveur, nous avons besoin d'une interface utilisateur. Lesapplications utilisant les interfaces pour interagir avec l'utilisateur sont de différents types : applications de bureau, applicationsweb s'exécutant dans un navigateur ou applications mobiles sur un terminal portable. Nous nous intéressons ici sur lesinterfaces web.

Initialement, le World Wide Web était un moyen de partager des documents écrits en HTML. Le protocole HTTP a été conçu pourvéhiculer ces documents, qui étaient à l'origine essentiellement statiques (leur contenu n'évoluait pas beaucoup au cours du

temps).

1. Les pages statiques sont composées de HTML pur contenant éventuellement des graphiques eux aussi statiques (JPG, PNG, par exemple).

2. Les pages dynamiques sont en revanche composées en temps réel (à la volée) à partir de données calculées à partir d'informations fournies par l'utilisateur.

Pour créer un contenu dynamique, il faut analyser les requêtes HTTP, comprendre leur signification et créer des réponses dans un format que le navigateur sauratraiter. Les servlets simplifie le processus en fournissant une vue orientée objet du monde HTTP (HttpRequest, HttpResponse, etc.).

Cependant, le modèle des servlets était de trop bas niveau et c'est la raison pour laquelle, les pages JSP (JavaServer Pages) ont ensuite pris le relais poursimplifier la création des pages web dynamiques. En coulisse, une JSP est une servlet, sauf qu'elle est écrite essentiellement en HTML - avec un peu de Javapour effectuer les traitements.

Ceci dit, les servlets peuvent toujours être utiles dans le cas de traitements spécifiques qui ne consistent pas à créer, pour la réponse au navigateur, de page weben format HTML. Nous pourrions, par exemple, fabriquer une vignette correspondant à une photo grand format archivée sur le serveur.

JSF (JavaServer Faces, ou simplement Faces) a été créé en réponse à certaines limitations de JSP et utilise un autre modèle consistant à porter des composantsgraphiques vers le Web. Inspiré par le modèle Swing, JSF permet aux développeurs de penser en termes de composants, d'événements, de beans gérés et deleur interactions plutôt qu'en termes de requêtes, de réponses et de langages à marqueurs.

Son but est de faciliter et d'accélérer le développement des applications web en fournissant des composants graphiques (comme des zones de texte, les listes, lesonglets, les grilles, etc.) afin d'adopter une approche RAD (Rapid Application Development).

Introduction à JSF

Les applications JSF sont des applications web classiques qui interceptent HTTP via la servlet Faces et produisent du HTML.

En coulisse, cette architecture permet de greffer n'importe quel langage de déclaration de page (PDL), de l'afficher sur des dispositifs différents (navigateur web,terminaux mobiles, etc.) et de créer des pages au moyen d'événements, d'écouteurs et de composants, comme en Swing.

JSF fournit un ensemble de widgets standard (boutons, liens hypertextes, cases à cocher, zone de saisie, tableaux dynamiques, etc.) et facilite son extension parl'ajout de composants tiers.

La figure ci-dessous représente les parties les plus importantes de l'architecture JSF qui la rendent aussi riche et aussi souple :

Page 2: 08 - JavaServer Faces 2.0

1. FacesServlet : est la servlet principale de l'application qui sert de contrôleur. JSF utilise le patron de conception MVC (Modèle-Vue-Contrôleur).MVC permet de découpler la vue (la page) et le modèle (le traitement des données affichées dans la vue). Le contrôleur prend en charge les actionsde l'utilisateur qui pourraient impliquer des modifications dans le modèle et dans les vues. Avec JSF, ce contrôleur est la servlet FacesServlet.Toutes les requêtes de l'utilisateur passent sytématiquement par elle, qui les examine et appelle les différentes actions correspondantes du modèleen utilisant les beans gérés. Il est possible de configurer le comportement de cette servlet au travers d'annotations spécifiques (sur les beans gérés,les convertisseurs, les composants, les moteurs de rendu et les validateurs).

2. Pages et composants : Le framework JSF doit envoyer une page sur le dispositif de sortie du client (un navigateur, pas exemple) et exige donc unetechnologie d'affichage appelée PDL. Dans sa version la plus récente, JSF utilise plutôt les Facelets. Facelets est formée d'une arborescence decomposants (également appelés widgets ou contrôles) fournissant des fonctionnalités spécifiques pour interagir avec l'utilisateur (champ de saisie,boutons, liste, etc.).

JSF dispose d'un ensemble standard de composants (graphiques ou sans apparences visuelles) et permet de créer également facilementles vôtres (composants personnalisés). Pour gérer cette arborescence, une page passe par un cycle de vie complexe (initialisation,événements, affichage, etc.).

Le code ci-dessous correspond à la page web de conversion vue plus haut et représente une page Facelets en XHTML qui utilise lesmarqueurs xmln:h et xmlns:f pour afficher un formulaire avec les deux zones de saisies (€uro et Franc) et un bouton (pour la conversion).Cette page est composée de plusieurs composants JSF : certains n'ont pas d'apparence visuelle, comme ceux qui déclare l'en-tête<h:head>, le corps <h:body> ou le formulaire <h:form>. D'autres ont une représentation graphique et affichent un texte en sortie<h:outputText>, une zone de saisie <h:inputText> ou un bouton <h:commandButton>. Vous remarquez que nous pouvons égalementutiliser des marqueurs HTML purs : <html>, <h3>, <hr />.

Page 3: 08 - JavaServer Faces 2.0

3. Moteurs de rendu : JSF reconnait deux modèles de programmation pour afficher les composants : l'implémentation directe et l'implémentationdéléguée. Avec le modèle direct, les composants doivent eux-même s'encoder vers une représentation graphique et réciproquement. Avec le modedélégué, ces opérations sont confiées à un moteur de rendu, ce qui permet aux composants d'être indépendants de la technologie d'affichage(navigateur, terminal mobile, etc.) et donc d'avoir plusieurs représentations graphiques possibles.

Un moteur de rendu s'occupe d'afficher un composant et de traduire la saisie d'un utilisateur en valeur de composants. Nous pouvonsdonc le considérer comme un traducteur placé entre le client et le serveur : il décode la requête de l'uilisateur pour initialiser les valeursdu composant et encode la réponse pour créer une représentation du composant que le client pourra comprendre et afficher.

4. Convertisseurs et validateurs : Lorsque la page est affichée, l'utilisateur peut s'en servir pour entrer des données. Comme il n'y a pas de contraintessur les types, un moteur de rendu ne peut pas prévoir l'affichage de l'objet. Voilà pourquoi les convertisseurs existent : ils traduisent un objet(Integer, Date, Enum, Boolean, etc.) en chaîne de caractères afin qu'il puisse s'afficher (protocole HTTP est un protocole uniquement textuel) et,inversement, construisent un objet à partir d'une chaîne qui a été saisie. JSF fournit un ensemble de convertisseurs pour les types classiques dans lapaquetage javax.faces.convert, mais vous pouvez développer les vôtres ou ajouter des types provenant de tierces parties.

Parfois, les données doivent également être validées avant d'être traitées par le back-end : c'est le rôle des validateurs ; nous pouvons ainsiassocier un ou plusieurs validateurs à un composant unique afin de garantir que les données saisies sont correctes. JSF fournit quelquesvalidateurs (LengthValidator, RegexValidator, etc.) et vous permet d'en créer d'autres en utilisant vos propres classes annotées. En casd'erreur de conversion ou de validation, un message est envoyé dans la réponse à afficher.

5. Beans gérés et navigation : Tous les concepts que nous venons de présenter - qu'est-ce qu'une page, qu'est-ce qu'un composant, comment sont-ilaffichés convertis et validés - sont liés à une page unique, mais les applications web sont généralement formées de plusieurs pages et doiventréaliser un traitement métier (en appelant une couche EJB, par exemple). Le passage d'une page à une autre, l'invocation d'EJB et lasynchronisation des données avec les composants sont pris en charge par les beans gérés.

L'exemple ci-dessous visualise un projet d'entreprise de gestion complète d'une bibliothèque. Nous découvrons ainsi toute la partie métier au traversd'un certain nombre d'EJB session, comme GérerAuteurs, GérerLivres, etc. qui s'occupent également de la persistance à l'aide d'entités adaptées. Lacouche présentation est traitée au moyen de JSF où nous découvrons toute la structure interne. Tout d'abord la servlet FacesServlet qui joue le rôle decontrôleur et qui prend en compte toute les requêtes venant du client déporté. Ensuite, la partie visuelle est représentée par les différentes pages webcomme auteurs.xhtml, livres.xhtml, etc. Enfin, ce qui permet de mettre en relation la logique métier avec cette partie visuelle, dans ce que nousappelons le back-end, nous trouvons les beans gérés comme GestionAuteurs, GestionLivres, etc.

Page 4: 08 - JavaServer Faces 2.0

Vous remarquez qu'un bean géré est systématiquement associé à une page xhtml. Ce n'est pas absolument indispensable. Nous pouvons tout aussibien avoir plusieurs beans pour une même page et inversement, un seul bean géré peut s'occuper de plusieurs pages.

5. Un bean géré est classe Java spécialisée qui synchronise les valeurs avec les composants, traite la logique métier et gère la navigation entre lespages. Nous associons un composant à une propriété ou à une action spécifique d'un bean géré en utilisant EL (Expression Language) :

Ainsi, par exemple, la première zone de saisie lie directement la valeur du champ à la propriété euro. Cette valeur est alorsautomatiquement synchronisée avec la propriété du bean géré.

Page 5: 08 - JavaServer Faces 2.0

Un bean géré peut également traiter des événements et associer un bouton de soumission à une action spécifique. Ainsi, lorsque nouscliquons sur la bouton de conversion, celui-ci déclenchera un événement sur le bean géré, qui exécutera alors une méthode écouteur - ici,euroFranc().

Le bean géré est une classe Java annotée par @ManagedBean et possède deux propriétés, euro et franc, qui sont synchronisées avec lesvaleurs des composants de la page. La méthode euroFranc() de ce bean managé réalise le traitement de la conversion.

6. Support d'Ajax : Une application web doit fournir une interface riche et rapide. Cette réactivité peut être obtenue en ne modifiant que de petitesparties de la page de façon asynchrone, sans que la page ne soit rechargée entièrement, et c'est exactement pour cela qu'Ajax a été conçu.

Par exemple, sur notre application web de conversion, nous pourrions souhaiter que seule la zone des francs soit changée lors de lasoumission de la requête de conversion à partir des €uros :

Voici le code correspondant :

Page 6: 08 - JavaServer Faces 2.0

Cycle de vie

Une page JSF est une arborescence de composants avec un cycle de vie spécifique qu'il faut bien avoir compris pour savoir à quel moment les composants sontvalidés ou quand le modèle est mis à jour.

1. Un clic sur un bouton provoque l'envoi d'une requête du navigateur vers le serveur et cette requête est traduite en événement qui peut être traité parl'application sur le serveur.

2. Toutes les données saisie par l'utilisateur passent par une étape de validation avant que le modèle soit mis à jour et que du code métier soit appelé.

3. JSF se charge alors de vérifier que chaque composant graphique (composants parent et fils) est correctement rendu par le navigateur.

Le cycle de vie de JSF se divise en six phases :

1. Restauration de la vue : JSF trouve la vue cible et lui applique les entrées de l'utilisateur. S'il s'agit de la première visite, JSF crée la vue comme uncomposant UIViewRoot (racine de l'arborescence de composants, qui constitue une page particulière). Pour les requêtes suivantes, il récupèrel'UIViewRoot précédemment sauvegardée pour traiter la requête HTTP courante.

2. Application des valeurs de la requête : Les valeurs fournies avec la requête (champ de saisie, d'un formulaire, valeurs des cookies ou à partir des en-têtes HTTP) sont appliquées aux différents composants de la page. Seuls les composants UI (de la page) modifient leur état, non les objets métiersqui forment le modèle.

3. Validations : Lorsque tous les composants UI ont reçu leurs valeurs, JSF traverse l'arborescence de composants et demande à chacun d'eux des'assurer que la valeur qui leur a été soumise est correcte. Si la conversion et la validation réussissent pour tous les composants, le cycle de viepasse à la phase suivante. Sinon il passe à la phase de Rendu de la réponse avec les messages d'erreur de validation et de conversion appropriés.

4. Modification des valeurs du modèle : Lorsque toutes les valeurs des composants ont été affectées et validées, les beans gérés qui leur sont associéspeuvent être mis à jour.

5. Appel de l'application : Nous pouvons maintenant exécuter la logique métier. Les actions qui ont été déclenchées seront exécutées sur le bean géré.La navigation entre en jeu car c'est la valeur qu'elle renvoie qui déterminera la réponse.

6. Rendu de la réponse : Le but principal de cette phase consiste à renvoyer la réponse à l'utilisateur. Son but secondaire est de sauvegarder l'état de lavue pour pouvoir la restaurer dans la phase de restauration si l'utilisateur redemande la vue.

Le thread d'exécution d'un cycle requête/réponse peut passer ou non par chacune de ces étapes en fonction de la requête et de ce qui se passe aucours de son traitement : en cas d'erreur notamment, le flux d'exécution passe directement à la phase de Rendu de la réponse. Quatre de ces étapespeuvent produire des messages d'erreur : Application des valeurs de la requête (2), Validation (3), Modification des valeurs du modèle (4) et Appel del'application (5). Avec ou sans erreur, la phase de Rendu de la réponse (6) renvoie toujours le résultat à l'utilisateur.

Petit résumé

Nous venons de le voir, créer des pages contenant des composants graphiques ne suffit pas : ces pages doivent interagir avec un back-end (un processus en arrièreplan), il faut pouvoir naviguer entre les pages et valider et convertir les données. JSF est une spécification très riche : les beans gérés permettent d'invoquer la couchemétier, de naviguer dans votre application, et, grâce à un ensemble de classes, vous pouvez convertir les valeurs des composants ou les valider pour qu'ilscorrespondent aux règles métiers. Grâces aux annotations, le développement de convertisseurs et de validateurs personnalisés est désormais chose facile.

Page 7: 08 - JavaServer Faces 2.0

JSF 2.0 apporte la simplicité et la richesse aux interfaces utilisateurs dynamiques. Il reconnait nativement Ajax en fournissant une bibliothèque JavaSriptpermettant d'effectuer des appels asynchrones vers le serveur et de rafraîchir une page par parties.

La création d'interfaces utilisateurs, le contrôle de la navigation dans les appels synchrones ou asynchrones de la logique métier sont possibles parce que JSFutilise le modèle de conception MVC (Modèle-Vue-Contrôleur). Chaque partie est donc isolée des autres, ce qui permet de modifier l'interface utilisateur sansconséquence sur la logique métier et vice versa.

Le modèle MVC et architecture JSF

JSF encourage la séparation des problèmes en utilisant une des variantes du modèle MVC. Ce dernier est un modèle d'architecture permettant d'isoler la logique métierde l'interface utilisateur car la première ne se mélange pas bien avec la seconde.

Avec PHP ou JSP, le mélange de la logique métier et de l'interface utilisateur produit des applications plus difficiles à maintenir et qui supportent moins bien lamontée en charge. En effet, une page JSP qui contient à la fois du code Java et des instructions SQL au millieu des balises HTML : bien que ce soittechniquement correct, imaginez la difficulté de maintenir une telle page... Elle mélange deux types de développement différents (celui du concepteur graphiqueet celui de programmeur métier) et pourrait finir par utiliser bien plus d'API encore (accès aux bases de données, appels d'EJB, etc.), par gérer les exceptions oupar effectuer des traitements métiers complexes.

Avec MVC, l'application utilise un couplage faible, ce qui facilite la modification de son aspect visuel ou des règles métiers sous-jacentes sans pour autantaffecter l'autre composante. Par exemple, nous avons travailler sur deux vues différentes (conversion.xhtml), avec ou sans prise en compte d'une action Ajax,sans que nous ayons modifier quoi que ce soit sur le bean géré. Revoici d'ailleurs les deux alternatives :

Comme le montre la figure ci-dessous, la partie modèle de MVC représente les données (et leurs différents traitements) de l'applications ; la vue correspond àl'interface utilisateur et le contrôleur gère la communication entre les deux :

Page 8: 08 - JavaServer Faces 2.0

1. Le modèle est représenté par le contenu, qui est quelque fois stocké dans une base de données et affiché dans la vue ; il ne se soucie pas de l'aspectque verra l'utilisateur. Avec JSF, il peut être formé de backing beans, d'appels EJB, d'entités JPA, etc.

2. La vue JSF est la véritable page XHTML (XHTML est réservée aux interfaces web, mais il pourrait s'agir d'autre type de vue, comme WML pour lesdispositifs mobiles). Une vue fournit une représentation graphique d'un modèle et un modèle peut avoir plusieurs vues pour prévoir un affichagesous forme de formulaire ou sous forme de liste, par exemple.

3. Lorsqu'un utilisateur manipule une vue, celle-ci informe un contrôleur des modifications souhaitées. Ce contrôleur se charge alors de rassembler,convertir et valider les données, appelle la logique métier puis produit le contenu en XHTML. Avec JSF, le contrôleur est un objet FacesServlet.

Cette servlet est déjà fabriquée. Nous n'avons aucun code à écrire en son sein. Nous pouvons toutefois influencer son comportement aumoyen d'annotations spécifiques, comme par exemple @ManagedBean. Dans ce cas là, la servlet s'occupera alors de générer un nouvelobjet correspondant à la classe du bean géré avec une durée de vie adaptée.

Architecture JSF au travers de l'exemple complet de conversion

Nous allons valider tous les différents concepts que nous venons de découvrir durant tout le début de cette étude au travers du projet de conversion sur lequel nousavons également travaillé. Nous en profiterons pour découvrir l'architecture d'une application web traité avec JSF et de voir comment se traite la gestion des resourcesainsi que le descripteur de déploiement (web.xml).

Page 9: 08 - JavaServer Faces 2.0

Nous allons maintenant suivre toute la procédure pour réaliser ce projet au travers de l'environnement Netbeans. Ce projet, je le rappelle, permet de réaliser laconversion monétaire des €uros vers les francs (uniquement dans ce sens).

Mise en place du projet

1. Création d'un projet de type application Web :

2. Nom du projet Francs :

3. Choix du serveur d'applications et des réglages de base :

Page 10: 08 - JavaServer Faces 2.0

4. Prise en compte de la technologie JSF pour cette application web :

Feuille de style CSS et gestion des ressources

La plupart des composants ont besoin de ressources externes pour s'afficher correctement : <h:graphicImage> a besoin d'une image, <h:commandButton>peut également afficher une image pour représenter le bouton, <h:outputScript> référence un fichier JavaScript et surtout les composants peuvent égalementappliquer des styles CSS (Sujet qui m'intéresse ici).

Avec JSF, une ressource est un élément statique qui peut être transmis aux éléments afin d'être affiché (images) ou traité (CSS) par le navigateur. JSF2.0 permet d'assembler directement les ressources dans un fichier jar séparé, avec un numéro de version et une locale, et de les placer à la racine del'application web, sous le répertoire suivant :

resources/<identifiant_ressource>ouMETA-INF/resources/<identifiant_ressource>

<identifiant_ressource> est formé de plusieurs sous-répertoire indiqués sous la forme :

[locale/ ] [nomBibliothèque/ ] nomRessource [ /versionRessource]

Tous les éléments entre crochets sont facultatifs. La locale est le code du langage, suivi éventuellement d'un code de pays (en, en_US, pt,pt_BR). Comme l'indique cette syntaxe, vous pouvez ajouter un numéro de version à la bibliothèque ou à la ressource elle-même.

Voici quelques exemples :

resources/principal.cssresources/css/principal.css

Après toutes ces considérations techniques, nous allons maintenant élaborer l'ensemble de nos styles de la page dans une feuille séparée. La suitenous montre la procédure à suivre :

1. Netbeans permet de prendre en compte les feuilles de styles :

Page 11: 08 - JavaServer Faces 2.0

2. Le plus important et de bien choisir l'emplacement, avec bien sûr le nom de votre feuille de style :

3. Voici le résultat avec la prise en compte de l'emplacement :

principal.css

root { display: block;}

body { background-color: orange; color: maroon;

Page 12: 08 - JavaServer Faces 2.0

font-family: Verdana,Arial,Helvetica,sans-serif; text-align: center;}

.saisie, .resultat { background-color: yellow; text-align: right; font-weight: bold; color: green;}

.resultat { color: red;}

.erreur { color: black;}

Le fait de choisir une feuille de style plutôt que d'intégrer les styles directement dans la vue me paraît être une attitude de bon développeur. Il fauttoujours séparer la mise en forme de votre page web par rapport à son ossature, surtout si vous devez en construire plusieurs. Toutes les pagesrespecterons ainsi la même charte graphique. A tout moment, vous pouvez changer cette charte sans remettre en cause les structures dedéveloppement de vos différentes vues. Pour finir, lorsque vous prenez une feuille de style à part entière, vous bénéficiez d'un éditeur CSS intégré, cequi n'est pas négligeable.

Le contrôleur FacesServlet et le descripteur de déploiement web.xml

Lorsqu'un utilisateur manipule une vue, celle-ci informe un contrôleur des modifications souhaitées. Ce contrôleur se charge alors de rassembler, convertir etvalider les données, appelle la logique métier puis produit le contenu en XHTML. Avec JSF, le contrôleur est un objet FacesServlet.

FacesServlet est une implémentation de javax.servlet.Servlet qui sert de contrôleur central par lequel passent toutes les requêtes. Comme le montre lafigure ci-dessous, la survenue d'un événement, lorsque l'utilisateur clique sur un bouton, par exemple, provoque l'envoi d'une notification au serveurvia HTTP ; celle-ci est interceptée par javax.faces.webapp.FacesServlet, qui examine la requête et exécute différentes actions sur le modèle à l'aide desbeans gérés.

En coulissse, la FacesServlet prend les requêtes entrantes et donne le contrôle à l'objet javax.faces.lifecycle.LifeCycle. A l'aide d'une méthode defabrique, elle crée un objet javax.faces.contextFacesContext qui contient et traite les informations d'état de chaque requête. L'objet Lifecycle utilise ceFacesContext en six étapes (décrites au chapitre précédent) avant de produire la réponse.

Les requêtes qui doivent être traitées par la FacesServlet sont redirigées à l'aide d'une association de servlet dans le descripteur de déploiement(web.xml) qui se situe dans le répertoire WEB-INF. Les pages web, les beans gérés, les convertisseurs, etc. doivent être assemblés à l'aide de ce fichier.

Page 13: 08 - JavaServer Faces 2.0

1. Ce fichier définit la javax.faces.webapp.FacesServlet en lui donnant un nom (Faces Servlet, ici) et une association. Dans cet exemple, toutes lesrequêtes dont le préfixe est faces/ sont associées pour être gérées par la servlet - toute requête de la forme http://localhost:8080/Francs/faces/*.xhtmlsera donc traité par JSF.

2. Nous pouvons en profiter pour définir la page d'accueil à l'aide du marqueur <welcome-file>, ici conversion.xhtml. Cette balise est optionnelle. Sivous ne voulez pas la définir, la page d'accueil doit alors s'appeler index.xhtml.

3. En option, vous pouvez également configurer quelques paramètres spécifiques à JSF dans l'élément <context-param>. dont la liste est proposée ci-dessous :

Paramètre Description

javax.faces.CONFIG_FILES Définit une liste de chemins de ressources liées au contexte dans lequel JSFrecherchera les ressources.

javax.faces.DEFAULT_SUFFIX Permet de féfinir une liste de suffixes possibles pour les pages ayant du contenu JSF(.xhtml, par exemple).

javax.faces.LIFECYCLE_ID Identifie l'instance LifeCycle utilisée pour traiter les requêtes JSF.

javax.faces.STATE_SAVING_METHOD Définit l'emplacement de sauvegarde de l'état. Les valeurs possibles sont server(valeur par défaut qui indique que l'état sera généralement sauvegardé dans un objetHttpSession) et client (l'état sera sauvegardé dans champ caché lors du prochainenvoi de formulaire).

javax.faces.PROJECT_STAGE Décrit l'étape dans laquelle se trouve cette application JSF dans le cycle de vie(Development, UnitTest, SystemTest ou Production). Cette information peut êtreutilisée par une implémentation de JSF pour améliorer les performances lors de laphase de production en utilisant un cache pour les ressources, par exemple.

javax.faces.DISABLE_FACELET_JSF_VIEWHANDLER Désactive Facelets comme langage de déclaration de page (PDL).

javax.faces.LIBRARIES Liste des chemins qui seront considérés comme une bibliothèque de marqueursFacelets.

Le bean géré Conversion

Comme nous l'avons évoqué plus haut dans ce chapitre, le modèle MVC encourage la séparation entre le modèle, la vue et le contrôleur. Avec Java EE, lespages JSF forment la vue et la FacesServlet est le contrôleur. Les beans gérés, quant à eux, sont une passerelle vers le modèle.

1. Les beans gérés sont des classes Java annotées. Ils constituent le coeur des applications web car ils exécutent la logique métier (ou la délèguent auxEJB, par exemple), gèrent la navigation entre les pages et stockent les données. Une application JSF typique contient un ou plusieurs beans gérésqui peuvent être partagés par plusieurs pages.

2. Les données sont stockées dans les attributs du bean géré, qui, en ce cas, est également appelé "backing bean". Un backing bean définit lesdonnées auxquelles est lié un composant de l'interface utilisateur (la cible d'un formulaire, par exemple). Pour établir cette liaison, nous utilisonsEL, le langage d'expressions.

3. Ecrire un bean géré est aussi simple qu'écrire un EJB ou une entité JPA puisqu'il s'agit simplement de créer une classe Java annotée par@ManagedBean (ou @Named, nous verrons la différence entre les deux écritures lors du prochain chapitre).

4. Les beans gérés sont des classes Java prises en charge par la FacesServlet. Les composants de l'interface utilisateur sont liés aux propriétés du bean(backing bean) et peuvent invoquer des méthodes d'action.

5. Bien qu'un bean géré puisse être une simple classe annotée, sa configuration peut être personnalisée grâce aux éléments de @ManagedBean et@ManagedProperty (voir pour plus de détail dans le chapitre suivant).

6. La présence de l'annotation @javax.faces.model.ManagedBean sur une classe l'enregistre automatiquement comme un bean géré. C'est laFacesServlet qui gère cette classe. Par défaut, le nom du bean géré (objet) est celui de la classe commençant par une minuscule. Il est possible dechoisir un autre nom en spécifiant l'attribut name de l'annotation @ManagedBean.

7. Les composants de l'interface utilisateur étant liés aux propriétés du bean géré, changer son nom par défaut a des répercussions sur la façond'appeler une propriété ou une méthode.

8. Les objets créés dans le cadre d'un bean géré ont une certaine durée de vie et peuvent ou non être accessibles aux composants de l'interfaceutilisateur ou aux objets de l'application. Cette durée de vie et cette accessibilté sont regroupées dans la notion de portée. Plusieurs annotations (quenous étudierons plus en détail dans la chapitre suivant) permettent de définir la portée d'un bean géré.

9. La portée que je choisi pour le bean géré est @ViewScoped. Cet objet est alors disponible dans une vue donnée jusqu'à sa modification. Son étatpersiste jusqu'à ce que l'utilisateur navigue vers une autre vue, auquel cas il est supprimé.

Après toutes ces réflexions, je vous propose maintenant de créer notre bean géré Conversion à l'aide de notre outil de développement Netbeans. Voicila procédure à suivre :

1. Création d'un nouveau bean géré :

Page 14: 08 - JavaServer Faces 2.0

2. Demande de création d'un bean géré dont le nom de l'objet sera conv issu de la classe Conversion et dont la durée de vie correspond exactement àla durée de vie de la page à afficher :

3. Nous plaçons toute la logique métier dans ce bean géré, et c'est lui qui réalise la conversion nécessaire. Voir le code ci-dessous.

bean.Conversion.java

package bean;

import javax.faces.bean.*;

@ManagedBean(name="conv")@ViewScopedpublic class Conversion { private final double TAUX = 6.55957; private double euro; private double franc;

public double getEuro() { return euro; } public void setEuro(double euro) { this.euro = euro; }

public double getFranc() { return franc; } public void setFranc(double franc) { this.franc = euro * TAUX; } public void euroFranc() { franc = euro * TAUX; }}

1. Mise à part les annotations, nous retrouvons une classe normale avec des propriétés et une méthode de traitement.

2. Ces propriétés sont indispensables pour que la page web puisse y accéder et qu'il y ait une interaction possible entre le modèle et la vue.

3. L'annotation @ManagedBean est également indispensable pour stipuler que cette classe doit être prise en compte par le contrôleur (être gérée). C'estfinalement l'équivalent d'un dispositif de configuration puisque nous demandons ainsi que le nom de l'objet correspondant s'appelle conv. Parailleurs, nous configurons également la durée de vie de cet objet pour qu'il soit en adéquation avec la vue au moyen de l'annotation @ViewScoped.

4. Grâce à ces simples annotations, il est très facile de changer de nom d'objet ainsi que sa durée de vie.

Page 15: 08 - JavaServer Faces 2.0

La vue conversion.xhtml

Le modèle, vous venez de le découvrir est très simple. Nous nous intéressons maintenant à notre dernier élément de l'application wen, à savoir la vue, plusprécisément la page conversion.xhtml.

Lorsque vous travaillez avec la vue, vous disposez d'un certain nombre de composants (marqueurs) déjà construits qui sont installés dans desbibliothèques spécifiques qu'il faut prendre en compte lors de l'élaboration de vos pages web si vous désirez les utiliser. Voici le tableau qui recenseles bibliothèques préfabriquées :

URIPréfixeclassique

Description

http://java.sun.com/jsf/html h Contient les composants et leurs rendus HTML (h:commandButton, h:inputText, etc.)

http://java.sun.com/jsf/core f Contient les actions personnalisées indépendantes d'un rendu particulier (f:convertNumber,f:validateDoubleRange, f:param, etc.)

http://java.sun.com/jsf/facelets ui Marqueurs pour le support les modèles de page.

http://java.sun.com/jsf/composite composite Sert à déclarer et à définir des nouveaux composants personnalisés.

http://java.sun.com/jsp/jstl/core c Les pages Facelets peuvent éventuellement utiliser certains marqueurs issus de JSP (c:if, c:forEach etc:catch). A éviter si possible.

http://java.sun.com/jsp/jstl/functions fn Les pages Facelets peuvent utiliser tous les marqueurs de fonctions issus de la technologie JSP.

conversion.xhtml

<?xml version='1.0' encoding='UTF-8' ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <h:head> <title><h:outputText value="Conversion entre les €uros et les francs" /></title> </h:head> <h:outputStylesheet library="css" name="principal.css" /> <h:body> <h3><h:outputText value="Conversion entre les €uros et les francs" /></h3> <hr /> <h:form> <h:inputText value="#{conv.euro}" styleClass="saisie" id="euro" converterMessage="Il faut une valeur monétaire" validatorMessage="Uniquement les nombres positifs" required="true" requiredMessage="Précisez votre valeur monétaire"> <f:convertNumber type="currency" currencySymbol="€"/> <f:validateDoubleRange minimum="0.0" /> </h:inputText> <h:commandButton value="Conversion" action="#{conv.euroFranc}" /> <h:inputText value="#{conv.franc}" readonly="true" styleClass="resultat"> <f:convertNumber type="currency" currencySymbol="F"/> </h:inputText> <p><h:message for="euro" styleClass="erreur"/></p> </h:form> </h:body></html>

1. Au début, dans la balise <html>, vous spécifiez les bibliothèques qui vous serons utiles pour la constitution de votre page.

2. Par exemple, sauf cas très rare, nous avons toujours besoin des marqueurs relatifs au rendu, comme les zones de saisie, les boutons etc. Aussi, nousproposons l'espace de nom h (pour HTML) associé à la bibliothèque xmlns:h="http://java.sun.com/jsf/html".

3. Pour les marqueurs qui réalise du traitement en coulisse, comme les convertisseurs et les validateurs, nous introduisons la bibliothèquexmlns:f="http://java.sun.com/jsf/core". (Nous aurions pu prendre l'espace de nom c, mais il est généralement déjà utilisé par la JSTL). Quelquefois,je prend comme espace de nom core.

4. La balise <h:outputStylesheet library="css" name="principal.css" /> nous permet de prendre en compte la feuille de style principal.css que nousavons mise en oeuvre au préalable, dans la bibliothèque (répertoire) css. Vous pouvez placer votre feuille de style directement dans le répertoireresources (donc sans bibliothèque), auquel cas vous n'avez plus à spécifier l'attribut library.

5. Nous retrouvons pratiquement le même code que nous avons déjà consulté mainte fois. Vous remarquez toutefois la présence d'un nouveaumarqueur <h:message for="euro" styleClass="erreur"/> qui permet d'avertir l'utilisateur d'une mauvaise utilisation sur la zone de saisie des €uros.

6. Cette balise doit toujours être rattachée à une autre au moyen de l'attribut for. De la même façon, la balise en question, comme ici <h:inputTextvalue="#{conv.euro}" id="euro">, doit posséder l'attribut id à l'intérieur duquel vous spécifiez un nom de variable à prendre en compte.

7. Toujours dans cette balise, vous avez la possibilité de spécifier les messages qui s'afficheront automatiquement lors d'une erreur de saisieparticulière. Ici, nous proposons des messages d'erreur de conversion, de validation et de champ non vide, respectivement avec les atttributsconverterMessage, validatorMessage et requiredMessage.

8. Voici d'ailleurs les différents résultats obtenus suivant les cas d'utilisation :

Page 16: 08 - JavaServer Faces 2.0

N'oubliez pas que nous ici dans la technique des pages web dynamiques, c'est-à-dire que tout les marqueurs que nous proposons ne sont pas envoyésau client. La page web conversion.xhtml reste sur le serveur et le système JSF envoie une page web au format HTML classique suivant la requêteproposée par le client (pas besoin d'une installation Java spécifique). Voici justement le code source de la page web qui est envoyée par rapport auxvaleurs proposées ci-dessus :

Page 17: 08 - JavaServer Faces 2.0

Conclusion

Les beans gérés et la navigation

Comme nous l'avons évoqué plus haut dans ce chapitre, le modèle MVC encourage la séparation entre le modèle, la vue et le contrôleur. Avec Java EE, les pages JSFforment la vue et la FacesServlet est le contrôleur. Les beans gérés, quant à eux, sont une passerelle vers le modèle. Je rappelle les points importants que nous avonsdéjà évoqué dans le chapitre précédent :

1. Les beans gérés sont des classes Java annotées. Ils constituent le coeur des applications web car ils exécutent la logique métier (ou la délèguent aux EJB, parexemple), gèrent la navigation entre les pages et stockent les données. Une application JSF typique contient un ou plusieurs beans gérés qui peuvent êtrepartagés par plusieurs pages.

2. Les données sont stockées dans les attributs du bean géré, qui, en ce cas, est également appelé "backing bean". Un backing bean définit les donnéesauxquelles est lié un composant de l'interface utilisateur (la cible d'un formulaire, par exemple). Pour établir cette liaison, nous utilisons EL, le langaged'expressions.

3. Ecrire un bean géré est aussi simple qu'écrire un EJB ou une entité JPA puisqu'il s'agit simplement de créer une classe Java annotée par @ManagedBean ou@Named.

Page 18: 08 - JavaServer Faces 2.0

4. Les beans gérés sont des classes Java prises en charge par la FacesServlet. Les composants de l'interface utilisateur sont liés aux propriétés du bean (backingbean) et peuvent invoquer des méthodes d'action.

5. Bien qu'un bean géré puisse être une simple classe annotée, sa configuration peut être personnalisée grâce aux éléments de @ManagedBean et@ManagedProperty.

6. La présence de l'annotation @javax.faces.model.ManagedBean ou @javax.inject.Named sur une classe l'enregistre automatiquement comme un bean géré.C'est la FacesServlet qui gère cette classe. Par défaut, le nom du bean géré (objet) est celui de la classe commençant par une minuscule. Il est possible dechoisir un autre nom en spécifiant l'attribut name de l'annotation @ManagedBean ou de l'annotation @Named.

7. Les composants de l'interface utilisateur étant liés aux propriétés du bean géré, changer son nom par défaut a des répercussions sur la façon d'appeler unepropriété ou une méthode.

Pour conclure sur cette première approche, un bean géré doit respecter les contraintes suivantes :

1. Le classe doit être annotée par @ManagedBean ou @Named.

2. La classe doit avoir une portée (qui vaut par défaut @RequestScoped). (Nous découvrirons les différentes portées dans la suite du chapitre).

3. La classe doit être publique et non finale ni abstraite.

4. La classe doit fournir un constructeur public sans paramètre qui sera utilisé par le conteneur pour créer les instances.

5. La classe ne doit pas définir de méthode finalize().

6. Pour être liés à un composant graphique de la vue, les attributs doivent avoir des getters et des setters public (ce que nous appelons des propriétés). En réalité,le point de contact d'un composant graphique avec la propriété se fait toujours au travers des méthodes. Du coup, dans certains cas, il n'est pas toujoursnécessaire d'avoir un attribut qui conserve la valeur. Par contre, la syntaxe du getter et du setter doit être respectée.

Les beans CDI

Jusqu'à présent, nous avons surtout travaillé sur les beans managés au travers de l'annotation @ManagedBean. Cependant, les beans managés sont assez limités. JSF,avec sa dernière version, définie un modèle de bean géré plus flexible, nommé CDI (Contexts and Dependency Injection). Ce bean, comme son nom l'indique, est lié àun context (comme, par exemple, la requête en cours, la session actuelle du navigateur, ou même le cycle de vie du context de l'utilisateur.

CDI spécifie un mécanisme pour injecter des beans gérés, pour intercepter les méthodes d'appel, et prendre en compte à la volée les événements liées auxdifférentes requêtes du client web.

Ceci dit, nous pouvons continuer à prendre des beans managés. Dans bien des cas ils sont généralement suffisants, notamment si nous n'avons pas besoind'interaction. Ils permettent d'avoir une gestion autonome du modèle.

Là où les beans CDI sont importants, c'est justement lorsque nous désirons avoir une forte interaction avec les autres éléments du serveur d'applications, commeles beans sessions, les entités, les applications web de type Rest. Ainsi, par exemple, l'injection permet d'avoir un bean session qui sert également de bean géréen relation directe avec la vue, à condition toutefois que ce bean session soit de type stateful afin de permettre le suivi des différentes requêtes de l'applicationweb.

Après toutes ces définissions, venons en maintenant à l'écriture proprement dite. Nous retrouvons pratiquement la même syntaxe que les beans managés. Vousavez juste à utiliser l'annotation @Named en lieu et place de l'annotation @ManagedBean, comme ci-dessous :

bean.Conversion.java

package bean;

import javax.io.Serializable;import javax.inject.Named; // importation différenteimport javax.enterprise.context.SessionScoped; // importation différente

@Named("conv")@SessionScoped // la durée de vie Vue n'existe pas dans les beans CDIpublic class Conversion implementation Serializable { // Nous devons également faire en sorte que l'objet soit sérialisé private final double TAUX = 6.55957; private double euro; private double franc;

public double getEuro() { return euro; } public void setEuro(double euro) { this.euro = euro; }

public double getFranc() { return franc; } public void setFranc(double franc) { this.franc = euro * TAUX; } public void euroFranc() { franc = euro * TAUX; }}

1. Mise à part quelques petits détails, le code du bean géré correspondant à la conversion demeure similaire.

2. Notamment nous pouvons conserver la même vue que précédemment. Ainsi, l'accès à une propriété de ce bean se fait exactement de la même façon: #{conv.euro}, par exemple.

3. Les différences notables concerne les importations d'une part, et surtout, notre bean doit être sérialisé.

4. Il existe des durées de vie différentes dans les deux types de bean.

5. La mise en oeuvre des beans CDI est également différente avec Netbeans. Nous verrons comment procéder lors du prochain exemple.

Portée et durée de vie des beans gérés

Les objets créés dans le cadre d'un bean géré ont une certaine durée de vie et peuvent ou non être accessibles aux composants de l'interface utilisateur ou aux objetsde l'application. Cette durée de vie et cette accessibilté sont regroupées dans la notion de portée. Plusieurs annotations permettent de définir la portée d'un bean géré.

Lorsque vous définissez un bean géré, vous êtes obligés de spécifier également sa portée. Trois portées sont communes au beans managés et beans CDI : lesportées de type Session, de type Requête et de type Application.

JSF 2.0 rajoute les portées de type Vue et de type Personnalisée qui ne sont pas supportées par les beans CDI mais qui proposent en contre partie une portéeplus puissante qui s'appelle Conversation.

Page 19: 08 - JavaServer Faces 2.0

Avec JSF 2.0, vous pouvez utiliser les annotations suivantes pour prendre en compte les portées communes : @SessionScoped, @RequestScoped et@ApplicationScoped. Notez que ces annotations sont décrites dans le paquetage javax.faces.bean pour les beans managés et dans le paquetagejavax.enterprise.context pour les beans CDI.

Définition de chacune des portées

1. @ApplicationScoped : Il s'agit de l'annotation la moins restrictive, avec la plus longue durée de vie. Les objets créés sont disponibles dans tous les cyclesrequête/réponse de tous les clients utilisant l'application tant que celle-ci est active. Ces objets peuvent être appelés de façon concurrente et doivent dont êtrethread-safe (c'est-à-dire utiliser le mot-clé synchronized). Les objets ayant cette portée peuvent utiliser d'autres objets sans portée ou avec une portéed'application.

Ce type de bean est construit dès l'apparition de la première requête d'un client et reste actif jusqu'à ce que l'application web soit enlevée du serveurd'applications. Cependant, il est possible de faire en sorte que ce bean soit actif plus tôt, bien avant que la première page soit affichée, dès quel'application web est déployée sur le serveur, au moyen de l'attribut eager, comme suit :

@ManagedBean(eager=true)

2. @SessionScoped : Ces objets sont disponibles pour tous les cycles requête/réponse de la session du client. Leur état persiste entre les requêtes et dure jusqu'àla fin de la session. Ils peuvent utiliser d'autres objets sans portée, avec une portée de session ou d'application.

Rappelez-vous que le protocole HTTP est sans état. Le navigateur envoie une requête au serveur, le serveur renvoie la réponse, et ni le navigateur nile serveur sont dans l'obligation, dans ce protocole, de garder en mémoire la transaction.

3. @ViewScoped : (Uniquement pour les beans managés) : Ces objets sont disponibles dans une vue donnée jusqu'à sa modification. Leur état persiste jusqu'à ceque l'utilisateur navigue vers une autre vue, auquel cas il est supprimé. Ils peuvent utiliser d'autres objets sans portée, avec une portée de vue, de session oud'application.

4. @RequestScoped : Il s'agit de la portée par défaut. Ces objets sont disponibles du début d'une requête jusqu'au moment où la réponse est envoyée au client.Un client pouvant exécuter plusieurs requêtes tout en restant sur la même vue, la durée @ViewScoped est supérieure à celle de @RequestScoped. Les objetsayant cette portée peuvent utiliser d'autres objets sans portée, avec une portée de requête, de vue, de session ou d'application.

Avec cette portée, la durée de vie est très courte. La création du bean se réalise dès qu'une requête est proposée et se détruit rapidement dès que laréponse à été renvoyée au client. Cela veut dire qu'une nouvelle instance est créée à chaque requête du client. Du coup, pour une même vue,beaucoup de mémoires risquent d'être utilisées pour rien.

5. @NoneScoped : Les beans gérés ayant cette portée ne sont visibles dans aucune page JSF; ils définissent des objets utilisés par d'autres beans gérés del'application. Ils peuvent utiliser d'autres objets avec la même portée.

6. @ConversationScoped : (Uniquement pour les beans CDI) : Cette portée est intéressante lorsque vous avez besoin de gérer plusieurs onglets pour une mêmesession. C'est un petit peu l'intermédiaire entre la portée de type requête et la portée de type session.

La portée des beans gérés doit être judicieusement choisie : vous ne devez leur donner que la portée dont ils ont besoin. Des beans ayant une portée trop grande(@ApplicationScoped, par exemple) augmentent l'utilisation mémoire et l'utilisation du disque pour leur persistance éventuelle. Il n'y a aucune raison de donnerune portée d'application à un objet qui n'est utilisé que dans un seul composant. Inversement, un objet ayant une portée trop restreinte (@RequestScoped, parexemple) ne sera pas disponible dans certaines parties de l'application, et éventuellement beaucoup d'objets (avec donc beaucoup de mémoires) risquent d'êtrecréés pour rien.

Injection de valeurs dans les beans (@ManagedProperty et @Inject)

Dans un bean géré, vous pouvez demander au système d'injecter une valeur dans une propriété (un attribut avec un getter et un setter) en utilisant l'[email protected] (pour les beans managés) ou @javax.inject.Inject (pour les beans CDI), dont l'attribut value peut recevoir une chaîne ou uneexpression EL.

Annotation du cycle de vie et des méthodes de rappel

L'introduction nous a montré le cycle de vie d'une page (qui compte six phases, de la réception de la requête à la production de la réponse), mais le cycle de vie desbeans gérés est totalement différent : en fait il est totalement identique à celui des beans sessions sans état.

Les beans gérés qui s'exécutent dans un conteneur de servlet peuvent utiliser les annotations @PostConstruct et @PreDestroy.

Ainsi, après avoir créé une instance de bean géré, le conteneur appelle la méthode de rappel @PostConstruct s'il y en a une. Puis le bean est lié à uneportée et répond à toutes les requêtes de tous les utilisateurs. Toutefois, avant de supprimer le bean, le conteneur appelle la méthode @PreDestroy. Cesméthodes permettent ainsi d'initialiser les attributs ou de créer et libérer les ressources externes.

bean.GestionLivre.java

@ManagedBean ou @Namedpublic class GestionLivre { ... @PostConstruct public void début() { ... }... @PreDestroy public void fin() { ... }}

Langage d'expressions EL

Page 20: 08 - JavaServer Faces 2.0

Les instructions EL fournissent une syntaxe simple d'utilisation afin de se connecter à une propriété ou à proposer une action spécifique sur un bean géré. Ellespermettent facilement d'afficher les valeurs des variables ou d'accéder aux attributs des objets, aux travers de leurs propriétés, et disposent également d'un grandnombre d'opérateurs mathématiques, logiques et relationnels.

La syntaxe de base d'une instruction EL est de la forme :

#{expression}

Les expressions EL peuvent utiliser la plupart des opérateurs Java habituels :

1. Arithmétiques : + - * / (division) % (modulo)

2. Relationnels : == (égalité) != (inégalité) < (inférieur) > (supérieur) <= (inférieur ou égal) >= (supérieur ou égal)

3. Logiques : && (et) || (ou) ! (non)

4. Autre : empty (vide) () (parenthèses) [ ] (crochets) . (séparateur) ?: (if arithmétique)

L'opérateur empty teste si un objet est null ou si les collections (tableaux, List, Map, etc. ) sont vides. Nous pouvons ainsi contrôler, par exemple, qu'unlivre est défini ou pas :

#{empty livre}

L'opérateur point permet d'accéder à un attribut d'un objet. Une autre syntaxe possible consiste à utiliser l'opérateur [ ]. Nous pouvons ainsi accéder àl'attribut titre de l'objet livre de la façon suivante :

#{livre.titre} ou #{livre[titre]}

Appel de méthodes

Il est également possible d'appeler des méthodes. Si vous désirez par exemple acheter un livre en appelant la méthode acheter() de l'objet livre :

#{livre.acheter}

Depuis la toute dernière version de JSF, nous pouvons également proposer des paramètres aux appels de méthode :

<h:commandButton value="Suivant" action="#{unBean.naviguer(1)}" /><h:commandButton value="Précédent" action="#{unBean.naviguer(-1)}" />

A condition que cette méthode soit effectivement déclarée avec le bon paramètre :

@ManagedBeanpublic class UnBean { ... public void naviguer(int sens) { ... }}

Actions fondamentales

Les actions fondamentales, énumérées dans le tableau ci-dessous, fournissent des marqueurs pour manipuler les beans gérés, des variables, traiter des erreurs, effectuerdes tests et exécuter des boucles et des itérations :

Action Description

<c:remove> Supprime une variable.

<c:catch> Capture une exception java.lang.Throuwable lancée par l'une de ses actions imbriquées.

<c:if> Teste si une expression est vrai (la plupart du temps, il est préférable d'utiliser plutôt l'attribut rendered présent dans toutes les balises de JSF).

<c:choose> Fournit plusieurs alternatives exclusives.

<c:when> Représente une alternative dans une section <c:choose>.

<c:otherwise> Représente la dernière alternative d'une action <c:choose>.

<c:forEach> Répète son corps pour chaque élément d'une collection ou un nombre fixé de fois.

Objets prédéfinies

Il existe des identificateurs spéciaux, que nous pouvons atteindre directement dans les différentes vues, qui correspondent à des objets spécifiques déjà prédéfinis. Cesont des objets implicites parce qu'une page peut les utiliser sans avoir besoin de les déclarer ou de les initialiser explicitement. Ces objets (énumérés dans le tableauci-dessous) sont utilisable à l'aide des expressions EL.

Objet implicite Description Type renvoyé

application Représente l'environnement de l'application web. Sert à obtenir les paramètres de configuration de cette application. Object

applicationScope Associe les noms des attributs de l'application à leurs valeurs. Map

component Désigne le composant courant. UIComponent

cc Désigne le composant composite courant. UIComponent

cookie Désigne un Map contenant les noms des cookies (clés) et des objets Cookie. Map

facesContext Désigne l'instance FacesContext de cette requête. FacesContext

header Fait correspondre chaque nom d'en-tête HTTP à une seule valeur de type String. Map

headerValue Fait correspondre chaque nom d'en-tête HTTP à un tableau String[] contenant toutes les valeurs de cet en-tête. Map

initParam Fait correspondre les noms des paramètres d'initialisation du contexte à leurs valeurs de type String. Map

param Fait correspondre chaque nom de paramètre à une seule valeur de type String. Map

paramValues Fait correspondre chaque nom de paramètre à un tableau String[] contenant toutes les valeurs de ce paramètre. Map

request Représente l'objet requête HTTP. Object

requestScope Fait correspondre les noms des attributs de la requête à leurs valeurs. Map

resource Indique l'objet ressource. Object

session Représente l'objet session HTTP. Object

Page 21: 08 - JavaServer Faces 2.0

session Représente l'objet session HTTP. Object

sessionScope Fait correspondre les noms des attributs de la session à leurs valeurs. Map

view Représente la vue courante. UIViewRoot

viewScope Fait correspondre les noms des attributs de la vue à leurs valeurs. Map

Tous ces objets implicites sont de vrais objets avec des interfaces. Vous pouvez accéder à leurs attributs avec EL :

1. Ainsi, #{view.locale}, par exemple, permet d'obtenir le pays dans lequel est consulté cette page (en_US, fr_FR, etc.).

2. Si vous stockez un livre dans la portée de la session, par exemple, vous pouvez l'atteindre avec #{sessionScope.livre}.

3. Vous pouvez même utiliser un alogorithme plus élaboré pour afficher tous les en-têtes HTTP et leurs valeurs :

<?xml version='1.0' encoding='UTF-8' ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:c="http://java.sun.com/jsp/jstl/core"> <h:body style="background-color: yellow; font-weight: bold"> <h3> <h:outputText value="Lecture des en-têtes de la requête HTTP" /> <h:outputText value=" (En france)" rendered="#{view.locale == 'fr_FR'}" /> </h3> <hr /> <c:forEach items="#{headerValues}" var="élément"> <h:outputText value="#{élément.key}" style="color: mediumslateblue" /> = <c:forEach var="valeur" items="#{élément.value}"> <h:outputText value="#{valeur}" escape="false" style="color: brown" /> <br /> </c:forEach> </c:forEach> </h:body></html>

Navigation

Les applications web sont formées de plusieurs pages entre lesquelles vous devez naviguer. Selon le cas, il peut exister différents niveaux de navigation avec des fluxde pages plus ou moins élaborés.

JSF dispose de plusieurs options de navigation et vous permet de contrôler le flux page par page ou pour toute l'application.

Navigation statique

Les composants <h:commandButton> et <h:commandLink> permettent de passer simplement d'une page à une autre en cliquant sur un bouton ou sur unlien sans effectuer aucun traitement intrinsèque. Il suffit d'initialiser leur attribut action avec le nom de la page vers laquelle vous voulez vous rendre. Ici, parexemple, nous sommes dans la page de configuration du jeu qui se nomme justement "configurer.xhtml". Voici le bouton de navigation que nous pourrionsavoir dans cette page pour demander à passer à la page "alea.xhtml" correspondant au jeu lui-même :

<h:commandButton value="Commencer le jeu" action="alea.xhtml" />

Navigation dynamique

Cependant, la plupart du temps, ceci ne suffira pas car vous aurez besoin d'accéder à une couche métier ou à une base de données pour récupérer ou traiterdes données. En ce cas, vous aurez besoin d'un bean géré. Par exemple, avant de commencer à jouer, nous avons besoin de faire un certain nombre detraitement avant que le jeu soit totalement prêt. Dans cette situation, le flux des pages reste simple, mais ces deux pages ont pourtant besoin d'un bean géré(Nombre) pour traiter à la fois la logique métier ainsi que la navigation. Elles utilisent toujours les composants bouton (ou lien) pour naviguer et interagiravec ce bean.

Il suffit juste de préciser la méthode du bean géré qui va traiter la logique métier (préparer le jeu) et s'occuper ensuite de la navigation. Ici, parexemple, c'est la méthode recommencer() du bean nombre qui est appelée :

<h:commandButton value="Commencer le jeu" action="#{nombre.recommencer}" />

Les composants bouton et lien n'appellent pas directement la page vers laquelle ils doivent se rendre : ils appellent des méthodes du bean géré quiprennent en charge cette navigation et laissent le code décider de la page qui sera chargée ensuite. La navigation utilise un ensemble de règles quidéfinissent tous les chemins de navigation possibles de l'application. Dans la forme la plus simple de ces règles de navigation, chaque méthode du

Page 22: 08 - JavaServer Faces 2.0

bean géré définit directement la page vers laquelle elle doit aller.

@Named@SessionScopedpublic class Nombre implements Serializable {... public String recommencer() { alea = (int)(Math.random()*valeurMax)+1; tentative = 0; valeur = 0; test = false; return "alea.xhtml"; }}

Ainsi, quand le <h:commandButton> invoque la méthode recommencer(), celle-ci initialise le jeu, tire le nombre aléatoire et renvoie le nom de la pagevers laquelle naviguer ensuite : alea.xhtml. La FacesServlet redirigera alors le flux de page vers la page désirée. Remarquez au passage, le type deretour String de cette méthode recommencer().

La chaîne renvoyée peut prendre plusieurs formes. Ici, nous avons utilisé la plus simple : le nom de la page. L'extension de fichier par défaut étant.xhtml, nous aurions même pu simplifié le code en supprimant l'extension.

@Named@SessionScopedpublic class Nombre implements Serializable {... public String recommencer() { alea = (int)(Math.random()*valeurMax)+1; tentative = 0; valeur = 0; test = false; return "alea"; }}

Les exemples précédentes nous ont montré une navigation simple où une page n'avait qu'une seule règle de navigation et une seule destination. Cen'est pas un cas si fréquent : les utilisateurs peuvent généralement être redirigés vers des pages différents en fonction de certaines conditions.

Cette navigation, là encore, peut être mise en place dans les beans gérés. Le code suivant utilise une instruction switch pour rediriger l'utilisateur verstrois pages possibles. Si nous renvoyons la valeur null, l'utilisateur reviendra sur la page sur laquelle il se trouve déjà.

public String uneMéthode() { switch (valeur) { case 1 : return "page1.xhtml"; break; case 2 : return "page2.xhtml"; break; case 3 : return "page3.xhtml"; break; default : return null; break; } }

Redirection et méthodes POST et GET du protocole HTTP

Vous pouvez solliciter l'implémentation JSF pour vous rediriger vers une autre vue. JSF envoie alors une redirection HTTP au client. La redirection est envoyéeau navigateur client avec l'URL correspondant à la nouvelle page. Le navigateur client soumet alors cette nouvelle requête en utilisant la méthode GET duprotocole HTTP.

La redirection est moins rapide que la navigation classique puisque vous proposer une requête supplémentaire au navigateur. Cependant, laredirection assure au navigateur de mettre à jour systématiquement la page web à visualiser.

1. La redirection est directive. Elle supplante les règles de navigations classiques. Pour la mettre en oeuvre, il suffit de rajouter la chaîne suivante :

?faces-redirect=true

2. Voici ce que nous pouvons proposer sur un composant <h:commandButton> :

<h:commandButton value="Accueil" action="accueil?faces-redirect=true" />

3. Par nature, les composants <h:commandButton> propose des requêtes HTTP de type POST. Si vous désirez plutôt proposer des requêtes de typeGET, prenez alors le composant <h:button> comme suit :

<h:button value="Accueil" outcome="accueil" />

Vous remarquez la présence de l'attribut outcome de ce composant <h:button> en lieu et place de l'attibut action du composant<h:commandButton>. Il existe une différence fondamentale de comportement. Avec outcome, vous pouvez vous rattacher à une propriétéd'un bean géré, mais surtout pas à l'appel d'une méthode. Pour action, vu d'ailleurs son nom, c'est l'inverse, c'est-à-dire que normalementcet attribut est utilisé pour faire appel à la méthode qui gère la navigation.

4. Dans les requêtes GET, nous avons quelquefois besoin de rajouter des paramètres qui vont servir à exploiter correctement la demande. Le plusfacile, à mon avis, est de rajouter une balise <f:param> pour chaque paramètre que vous souhaitez prendre en compte dans votre soumissions :

<h:button value="Accueil" includeViewParams="true" outcome="accueil"> <f:param name="utilisateur" value="#{bean.personne}"> <f:param name="administrateur" value="non"></h:button>

Page 23: 08 - JavaServer Faces 2.0

Application web qui propose un jeu de tirage aléatoire d'un nombre

Pour terminer ce chapitre, je vous propose de prendre en compte ces notions de navigation avec pour modèle un bean CDI au travers d'un projet spécifique. Je vouspropose de faire un petit jeu qui nous permet de retrouver un nombre déterminé aléatoirement avec un nombre de coup et une valeur maximale limites.

Nous allons maintenant suivre toute la procédure pour réaliser ce projet au travers de l'environnement Netbeans.

Mise en place du projet

1. Création d'un projet de type application Web :

2. Nom du projet Alea :

Page 24: 08 - JavaServer Faces 2.0

3. Choix du serveur d'applications et des réglages de base :

4. Prise en compte de la technologie JSF pour cette application web :

Descripteur de déploiement web.xml

L'application web comporte cette fois-ci deux vues, la première (configurer.xhtml) permet de configurer le jeu en spécifiant la valeur limite du nombre àrechercher avec également un nombre de coup limite, la deuxième (alea.xhtml) concerne le jeu lui-même. J'aimerai que la première page soit affichée dès quenous sollicitons cette application web. Voici ce que nous pouvons proposer au niveau du descripteur de dpéloiement :

web.xml

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

<servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup>

</servlet>

Page 25: 08 - JavaServer Faces 2.0

</servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping>

<welcome-file-list> <welcome-file>faces/configurer.xhtml</welcome-file> </welcome-file-list></web-app>

Le bean géré Nombre

Une fois que le projet est en place, la première démarche avant de s'intéresser aux vues, est de s'occuper du modèle qui va réaliser tous les traitementsnécessaires en coulisse. Pour changer, par rapport au premier projet de conversion, le modèle sera mis en oeuvre au travers d'un bean CDI.

bean.Nombre.java

package bean;

import javax.inject.*;import javax.enterprise.context.*;import java.io.Serializable;

@Named@SessionScopedpublic class Nombre implements Serializable { private int valeurMax = 20; private int tentativeMax = 4; private int valeur; private int alea; private int tentative; private boolean test;

public int getTentativeMax() { return tentativeMax; } public void setTentativeMax(int tentativeMax) { this.tentativeMax = tentativeMax; }

public int getValeurMax() { return valeurMax; } public void setValeurMax(int valeurMax) { this.valeurMax = valeurMax; }

public int getValeur() { return valeur; } public void setValeur(int valeur) { this.valeur = valeur; } public int getTentative() { return tentative; }

public String recommencer() { alea = (int)(Math.random()*valeurMax)+1; tentative = 0; valeur = 0; test = false; return "alea.xhtml"; } public void calcul() { if (tentative<tentativeMax) { tentative++; test = alea == valeur; } }

public String getRésultat() { if (test) return "Bravo, vous avez trouvé !"; if (tentative==tentativeMax) return "Désolé, vous avez perdu. La valeur à rechercher est "; if (tentative==0) return "Tentez votre chance"; 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 "+(alea>valeur ? "grand" : "petit"); }

public int getAlea() { return alea; } public boolean isFin() { return test || tentative == tentativeMax; }}

1. Pour cette partie relative au modèle, nous pouvons envisager plusieurs approches quant au nombre de beans gérés à prendre en compte. Lasolution retenue ici est de n'utiliser qu'un seul bean. Du coup, le code est beaucoup plus volumineux que lors du projet précédent, puisque cemême bean doit être en relation avec deux vues différentes. Par ailleurs, le traitement à réaliser est plus conséquent.

2. Il s'agit d'un bean CDI. Remarquez cette fois-ci la présence de l'annotaion @Named. Pour sa mise en oeuvre avec Netbeans, nous retrouvons lesmêmes boîtes de dialogue, si ce n'est la petite différence quant au choix de la portée de l'objet.

3. Lors de l'élaboration d'un bean géré, nous devons retrouver, bien entendu, des attributs, pour sauvegarder des informations qui vont être utiles lorsdu passage d'une requête à l'autre, des propriétés (getters et setters) indispensables pour la communication directe avec les vues, et des méthodesqui vont être appelées pour réaliser des traitements spécifiques ou pour naviguer entre les vues lorsque l'utilisateur clique sur les boutons desoumissions.

4. La portée choisie ici est une portée de type session. Ce choix est important puisque lorsque nous réglons les valeurs limites dans la page deconfiguration, il est impératif de conserver ces valeurs lorsque nous basculons vers la page correspondant au jeu. Pour les mêmes raisons, parexemple, il faut bien garder en mémoire le nombre aléatoire tiré pendant toute la phase du jeu.

5. Les attributs présents dans ce bean, sont les valeurs limites valeurMax et tentativeMax, aléa le nombre aléatoire à rechercher, la valeur proposée parl'utilisateur en cours de jeu, le nombre de tentative qui s'incrémente automatiquement en cours de jeu et enfin test qui détermine si le nombreproposé par l'utilisateur est le bon.

Page 26: 08 - JavaServer Faces 2.0

6. Nous retrouvons la plupart des proriétés en relation avec ces attributs. Toutefois, il n'existe pas de propriété relative à l'attribut test. Ainsi, desattributs peuvent exister sans qu'ils soient systématiquement accessibles directement dans la vue. Cet attribut test reste utile lors des traitementsannexes.

7. A l'inverse, et c'est flagrant ici, nous pouvons proposer des propriétés qui ne sont associées à aucun attribut particulier parce que nous ne désironspas conserver d'informations particulières. Elles ne sont utiles que pour l'instant présent. C'est le cas des propriétés en lecture seule, résultat,progression et fin, accessibles donc au travers des méthodes respectives getRésultat(), getProgression() et isFin(). Les deux premières propriétésservent pour l'affichage d'informations alors que la dernière permet de savoir si nous somme à la fin du jeu.

8. Pour terminer avec ce bean, la méthode intéressante, comme nous l'avons déjà évoqué dans ce chapitre, est la méthode recommencer() qui serasollicitée à chaque fois que nous devons débuter le jeu, soit après la configuration (appel depuis configurer.xhtml), soit lorsque nous désirons toutsimplement recommencer une partie (appel depuis alea.xhtml).

9. Cette méthode permet d'initialiser correctement tous les attributs afin que le jeu débute dans de bonnes conditions, et surtout, quand tout est prêt,c'est la vue alea.xhtml qui est automatiquement appelée au retour de la méthode. Cette requête est prise en compte par le contrôleur qui s'occupeeffectivement de cette demande d'affichage. Il s'agit d'une navigation dynamique.

Feuille de style CSS

Pour ce projet également, et pour tous les projets d'ailleurs, il est judicieux de proposer une feuille de style principale afin de bien séparer l'aspect visuel ainsique la charte graphique avec les fonctionnalités propres des composants de la vue. Ainsi, il sera très facile par la suite de changer rapidement cet aspect pour enproposer un autre plus adapté.

Rappelez-vous que cette feuille de style ne doit pas être placée n'importe où. Vous devez impérativement prévoir au moins un répertoire bienspécifique pour toutes les ressources annexes à votre projet qui se nomme très justement resources :

resources/<identifiant_ressource>ouMETA-INF/resources/<identifiant_ressource>

<identifiant_ressource> est formé de plusieurs sous-répertoire indiqués sous la forme :

[locale/ ] [nomBibliothèque/ ] nomRessource [ /versionRessource]

Je rappelle que tous les éléments entre crochets sont facultatifs. La dernière fois, j'avais proposé de prendre en compte la bibliothèque (css)que je ne renouvelle pas ici :

resources/principal.css

principal.css

root { display: block;}

body { background-color: orange; font-weight: bold; color: maroon; }

.saisie { text-align:right; background-color:yellow; font-weight:bold; color:green; width: 30px; display: block;}

.normal { font-weight:bold; }

h2, h3 { background-color: yellow; padding: 5px; border: groove; }

.progression { color: blue; }

.resultat { border: groove; padding-right: 3px; }

Les vues configurer.xhtml et alea.xhtml

Dans le projet, nous disposons de deux vues :

1. La première configurer.xhtml qui permet, comme son nom l'indique, de faire les réglages nécessaires sur les valeurs maximales savoir, la valeurmaximale du nombre à recherche et le nombre de tentative maximum.

Page 27: 08 - JavaServer Faces 2.0

2. La deuxième alea.xhtml qui s'occupe de jeu proprement dit :

configurer.xhtml

<?xml version="1.0" encoding="UTF-8"?>

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">

<h:head> <title>Recherche d'un nombre aléatoire</title> </h:head>

<h:outputStylesheet name="principal.css" /> <h:body> <h:form> <h:panelGrid columns="2"> <h:outputText value="Recherche d'un nombre aléatoire compris entre 1 et " styleClass="normal" /> <h:inputText value="#{nombre.valeurMax}" styleClass="saisie"/> <h:outputText value="Nombre de tentative possibles " styleClass="normal"/> <h:inputText value="#{nombre.tentativeMax}" styleClass="saisie"/> </h:panelGrid> <hr /> <h:commandButton value="Commencer le jeu" action="#{nombre.recommencer}" /> </h:form> </h:body></html>

1. Cette page est relativement modeste. Nous retrouvons la même ossature que lors du premier projet. Le fait d'avoir construit une feuille de styleséparée permet d'alléger considérablement la vue elle-même.

2. Dans ce projet, encore plus que pour le premier, une feuille de style est vraiment intéressante, puisqu'elle est utilisée pour deux vues différentes.Cela permet de factoriser les réglages nécessaires dans un même endroit et d'éviter ainsi les duplications de code.

3. La prise en compte de la feuille de style se fait toujours au moyen de la balise <h:outputStylesheet name="principal.css" />. Cette fois-ci toutefois,l'attribut library n'est pas utilisé puisque nous avons placé la feuille de style directement dans le répertoire resources sans proposer de libraireinterne.

4. La grande nouveauté concerne la balise <h:panelGrid columns="2">. Ce composant est l'équivalent d'un panneau intermédiaire qui permet d'alignertous les autres composants qui se trouve à l'intérieur, et dans ce cas précis suivant deux colonnes.

5. Avec le composant <h:commandButton value="Commencer le jeu" action="#{nombre.recommencer}" />, lorsque l'utilisateur clique sur le bouton,c'est la méthode recommencer() du bean CDI nombre qui est appelée, et cette dernière comme nous l'avons vu, après avoir remis à zéro les attributsconcernant le jeu, demande au contrôleur d'afficher la page alea.xhtml.

public String recommencer() { alea = (int)(Math.random()*valeurMax)+1; tentative = 0; valeur = 0; test = false; return "alea.xhtml";}

alea.xhtml

<?xml version='1.0' encoding='UTF-8' ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Page 28: 08 - JavaServer Faces 2.0

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">

<h:head> <title>Recherche d'un nombre aléatoire</title> </h:head> <h:outputStylesheet name="principal.css" />

<h:body> <h:form> <h:panelGrid columns="3"> <h:outputText value="Votre nombre : " /> <h:inputText value="#{nombre.valeur}" styleClass="saisie" /> <h:outputText value="#{nombre.progression}" styleClass="progression" /> <h:outputFormat value="Tentative{0, choice, 0#|2#s} : "> <f:param value="#{nombre.tentative}" /> </h:outputFormat> <h:inputText value="#{nombre.tentative}" styleClass="saisie" disabled="true" /> </h:panelGrid> <hr /> <h:commandButton value="Valider votre nombre" action="#{nombre.calcul}" disabled="#{nombre.fin}" /> &nbsp; <h:commandButton value="Recommencer" action="#{nombre.recommencer}" /> &nbsp; <h:commandButton value="Changer les valeurs limites" action="configurer.xhtml" /> <hr /> <h2> <h:outputText value="#{nombre.résultat}" /> <h:outputText value="#{nombre.alea}" styleClass="saisie" rendered="#{nombre.fin}" /> </h2> </h:form> </h:body></html>

1. Ici aussi, je vous propose quelques remarques. Sur cette dernière version de JSF, il n'est pas obligé de prendre systématiquement une balise<h:outputText value="Votre nombre : " />. Nous aurions pu écrire directement Votre nombre : . Si vous avez à prendre en compte des styles CSS, ilest alors intéressant de les utiliser, comme ici <h:outputText value="#{nombre.progression}" styleClass="progression" />.

2. Le composant <h:outputFormat value="Tentative{0, choice, 0#|2#s} : "> permet de proposer d'afficher des textes paramétrés, comme ici de rajouterun s à partir de la deuxième tentative. A l'intérieur de ce composant, vous devez spécifier l'ensemble des paramètres qui sert de critère de calcul autravers du composant <f:param value="#{nombre.tentative}" />.

3. Le bouton <h:commandButton value="Valider votre nombre" action="#{nombre.calcul}" disabled="#{nombre.fin}" /> peut être grisé, et donc nonactif, au moyen de l'attribut disabled, ici par exemple lorsque nous somme à la fin du jeu.

4. Lorsque vous désirez faire une navigation statique, c'est-à-dire lorsque vous désirez atteindre une autre page sans faire de traitement préliminaire ousans condition particulière, il suffit simplement de préciser la page dans l'attribut action du composants <h:commandButton value="Changer lesvaleurs limites" action="configurer.xhtml" />.

5. Enfin, il est possible d'afficher un composant sous certaines conditions, ceci également très simplement, au moyen de l'attribut rendered (présentsur tous les composants visuels). Par exemple, lorsque nous sommes à la fin du jeu, nous pouvons montrer le nombre à rechercher <h:outputTextvalue="#{nombre.alea}" styleClass="saisie" rendered="#{nombre.fin}" />.

Conclusion

Page 29: 08 - JavaServer Faces 2.0

Bibliothèques de balises JSF

L'architecture JSF est conçue pour être indépendante de tout protocole ou langage à marqueurs particulier et pour écrire des applications pour les clients HTML quicommuniquent via HTTP. Une interface utilisateur pour une page web donnée est créée en assemblant des composants qui fournissent des fonctionnalités spécifiquesafin d'interagir avec l'utilisateur (labels, cases à cocher, etc.) - JSF met à disposition un certain nombre de classes composants couvrant la plupart des besoinsclassiques.

Une page est une arborescence de classes héritant de javax.faces.component.UIComponent ayant des propriétés, des méthodes et des événements. La racine del'arbre est une instance de UIViewRoot et tous les autres composants respectent une relation d'héritage.

Lors de la version précédente, JSF proposait uniquement deux librairies de balises : core et HTML, la version JSF 2.0 couvre maintenant six librairies différentesqui possèdent plus d'une centaine de marqueurs spécifiques. Le tableau ci-dessous nous rappelle ces différentes librairies. Dans ce chapitre toutefois, nous nousintéresserons uniquement sur les bibliothèques core et HTML.

URIPréfixeclassique

Description

http://java.sun.com/jsf/html h Contient les composants et leurs rendus HTML (h:commandButton, h:inputText, etc.)

http://java.sun.com/jsf/core f Contient les actions personnalisées indépendantes d'un rendu particulier (f:convertNumber,f:validateDoubleRange, f:param, etc.)

http://java.sun.com/jsf/facelets ui Marqueurs pour le support des modèles de page.

http://java.sun.com/jsf/composite composite Sert à déclarer et à définir des nouveaux composants personnalisés.

http://java.sun.com/jsp/jstl/core c Les pages Facelets peuvent éventuellement utiliser certains marqueurs issus de JSP (c:if, c:forEach etc:catch).

http://java.sun.com/jsp/jstl/functions fn Les pages Facelets peuvent utiliser tous les marqueurs de fonctions issus de la technologie JSP.

Bibliothèque core

La bibliothèque core (coeur) contient des balises qui sont indépendante du rendu HTML. Elles sont utiles pour proposer des traitements et des réglages spécifiquespour les balises relatives à la vue (bibliothèque HTML).

Page 30: 08 - JavaServer Faces 2.0

Balises Description

<f:attribute> Propose un attribut particulier (clé/valeur) sur une balise parente.

<f:param> Spécifie un paramètre particulier associé à la chaîne paramétrée proposée par la balise parente.

<f:facet> Gestion d'une zone délimitée de la page Web.

<f:actionListener> Ajoute un événement de type validation sur un composant parent.

<f:setPropertyActionListener> Propose une propriété sur un événement de type validation associé à un composant parent.

<f:valueChangeListener> Ajoute un événement de type changement de valeur sur un composant parent.

<f:phaseListener> Ajoute un événement de type changement de phase sur un composant parent.

<f:event> Ajoute un système d'événement sur un composant parent.

<f:converter> Ajoute un convertisseur personnalisé sur un composant parent.

<f:convertDateTime> Ajoute un convertisseur prédéfini de type date ou heure sur un composant parent.

<f:convertNumber> Ajoute un convertisseur prédéfini numérique sur un composant parent.

<f:validator> Ajoute un validateur personnalisé à un composant parent.

<f:validateDoubleRange> Ajoute un valideur prédéfini qui limite les valeurs numériques réelles sur un composant parent.

<f:validateLength> Ajoute un valideur prédéfini qui limite le nombre de caractères saisie sur un composant parent.

<f:validateLongRange> Ajoute un valideur prédéfini qui limite les valeurs numériques entières sur un composant parent.

<f:validateRequired> Vérifie qu'une valeur est présente sur un composant parent.

<f:validateRegex> Vérifie que la valeur saisie respecte une expression régulière sur un composant parent.

<f:validateBean> Utilise un bean de validation qui impose un certain nombre d'éléments à prendre en compte.

<f:loadBundle> Prise en compte d'une ressource qui propose l'ensemble des messages paramétrés (gestion de la nationalité, par exemple).

<f:selectItems> Propose l'ensemble d'éléments qui vont remplir les radios boutons, les cases à cocher, la liste déroulante, etc.

<f:selectItem> Propose un élément spécifique.

<f:verbatim> Permet de donner le texte qui possède des balises sans interprétation particulière.

<f:viewParam> Défini un paramètre pour la vue qui sera initialisé à l'aide du paramètre de la requête.

<f:ajax> Permet d'implémenter des commandes ajax.

<f:view> Utile si nous désirons prendre en compte la nationalité ou la gestion événementielle de phase.

Nous allons aborder certains de ces marqueurs afin d'expliquer leurs fonctionnement internes :

Attributs, paramètres et facettes

Les balises <f:attribute>, <f:param> et <f:facet> sont généralement proposées pour rajouter des informations sur un composant parent. Chaque composant peutenregistrer un nombre arbitraire de paires nom / valeur.

1. <f:attribute> : Ainsi, à l'aide de cette balise, vous pouvez proposer un attribut particulier dans la page web (la vue) qui sera ensuite exploitée par lemodèle pour réaliser un traitement spécifique :

<h:outputText value="#{agent.téléphone}"> <f:converter converterId="numéroTéléphone" /> <f:param name="séparateur" value="-" /></h:outputText>

Les attributs sont généralement utiles pour les convertisseurs personnalisés. Une fois que l'attribut spécifié est associé à la balise parente,le convertisseur est capable de le retrouver aisément, comme ceci :

séparateur = (String) component.getAttributes().get("séparateur"); // component est issu de la méthode String getAsString(FacesContext context, UIComponent component, Object value)

2. <f:param> : Cette balise permet également de définir une paire nom / valeur. Le nom correspond cette fois-ci plutôt à un numéro, suivant l'ordre oùnous plaçons chacunes des balises <f:param>. Typiquement, cette balise peut être associée à la balise parente <h:outputFormat> comme nousl'avons déjà utilisée dans le projet précédent :

<h:outputFormat value="Tentative{0, choice, 0#|2#s} : "> <f:param value="#{nombre.tentative}" /></h:outputFormat>

Dans ce cas, il n'existe qu'un seul paramètre, correspondant donc à la position 0, et dont la valeur récupérée dans la propriété tentative denombre est soumise à la balise parente afin que son évaluation détermine la mise en place du pluriel ou pas.

3. <f:facet> : Cette balise est utilisée dans des cas très particulier pour spécifier une apparence adaptée. Ainsi, par exemple, dans une page web, nousretrouvons presque systématiquement deux facettes nommées head et body. Typiquement, nous utilisons cette balise presque uniquement pourproposer des facettes différentes à un tableau (<h:dataTable>). Ainsi, nous pouvons proposer un tableau uniforme, ou avec une en-tête, ou avec unpied, ou avec un titre, ou bien avec une combinaison de toutes ces possibilités. Pour obtenir ces différents aspects, vous placez respectivement lesvaleurs header, footer ou caption dans cette balise <f:facet> suivant le cas.

<h:dataTable value="#{auteurs}" var="élément" headerClass="inverse" columnClasses="ligne"> <h:column> <f:facet name="header">Nom</f:facet> #{élément.nom} </h:column> <h:column> <f:facet name="header">Prénom</f:facet> #{élément.prénom} </h:column></dataTable>

Dans ce tableau, par exemple, nous plaçons une en-tête d'une couleur différente que les autres lignes du tableau, dont la premièrecolonne sera intitulé Nom et la deuxième Prénom. Par ailleurs, et de façon automatique, la facette de type header permet de centrer dansla colonne la valeur que nous lui proposons.

Page 31: 08 - JavaServer Faces 2.0

Bibliothèque html

Cette bibliothèque intègre cette fois-ci des composants visuels, qui assurent donc le rendu de la page web. Nous pouvons les regrouper par catégories :

1. Structure de la page HTML (head, body, form, outputStylesheet, outputScript)

2. Dispositions (panelGrid, panelGroup)

3. Tables (dataTable et column)

4. Les entrées : (input...)

5. Les sorties (output...)

6. Les images (graphicImage)

7. Les commandes (commandButton et commandLink)

8. Les requêtes GET HTTP (button, link, outputLink)

9. Les sélections (checkbox, listbox, menu, radio)

10. Messages d'erreur (message, messages)

Nous allons prendre le temps de bien analyser chacun de ces groupes de balises. Au préalable, je vous invite à consulter l'ensemble des attributs qui leurs sontcommuns. Il existe trois types d'attribut :

1. Les attributs de base,

2. Les attributs qui ont leurs correspondances HTML,

3. Les attributs associés aux événements DHTML.

Attributs de base

Dans le tableau ci-dessous, nous découvrons l'ensemble des attributs qui sont partagés par la majorité des marqueurs JSF.

Attributs Description

id Permet d'identifier le composant pour interagir avec un autre.

binding Lie ce marqueur (ce composant dans sa globalité) directement avec le bean géré, et permet donc une interaction en coulisse.

rendered Attribut très intéressant qui permet d'afficher ou pas la balise (équivalent d'un if). Valeurs possibles true ou false.

value Attribut certainement le plus utilisé, qui permet d'être en relation directe avec une propriété particulière du bean géré déterminépar une expression EL (#{bean.propriété}).

valueChangeListener Un écouteur spécifique qui entre en action lors d'un changement de valeur. La méthode désignée dans cet attribut est alorsautomatiquement sollicitée.

converter Mise en relation avec un convertisseur personnalisé (classe qui implémente l'interface Converter) et qui permet de passer d'unechaîne de caractères (seule type compatible avec le protocole HTTP) vers un autre type quelconque et vice versa.

validator Mise en relation avec un validateur personnalisé (classe qui implémente l'interface Validator, ou éventuellement une méthodeavec une signature spécifique) qui permet d'envoyer la valeur désignée dans l'attribut value au bean géré (qui travaille encoulisse) que si la valeur est correcte.

required Une valeur est impérativement requise dans ce champ pour passer la phase de validation.

converterMessage,validatorMessage,requiredMessage

Messages personnalisés qui s'affichent automatiquement (en relation avec les balises <h:message> ou <h:messages>) lorsque unproblème survient lors de la phase de conversion, de validation ou lorsque q'une valeur de saisie est oubliée.

1. Tous les composants, quels qu'ils soient, peuvent utiliser les attributs id, binding et rendered que nous allons tout de suite analyser.

2. Les attributs value et converter permettent, de concert, de spécifier comment la propriété du bean proposée puisse être automatiquement convertiesous forme de chaîne de caractères, afin d'être transmis correctement par le protocole HTTP pour la vue, et comment, en coulisse avec le modèle,manipuler cette propriété par le bean géré pour travailler directement avec le type adéquat.

3. Enfin, les attributs validator, required et valueChangeListener sont disponibles pour les composants de saisie (Entrées) qui réalisent un contrôle desvaleurs saisies afin de faire réagir éventuellement l'opérateur pour qu'il corrige le tir afin que ces dernières soient finalement considérées commevalides pour le traitement souhaité.

Identification et liaisons entre composantsL'attribut polyvalent id permet de réaliser les choses suivantes :

1. L'accès au composant identifié par un autre composant de la page web. L'exemple très fréquent consiste à identifier un composant d'entrée afind'afficher un message d'erreur adapté au cas où la saisie ne serait pas correcte :

<h:inputText value="#{conv.euro}" id="euro" converterMessage="Il faut une valeur monétaire" validatorMessage="Uniquement les nombres positifs" required="true" requiredMessage="Précisez votre valeur monétaire"> <f:convertNumber type="currency" currencySymbol="€"/> <f:validateDoubleRange minimum="0.0" /></h:inputText> <h:message for="euro" styleClass="erreur"/>

2. Obtenir en coulisse les références de ce composant dans le code Java du bean géré. Par exemple, si nous désirons accéder au composant désignépar euro au travers d'un écouteur, voici ce que nous pouvons écrire :

UIComponent composant = event.getComponent().findComponent("euro");

Attention, pour que ce code soit exploitable, le composant qui génère l'événement doit se trouver dans le même formulaire (<h:form>)

Page 32: 08 - JavaServer Faces 2.0

que le composant identifié, sinon le composant ne sera pas accessible.

3. Accès aux éléments HTML au travers de scripts.

Il existe une autre démarche pour accéder à un composant de la vue depuis le code Java. Il suffit de définir une propriété dans le modèle et ensuite despécifier l'attribut binding du composant en connexion avec cette propriété particulière.

<h:inputText binding="#{beanGéré.propriété}" ... />

L'attribut binding est spécifié à l'aide d'une expression EL. Cette expression, comme d'habitude fait référence à une propriété particulière du bean géré,qui d'ailleurs doit être à la fois accessible en lecture et en écriture.

private UIComponent propriété = new UIInput(); // création d'un objet qui correspond au type du composant visuel à représenterpublic UIComponent getPropriété() { return propriété; }public void setPropriété(UIComponent propriété) { this.propriété = propriété; }

Nous pourrions nous poser la question sur l'intérêt d'un tel attribut binding puisque value est généralement suffisant. Dans des cas très particulier, ilpeut être intéressant de faire référence au composant de la vue dans son ensemble plutôt que de rester uniquement sur la propriété, interne donc aubean. Nous pourrions du coup envisager de faire du traitement spécifique sur ce composant visuel pour faire en sorte qu'il soit par exemple nonéditable, non visible, grisé, etc. directement depuis le bean géré.

Effectivement, tous les composant visuels sont avant tout des classes avec donc leurs propres méthodes. il suffit de faire appel à ces méthodes pourchanger le comportement de ces éléments visuel, en coulisse, directement depuis le modèle.

Valeurs, convertisseurs et validateursLes entrées, les sorties, les commandes et tables de données manipulent toutes des valeurs. L'attribut value permet d'être en relation avec ces valeurs. Il peuts'agir d'une valeur littérale comme d'une valeur issue d'une propriété :

<h:commandButton value="Intitulé du bouton" ... /><h:inputText value="#{beanGéré.propriété}" ... />

1. L'attribut converter, proposé pour les balises d'entrée et de sortie, permet de rattacher un convertisseur personnalisé à un composant.

2. Les balises d'entrée peuvent également proposée l'attribut validator afin de rattacher un validateur personnalisé à un composant.

3. Ces convertisseurs et validateurs sont bien utiles afin d'éviter que le bean géré ne rentre dans sa phase de traitement d'informations tant que lesvaleurs proposées ne sont pas valides.

Rendu conditionnelVous pouvez utiliser l'attribut rendered pour inclure ou exclure des composants dans votre page web, d'avoir ainsi un rendu conditionnel. Par exemple, nouspourrions afficher un bouton de déconnexion que si nous sommes sûr que l'utilisateur s'est déjà logger :

<h:commandButton value="Deconnexion" rendered="#{utilisateur.connecté}" action="#{utilisateur.seDéconnecter}" /><h:inputText... />

La condition du rendu peut s'appliquer sur un groupe de composants, au travers des balises <h:panelGrid> ou <h:panelGroup> qui possèdent cetattribut rendered.

<h:pannelGrid columns="2" rendered="#{bean.ongletSélectionné == 'vidéo'}"> <h:outputText... /> <h:commandButton... /> ...</h:pannelGrid>

Attributs HTML

Ces types d'attributs sont particuliers puisqu'ils ne sont pas interprétés par les composants JSF mais sont directement traduits dans les balises HTMLcorrespondantes. Il s'agit exactement des mêmes attributs qui sont proposés par les balises HTML standard.

<h:inputText size="25" value="#{bean.propriété}" /> // code proposé en JSF...<input size="25" type="text" ... /> // balise générée automatiquement par le système pour l'envoyer ensuite au client

Ainsi, par exemple, si nous proposons l'attribut size à une balise JSF, nous la retrouvons ensuite intégralement, sans interprétation particulière, dansla balise HTML équivalente. Rappelez vous que la vue JSF reste sur le serveur et que le document envoyé est une page web avec des balises HTMLstandard (le client n'a besoin d'installer de pluggin particulier, un simple navigateur suffit).

Attributs Description

alt Prévoit un texte alternatif dans le cas où une image par exemple n'est pas présente.

border Largeur de bordure en pixel.

dir Direction du texte. Les valeurs valides sont "LTR" (Left To Right) et "RTL" (Right To Left).

disabled Permet de grisé un élément pour le rendre inactif à l'image des zones de saisie et des boutons de commande.

maxlength Spécifie le nombre maximum de caractères possible sur une zone de saisie.

readonly Empêche de réaliser une édition sur une zone de saisie.

rows Spécifie le nombre de lignes pour une zone de texte.

size Taille pour une zone de saisie.

style Possibilité d'introduire un style CSS uniquement sur cette balise.

styleClass Propose un style CSS prédéfini dans une feuille de style séparée.

title Description du marqueur qui typiquement est traduit sous forme de bule d'aide par les navigateurs.

width Largeur en pixels de ce composant.

Styles CSS

Page 33: 08 - JavaServer Faces 2.0

Nous pouvons donc introduire des styles CSS, soit directement (attribut style), soit à partir d'une déclaration déjà faite antérieurement (attributstyleClass) qui influence, bien entendu, le rendu du composant.

<h:inputText styleClass="bordure" value="#{bean.propriété}" /><h:inputText style="border: thin solid blue" value="#{bean.propriété}" />

Gestion des ressourcesLa plupart des composants ont besoin de ressources externes pour s'afficher correctement : <h:graphicImage> a besoin d'une image, <h:commandButton>peut également afficher une image pour représenter le bouton, <h:outputScript> référence un fichier JavaScript et surtout les composants peuvent égalementappliquer des styles CSS.

Avec JSF, une ressource est un élément statique qui peut être transmis aux éléments afin d'être affiché (images) ou traité (CSS) par le navigateur. JSF2.0 permet d'assembler directement les ressources dans un fichier jar séparé, avec un numéro de version et une locale, et de les placer à la racine del'application web, sous le répertoire suivant :

resources/<identifiant_ressource>ouMETA-INF/resources/<identifiant_ressource>

<identifiant_ressource> est formé de plusieurs sous-répertoire indiqués sous la forme :

[locale/ ] [nomBibliothèque/ ] nomRessource [ /versionRessource]

Tous les éléments entre crochets sont facultatifs. La locale est le code du langage, suivi éventuellement d'un code de pays (en, en_US, pt,pt_BR). Comme l'indique cette syntaxe, vous pouvez ajouter un numéro de version à la bibliothèque ou à la ressource elle-même.

Voici quelques exemples :

resources/css/principal.cssresources/images/logo.pngresources/javascript/jsf.js

Voici maintenant comment prendre en compte ces différentes ressources :

<h:outputStylesheet library="css" name="principal.css" /><h:outputScript library="javascript" name="jsf.js" target="head" /><h:graphicImage library="images" name="logo.png" />

Evénements DHTML

Il est possible de rajouter un comportement plus dynamique sur vos pages web, comme des animations ou la prise en compte en temps réel d'un certainnombre d'événements. C'est ce que nous appelons communément le DHTML. En réalité, en coulisse, dès que nous évoquons des pages DHTML, nous faisonsréférence à du javascript.

Tous ces événement javascript sont disponibles sur chacun des composants JSF au travers d'attributs spécifiques dont voici la liste. Vous devezpréciser ensuite l'action que vous désirez réaliser à l'issu de ces événements.

Attributs Description

onblur L'élément perd le focus.

onchange La variable de la zone de saisie change de valeur.

onclick Prise en compte du clic de la souris.

ondblclick Prise en compte du double clic de la souris.

onfocus L'élément reprend le focus.

onkeydown L'opérateur est en train d'appuyer sur une touche.

onkeypress L'opérateur tape sur une touche.

onkeyup L'opérateur relache une touche.

onload Au moment où la page est chargée.

onmousedown En train d'appuyer sur un bouton de la souris.

onmousemove La souris se déplace sur l'élément.

onmouseout La souris sort de la zone de l'élément.

onmouseover La souris passe au dessus de l'élément.

onmouseup On relache un bouton de la souris

onreset Le formulaire est remise à zéro.

onselect Texte sélectionné dans une zone de saisie.

onsubmit Le formulaire est envoyé pour traitement.

onunload Au moment où nous quittons la page en cours.

Structure de la page HTML (<h:head>, <h:body>, <h:form>, <h:outputScript>, <h:outputStylesheet>)

Tous ces marqueurs n'ont pas de représentation graphiques mais possèdent un équivalent HTML (voir tableau ci-dessous). Bien que les marqueurs natifsHTML puissent être utilisés directement sans problème, les marqueurs JSF possèdent des attributs supplémentaires qui facilitent le développement.

Vous pouvez, par exemple, ajouter une bibliothèque JavaScript à l'aide du marqueur HTML Standard <script type="text/JavaScript">, mais lemarqueur <h:outputScript library="javascript" name="jsf.js" target="head" /> de JSF permet d'utiliser la nouvelle gestion des ressources, comme nousvenons de le découvrir plus haut.

Balises Description

<h:body> Génère un élément <body> HTML.

<h:head> Génère un élément <head> HTML.

<h:form> Génère un élément <form> HTML.

<h:outputScript> Génère un élément <script> HTML.

<h:outputStylesheet> Génère un élément <link> HTML.

Page 34: 08 - JavaServer Faces 2.0

<h:outputStylesheet> Génère un élément <link> HTML.

Typiquement, les applications web fonctionnent en soumettant des requêtes issues d'un formulaire. JSF n'échappe pas à cette règle de base et doitproposer au moins une balise <h:form>.

1. Bien que la balise <form> du HTML standard propose les attributs method et action qu'il est nécessaire de spécifier, le marqueur équivalent JSF<h:form> n'a pas besoin de ce genre d'informations.

2. Il faut dire que dans le cas de JSF, l'attribut action n'a pas de sens puisque le traitement souhaité par les requêtes issues de ce formulaire peuventéventuellement être réalisé par plusieurs beans gérés.

3. Comme nous pouvons sauvegarder l'état complet d'un ou plusieurs beans gérés chez le client, une option qui s'implémente au travers de champscachés, les soumissions de formulaire ne peuvent être effectuées par la méthode GET HTTP.

4. Effectivement, le contenu de ces champs cachés peut dépasser largement les capacités du buffer relatif à l'envoi de la requête, aussi les formulairesJSF sont toujours implémentés à l'aide des méthodes POST HTTP.

Grilles et tableaux

Les données doivent souvent être affichées sous forme de tableau. JSF fournit donc le marqueur <h:dataTable> permettant ainsi de parcourir une listed'éléments (dont la taille est variable) afin de générer automatiquement un tableau. Les tableaux peuvent également servir de gestion de disposition descomposants afin de créer une interface utilisateur sous forme de grille. Dans ce cas, vous pouvez utiliser les marqueurs <h:panelGrid> et <h:panelGroup>pour disposer les composants à votre guise.

Balises Description

<h:dataTable> Représente un ensemble de données qui seront affichés dans un élément <table> HTML.

<h:column> Produit une colonne de données dans un composant <h:dataTable>.

<h:panelGrid> Produit également un élément <table> HTML.

<h:panelGroup> Conteneur de composants pouvant s'imbriquer dans un <h:panelGrid>.

Les tableaux dynamiques composés de la balise <h:dataTable> et des balises <h:column> feront parti d'un chapitre à part entière au cours de cetteétude.

A la différence de <h:dataTable>, le marqueur <h:panelGrid> n'utilise pas de modèle de données sous-jacent pour produire des lignes de données -c'est un conteneur permettant d'insérer les autres composants JSF dans une grille de lignes et de colonnes.

Vous pouvez préciser le nombre de colonnes que comportera cette grille de disposition à l'aide de l'attribut column. <h:panelGrid> détermineraautomatiquement le nombre de lignes nécessaire suivant le nombre de composants introduits. Il place alors les composants dans l'ordre précisé de lagauche vers la droite et du haut vers le bas.

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">

<h:body style="background-color: orange"> <h:form> <h:outputText value="Identification" /> <hr /> <h:panelGrid columns="2" border="1"> <h:outputText value="Nom :" /> <h:inputText value="" /> <h:outputText value="Prénom :" /> <h:inputText value="" /> <h:outputText value="Mot de passe :" /> <h:inputSecret value="" /> </h:panelGrid> <hr /> <h:commandButton value="Connexion" /> </h:form> </h:body></html>

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">

<h:body style="background-color: orange"> <h:form> <h:outputText value="Identification" /> <hr /> <h:panelGrid columns="2"> <h:outputText value="Nom :" /> <h:inputText value="" /> <h:outputText value="Prénom :" /> <h:inputText value="" /> <h:outputText value="Mot de passe :" /> <h:inputSecret value="" /> </h:panelGrid> <hr /> <h:commandButton value="Connexion" /> </h:form> </h:body></html>

Pour combiner plusieurs composant dans la même colonne, utilisez un <h:panelGroup> qui produira ses fils comme un seul et unique composant.Vous pouvez également définir un en-tête et un pied à l'aide du marqueur spécial <f:facet>.

Page 35: 08 - JavaServer Faces 2.0

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <style type="text/css"> body {background-color: green; color: yellow; } .ligne {background-color: #005500; } .saisie {background-color: greenyellow; } </style>

<h:body> <h:form> <h:panelGrid columns="2" styleClass="ligne"> <f:facet name="header"> <h:outputText value="Identification" /> </f:facet> <h:outputText value="Nom :" /> <h:inputText value="" styleClass="saisie"/> <h:outputText value="Prénom :" /> <h:inputText value="" styleClass="saisie" /> <h:outputText value="Mot de passe :" /> <h:panelGroup> <h:inputSecret value="" styleClass="saisie" /> <h:outputText value=" (4 mini)" /> </h:panelGroup> <f:facet name="footer"> <h:commandButton value="Connexion" /> </f:facet> </h:panelGrid> </h:form> </h:body></html>

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <style type="text/css"> body {background-color: green; color: yellow; } .cadre {background-color: #005500; } .ligne {background-color: #007000; } .saisie {background-color: greenyellow; } </style>

<h:body> <h:form> <h:panelGrid columns="2" rowClasses="ligne" footerClass="cadre" headerClass="cadre"> <f:facet name="header"> <h:outputText value="Identification" /> </f:facet> <h:outputText value="Nom :" /> <h:inputText value="" styleClass="saisie"/> <h:outputText value="Prénom :" /> <h:inputText value="" styleClass="saisie" /> <h:outputText value="Mot de passe :" /> <h:panelGroup> <h:inputSecret value="" styleClass="saisie" size="12"/> <h:outputText value=" (4 mini)" /> </h:panelGroup> <f:facet name="footer"> <h:commandButton value="Connexion" /> </f:facet> </h:panelGrid> </h:form> </h:body></html>

Il est possible de rajouter des styles personnalisés sur différentes partiesde la table :

1. La table dans son entier avec l'attribut styleClass.

2. L'entête avec l'attribut headerClass.

3. Le pied avec l'attribut footerClass.

4. Les lignes avec l'attribut rowClasses.

5. Les colonnes avec l'attribut columnClasses.

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <style type="text/css"> body {background-color: green; color: yellow; } .cadre {background-color: #005500; } .ligne {background-color: #007000; } .saisie {background-color: greenyellow; } </style>

<h:body> <h:form> <h:panelGrid columns="2" rowClasses="ligne, cadre" footerClass="cadre" headerClass="cadre"> <f:facet name="header"> <h:outputText value="Identification" /> </f:facet> <h:outputText value="Nom :" /> <h:inputText value="" styleClass="saisie"/> <h:outputText value="Prénom :" /> <h:inputText value="" styleClass="saisie" />

Vous remarquez que les attributs rowClasses et columnClasses possèdentun "s" à la fin, contrairement aux autres. Cette particularité est importantepuisqu'il est possible de proposer plusieurs styles pour le même attribut.L'intérêt ici est de permettre une alternance de couleurs entre les lignesou les colonnes à l'image de certains listings.

Page 36: 08 - JavaServer Faces 2.0

<h:outputText value="Mot de passe :" /> <h:panelGroup> <h:inputSecret value="" styleClass="saisie" size="12"/> <h:outputText value=" (4 mini)" /> </h:panelGroup> <f:facet name="footer"> <h:commandButton value="Connexion" /> </f:facet> </h:panelGrid> </h:form> </h:body></html>

Les entrées

les entrées sont des composants qui affichent leur valeur courante (actuelle) et permettent à l'utilisateur de saisir différentes informations textuelles. Il peuts'agir de champs de saisie, de zone de texte ou de composants pour entrer un mot de passe ou des données cachées.

Balises Description

<h:inputHidden> Représente un élément d'entrée HTML de type caché (non affiché).

<h:inputSecret> Représente un élément d'entrée HTML de type mot de passe. Pour des raisons de sécurité, tout ce qui est saisi ne s'affiche pas (despoints apparaissent à la place de chaque caractère introduit), sauf si la propriété redisplay vaut true.

<h:inputText> Représente un élément d'entrée HTML de type texte.

<h:inputTextarea> Représente une zone de texte HTML.

De nombreuses pages web contiennent des formulaires pour que l'utilisateur puisse saisir des données ou se connecter en fournissant un mot depasse. En outre les composants d'entrée utilisent plusieurs attributs permettant de modifier leur longueur, leur contenu ou leur aspect.

Attributs Description

cols Nombre de colonnes, utile uniquement pour la balise <h:inputTextarea>.

immediate Permet de passer outre les phases de conversion et de validations.

redisplay Uniquement pour la balise <h:inputSecret>. Lorsque cet attribut est validé (true), la valeur du champ est réaffichée aurecharchement de la page.

required Une valeur est impérativement requise dans ce champ pour passer la phase de validation.

rows Nombre de lignes, utile uniquement pour la balise <h:inputTextarea>.

label Description du composant lorsqu'un message d'erreur est sollicité. Ne s'applique pas à la balise <h:inputHidden>.

valueChangeListener Un écouteur spécifique qui entre en action lors d'un changement de valeur.

<h:inputHidden value="#{bean.valeurCachéeRécupérée}" /><h:inputSecret value="#{bean.motDePasse}" maxlength="8" /><h:inputText value="#{bean.propriété}" /><h:inputText value="#{bean.propriété}" size="40" /><h:inputTextarea value="#{bean.propriété}" rows="5" cols="20" />

1. Tous les composants possèdent un attribut value pour fixer leur valeur par défaut, et surtout pour enregistrer la valeur saisie dans la propriétéchoisie. Ce qui sous-entend que la propriété doit impérativement être accessible à la fois en lecture et en écriture. Les attributs immediate, requiredet valueChangeListener existent pour tous ces marqueurs d'entrée.

2. L'attribut maxLength permet de s'assurer que le texte ne dépasse pas une longueur donnée et l'attribut size modifie la taille par défaut ducomposant. (voici ci-dessous l'apparence du code proposé).

3.

4. Trois attributs sont spécifiques à un seul marqueur. Il s'agit de cols et rows qui permettent de proposer une dimension (un nombre de lignes et decolonnes) à la balise <h:inputTextArea>. Le dernier attribut est redisplay qui est éventuellement utilisé par la balise <h:inputSecret>. Cet attributprend une valeur booléenne qui permet, en cas de validation, de retenir le mot de passe pour qu'il soit automatiquement reproposer (de façoncaché, bien évidemment) à la prochaine demande de connexion.

<html xmlns="http://www.w3.org/1999/xhtml"

Page 37: 08 - JavaServer Faces 2.0

xmlns:h="http://java.sun.com/jsf/html">

<h:body style="background-color: green; color: yellow; font-weight: bold"> <h:form> <h:panelGrid columns="2"> <h:outputText value="Lecture seule :" /> <h:inputText value="#{test.valeur}" readonly="true"/> <h:outputText value="Réaffichage du mot de passe :" /> <h:inputSecret value="#{test.motPasse}" redisplay="true" /> <h:outputText value="Pas de réaffichage :" /> <h:inputSecret value="#{test.motPasse}" redisplay="false" /> <h:outputText value="Style personnalisé :" /> <h:inputText value="#{test.valeur}" style="background: yellow; color: green"/> <h:outputText value="Taille limite :" /> <h:inputText value="#{test.valeur}" size="5"/> <h:outputText value="Nombre de caractères limités :" /> <h:inputText value="#{test.valeur}" size="10" maxlength="6" /> </h:panelGrid> <hr /> <h:commandButton value="Soumettre" /> </h:form> </h:body></html>

JSF supporte les champs cachés à l'aide du marqueur <h:intputHidden>. Les champs cachés sont souvent utilisés avec des actions JavaScript pourinteragir avec le serveur.

Les sorties

Les composants de sortie affichent une valeur qui peut éventuellement avoir été obtenue à partir d'un bean géré, une valeur issue d'une expression ELquelconque ou un simple texte littéral. L'utilisateur ne peut pas modifier ce contenu car il est bien entendu en lecture seule.

Balises Description

<h:outputLabel> Génère une balise <label> HTML.

<h:outputLink> Génère une balise <a> HTML.

<h:outputText> Génère tout simplement un texte littéral.

<h:outputFormat> Génère un texte littéral paramétré.

<h:graphicsImage> Génère une balise <img> HTML.

La plupart des pages web affichent du texte. Pour ce faire, vous pouvez utiliser des balises HTML classiques mais, grâce à EL, les marqueurs de sortiede JSF permettent d'afficher le contenu d'une propriété liée à un bean géré.

<h:outputText>La balise <h:outputText> est certainement le marqueur le plus simple de JSF. Avec une simple poignée d'attributs, il ne génère aucune balise HTMLparticulière. Il produit un simple texte. Il existe toutefois une seule exception à cette règle. En effet, lorsque nous demandons à prendre en compte un styleCSS, au travers des attributs style ou styleClass, la balise <h:outputText> génère alors, comme nous nous en doutons, une balise <span>.

Depuis la version JSF 2.0, vous n'êtes pas obligé d'utiliser la balise <h:outputText> pour afficher le contenu d'une propriété. Il est possible de s'enpasser et d'écrire directement l'expression EL : #{bean.propriété}, par exemple. Vous devez toute de même utiliser cette balise dans les circonstancessuivantes :

1. Pour générer une sortie avec la prise en compte de styles CSS.

2. Lorsque vous utilisez un panneau pour être sûr que le texte soit considéré comme une cellule à part entière.

3. Pour générer impérativement une balise HTML.

Les balises <h:outputText> <h:outputLabel> et <h:outputFormat> possèdent un attribut très particulier qui n'existe que pour ces trois marqueurs. Ils'agit de l'attribut escape, qui par défaut prend la valeur true, et qui permet automatiquement de transformer les caractères < > et & respectivement en&lt; &gt; et &amp; afin de conserver l'affichage original. Vous devez positionner cet attribut à false si vous désirez générer des balises HTML parprogramme.

<h:outputFormat>La balise <h:outputFormat> permet de composer des messages paramétrés à l'image de la classe MessageFormat. En interne, la balise <h:outputText> utiliseeffectivement cette classe. Vous devez ensuite spécifier vos différents paramètres à l'aide des balises <f:param>.

<h:outputFormat value="Il reste {0} jour{0, choice, 0#|2#s}" style="color: green"> <f:param value="#{gestionEmprunts.emprunt.joursRestant}" /></h:outputFormat>

Dans ce code, le message utilise un seul paramètre qui détermine le nombre de jour restant avant de rendre le document emprunté dans unebibliothèque. Rappelez-vous que la numérotation du paramètre commence toujours par 0. Remarquez au passage comment faire en sorte que lepluriel soit pris en compte.

<h:outputLabel>La balise <h:outputLabel> est la représentation exacte de l'équivalent <label> du HTML. Cette balise meconnue permet d'améliorer grandement l'ergonomiede vos formulaires. Elle permet, par exemple, de cocher un élément de type radio bouton ou de case à cocher par un clic sur le texte qui lui est joint.

De façon plus générale, la balise <h:outputLabel> permet de rattacher une information à un contrôle par le biais d'une étiquette. Comme autreexemple, elle peut être utilisé dans les formulaires pour mettre en relation une zone de saisie et son descriptif. Dans la pratique, cette relationentre <h:outputLabel> et <h:inputText> peut se faire en liant l'attribut for du LABEL à l'attribut id de l'élément INPUT.

<h:outputLabel value="Identifiant : " for="identifiant" /><h:inputText value="#{test.identifiant}" id="identifiant" /><h:outputLabel value="Mot de passe : " for="passe" />

<h:inputSecret value="#{test.motPasse}" id="passe" />

Page 38: 08 - JavaServer Faces 2.0

<h:inputSecret value="#{test.motPasse}" id="passe" /><h:selectBooleanCheckbox id="choix"> <h:outputLabel value="Sélectionner le texte ou la case" for="choix" /></h:selectBooleanCheckbox>

Les graphiques

Il n'existe qu'un seul composant pour afficher les images <h:graphicsImage>. Ce marqueur génère un élément <img> HTML pour afficher une image que lesutilisateurs n'auront pas le droit de manipuler. Ses différents attributs permettent de modifier la taille de l'image, de l'utiliser comme image cliquable, etc. Uneimage peut être liée à une propriété d'un bean géré et provenir d'un fichier sur le système ou d'une base de données.

Vous pouvez spécifier la localisation de l'image avec les attributs url ou value relativement au placement de l'image dans votre application web. Deplus, depuis la version 2.0 de JSF, il est souhaitable de placer vos images comme ressource dans une librairie prévue à cet effet.

<h:graphicsImage library="images" name="logo.gif" /><h:graphicsImage url="/resources/images/logo.gif" /><h:graphicsImage value="#{bean.logo}" />

Ces trois exemples réalise en réalité le même traitement, celui d'afficher le logo qui se trouve dans le sous-répertoire images qui se trouve lui-mêmedans le répertoire resources.

Les commandes - boutons et hyperliens

Les commandes sont les contrôles sur lesquels l'utilisateur peut cliquer pour déclencher une action. Ces composants sont généralement représentés sousforme de boutons ou de liens hypertextes spécifiés par les marqueurs suivants :

Balises Description

<h:commandButton> Représente un élément HTML pour un bouton de type submit ou reset. La méthode HTTP de la requête est de type POST.

<h:commandLink> Représente un élément HTML pour un lien agissant comme un bouton submit. Ce composant doit être placé dans un formulaire. Laméthode HTTP de la requête est de type POST.

<h:button> Ce composant est similaire au marqueur <h:commandButton> mais c'est La méthode GET HTTP qui est propsée pour soumettre larequête.

<h:link> Ce composant est similaire au marqueur <h:commandLink> mais c'est La méthode GET HTTP qui est propsée pour soumettre larequête.

<h:outputLink>Génère une balise <a> HTML. A la différence de <h:commandLink>, il n'est pas nécessaire de placer cette balise dans unformulaire, il s'agit d'un simple lien statique sans interprétation particulière pas JSF, ni d'appel de méthode spécifique du beangéré.

1. Par défaut, un <h:commandButton> est de type submit. A l'image du HTML, nous pouvons prévoir un bouton de réinitialisation du formulaire aumoyen de l'attribut type.

2. L'attribut value permet de renseigner l'intitulé du bouton. Vous avez aussi la possibilité d'utiliser une image comme bouton. Dans ce cas ne prenezplus l'attribut value, mais plutôt l'attribut image pour indiquer le chemin d'accès du fichier image que vous souhaitez afficher.

3. Les boutons et les liens possèdent tous les deux un attribut action qui permet soit de naviguer vers une nouvelle page, soit d'appeler une méthodespécifique du bean géré afin de réaliser un traitement particulier (qui elle-même peut proposer une navigation vers une autre page).

<h:commandButton value="Valider votre commande" action="#{bean.validation}" /><h:commandButton value="Réinitialiser le formulaire" type="reset" /><h:commandButton image="image.png" action="page.xhtml" /><h:commandLink value="Naviguer vers votre nouvelle page" action="#{bean.méthode}" /><h:commandLink value="Naviguer vers votre nouvelle page" action="page.xhtml" />

1. Les balises <h:commandButton> et <h:commandLink> sont certainement les composants principaux que nous utiliserons pour la navigation dansune application JSF, soit respectivement sous l'apparence d'un bouton ou sous l'apparence d'un hyperlien. Lorsque un bouton ou un lien est activé,une requête POST est soumise et les données du formulaire sont envoyées au serveur d'applications.

2. JSF 2.0 introduit les composants <h:button> et <h:link>. Ces balises donnent le même rendu que les précédentes, savoir un bouton et un lien, maislorsque nous cliquons sur un de ces composant, c'est cette fois-ci une requête GET qui est alors soumise au serveur d'applications.

3. La balise <h:outpuLink> quant à elle génère une simple balise <a> HTML qui permet alors de pointer vers une ressource comme une image ou uneautre page web. Cliquer sur ce type de lien nous renvoie directement sur la ressource désignée sans aucune interprétation particulière du frameworkJSF. Ce type de lien est intéressant lorsque vous désirez naviguer vers différents sites web.

Attributs Description

action(<h:commandButton> et <h:commandLink> uniquement) Si vous proposez une chaîne de caractères à cet attribut, c'est que vous désignez la nouvelle page web à atteindre instantanément lorsquel'utilisateur clique sur un de ces composants.Si vous spécifiez une méthode d'un bean au travers d'une expression EL, la méthode est alors exécutée lorsque l'utilisateur clique sur unde ces composants. Si cette méthode renvoie une chaîne de caractères, elle doit alors correspondre à l'identification de la nouvelle page àatteindre.Si vous n'utilisez pas cet attribut, c'est la page web en cours qui est réaffichée lorsque l'utilisateur clique sur un de ces composants.

outcome (<h:button> et <h:link> uniquement) indique la prochaine cible à atteindre lorsque le composant s'affichera.

fragment (<h:button> et <h:link> uniquement) Un fragment qui se rajoute à l'URL cible. Le séparateur # est automatiquement appliqué et vousn'avez pas besoin de l'inclure dans votre fragment.

actionListener Prise en compte d'un événement de type action et lance la méthode du bean proposée - méthode(ActionEvent)

image (<h:commandButton> et <h:button> uniquement) L'image proposée s'affiche à la place du rendu classique d'un bouton.

immediate La valeur attendue est de type booléen. La valeur par défaut est false. Dans ce cas là, les actions et les événements sont pris en compteuniquement à la fin du cycle de vie, c'est-à-dire après les phases de conversion et de validation. Si par contre, vous proposez la valeurtrue, les actions et les événements sont pris en compte immédiatement.

type Pour <h:commandButton> les types prévus sont : button, submit et reset. Par défaut, sauf si vous spécifiez l'attribut image, est submit.Pour <h:commandLink> et <h:link> : correspond au type MIME (type de ressource), text/html, image/gif ou audio/basic par exemple.

value Intitulé du bouton ou du lien. Cela peut être une chaîne de caractères ou une expression EL.

Page 39: 08 - JavaServer Faces 2.0

Les sélections

Les composants de sélection permettent de choisir une ou plusieurs valeurs dans une liste. Graphiquement, ils sont représentés par des cases à cocher, desboutons radio, des listes ou des combos box.

Balises Description

<h:selectBooleanCheckbox> Génère une case à cocher représentant une valeur booléenne unique. Cette cas sera initailement cochée ou décochée selonla valeur de sa propriété checked.

<h:selectManyCheckbox> Génère une liste de cases à cocher.

<h:selectManyListBox> Génère un composant à choix multiples, dans lequel nous pouvons choisir une ou plusieurs options.

<h:selectManyMenu> Génère une balise <select> HTML.

<h:selectOneListBox>Génère un composant à choix unique, dans lequel nous ne pouvons choisir qu'une seule option.

<h:selectOneMenu> Génère un composant à choix unique, dans lequel nous ne pouvons choisir qu'une seule option. N'affiche qu'une option àla fois.

<h:selectOneRadio> Génère une liste de boutons radio.

Les marqueurs de ce tableau ont une représentation garphique, mais ils ont besoin d'imbriquer d'autres marqueurs (<f:selectItem> ou <f:selectItems>)pour obtenir l'ensemble des valeurs disponibles.

<h:selectOneMenu value="#{test.semaine}"> <f:selectItem itemValue="Lundi" /> <f:selectItem itemValue="Mardi" /> <f:selectItem itemValue="Mercredi" /> <f:selectItem itemValue="Jeudi" /> <f:selectItem itemValue="Vendredi" /> <f:selectItem itemValue="Samedi" /> <f:selectItem itemValue="Dimanche" /> </h:selectOneMenu>

Attributs Description

enabledClass,disabledClass (<h:selectOneRadio> et <h:selectManyCheckbox> uniquement) Possibilité de placer des styles CSS sur la prise en compte ou pas

de cet élément.

selectedClass,unselectedClass

(<h:selectManyCheckbox> uniquement) Possibilité de placer des styles CSS sur la prise en compte de la sélection ou pas de cetélément.

layout (<h:selectOneRadio> et <h:selectManyCheckbox> uniquement) Spécification qui détermine l'orientation de l'ensemble des casesà cocher ou des boutons radio lineDirection (horizontal) ou pageDirection (vertical)

label Description du composant utilisable lors d'un message d'erreur.

collectionType (<h:selectMany...> uniquement) Une chaîne de caractères ou une expression EL qui identifie une collection.

hideNoSelectionOption Cache tous les éléments qui sont désignés comme "aucune sélection" noSelectionOption dans les balise <f:selectItem>.

<h:selectBooleanCheckbox value="#{test.validation}" id="validation"> <h:outputLabel value="Contactez-moi " for="validation" /></h:selectBooleanCheckbox>

@ManagedBeanpublic class Test { private boolean validation;

public boolean isValidation() { return validation; }

public void setValidation(boolean validation) { this.validation = validation; }}

Cette balise représente une seule case à cocher qui doit êtrerattachée à une propriété booléenne.

<h:selectManyCheckbox value="#{test.couleurs}"> <f:selectItem itemLabel="Rouge" itemValue="Color.RED"/> <f:selectItem itemLabel="Jaune" itemValue="Color.YELLOW" /> <f:selectItem itemLabel="Bleu" itemValue="Color.BLUE" /> <f:selectItem itemLabel="Vert" itemValue="Color.GREEN" /> <f:selectItem itemLabel="Orange" itemValue="Color.ORANGE" /></h:selectManyCheckbox><hr /><h:commandButton value="Choisissez vos couleurs" /><hr /><h:dataTable value="#{test.couleurs}" var="couleur"> <h:column>#{couleur}</h:column></h:dataTable><hr />

@ManagedBeanpublic class Test { private ArrayList<Color> couleurs = new ArrayList<Color>();

public ArrayList<Color> getCouleurs() { return couleurs; }

public void setCouleurs(ArrayList<Color> couleurs) {

Vous avez la possibilité de regrouper un ensemble de cases àcocher à l'aide de cette balise. Cela implique qu'il est possiblede sélectionner plusieurs éléments, et la valeur de la propriétédoit correspondre à une collection.

La balise <f:selectItem> possède deux attributs. Le premier,itemValue représente la valeur de l'élément. Le deuxième,itemLabel représente l'intitulé. Vous ne l'utilisez que dans le

cas où ce dernier est différent de la valeur.

Page 40: 08 - JavaServer Faces 2.0

this.couleurs = couleurs; }}

cas où ce dernier est différent de la valeur.

<h:panelGrid columns="2" border="1" cellspacing="0"> <h:panelGroup> <h:selectManyCheckbox value="#{test.couleurs}" layout="pageDirection" > <f:selectItem itemLabel="Rouge" itemValue="Color.RED"/> <f:selectItem itemLabel="Jaune" itemValue="Color.YELLOW" /> <f:selectItem itemLabel="Bleu" itemValue="Color.BLUE" /> <f:selectItem itemLabel="Vert" itemValue="Color.GREEN" /> <f:selectItem itemLabel="Orange" itemValue="Color.ORANGE" /> </h:selectManyCheckbox> </h:panelGroup> <h:panelGroup> <h:commandButton value="Choisissez vos couleurs" /> <hr /> <h:dataTable value="#{test.couleurs}" var="couleur"> <h:column>#{couleur}</h:column> </h:dataTable> </h:panelGroup></h:panelGrid>

Il est possible de choisir l'orientation des cases à cocher (pourles boutons radio aussi). Par défaut, c'est un alignementhorizontal qui est proposé. Vous pouvez choisir l'alignementvertical en spécifiant la valeur pageDirection dans l'attributlayout.

<h:panelGrid columns="2" border="1" cellspacing="0"> <h:panelGroup> <h:selectOneRadio value="#{test.couleur}" layout="pageDirection" > <f:selectItem itemLabel="Rouge" itemValue="#FF0000"/> <f:selectItem itemLabel="Jaune" itemValue="#FFFF00" /> <f:selectItem itemLabel="Bleu" itemValue="#0000FF" /> <f:selectItem itemLabel="Vert" itemValue="#00FF00" /> <f:selectItem itemLabel="Orange" itemValue="#FF6600" /> </h:selectOneRadio> </h:panelGroup> <h:panelGroup> <h:commandButton value="Choisissez votre couleur" /> <hr /> Choix : <br /> <h:inputTextarea value="#{test.couleur}" readonly="true" style="background: #{test.couleur}"/> </h:panelGroup></h:panelGrid>

@ManagedBeanpublic class Test { private String couleur = "#FFFF00";

public String getCouleur() { return couleur; }

public void setCouleur(String couleur) { this.couleur = couleur; }}

Il est également possible de faire un choix parmi plusieursvaleurs proposées, ce qui correspond au boutons radios.Cette fois-ci la valeur de la propriété doit représenter unélément unique.

<h:panelGrid columns="2" border="1" cellspacing="0"> <h:panelGroup> <h:selectOneListbox value="#{test.couleur}" > <f:selectItem itemLabel="Rouge" itemValue="#FF0000"/> <f:selectItem itemLabel="Jaune" itemValue="#FFFF00" /> <f:selectItem itemLabel="Bleu" itemValue="#0000FF" /> <f:selectItem itemLabel="Vert" itemValue="#00FF00" /> <f:selectItem itemLabel="Orange" itemValue="#FF6600" /> </h:selectOneListbox> </h:panelGroup> <h:panelGroup> <h:commandButton value="Choisissez votre couleur" /> <hr /> <h:inputText value="#{test.couleur}" readonly="true" style="background: #{test.couleur}" size="23"/> </h:panelGroup></h:panelGrid>

Une autre solution pour faire un choix parmi plusieurs valeursproposées, c'est d'utiliser une liste. Là aussi, la valeur de lapropriété doit représenter un élément unique.

Par défaut, tous les éléments de la liste sont systématiquementvisibles. Vous avez la possibilté de limiter le nombred'éléments visibles au moyen de l'attribut size. Un ascenceurvertical sera alors proposé.

<h:panelGrid columns="2" border="1" cellspacing="0"> <h:panelGroup> <h:selectManyListbox value="#{test.couleurs}" layout="pageDirection" > <f:selectItem itemLabel="Rouge" itemValue="Color.RED"/> <f:selectItem itemLabel="Jaune" itemValue="Color.YELLOW" /> <f:selectItem itemLabel="Bleu" itemValue="Color.BLUE" /> <f:selectItem itemLabel="Vert" itemValue="Color.GREEN" /> <f:selectItem itemLabel="Orange" itemValue="Color.ORANGE" /> </h:selectManyListbox> </h:panelGroup> <h:panelGroup> <h:commandButton value="Choisissez vos couleurs" /> <hr /> <h:dataTable value="#{test.couleurs}" var="couleur">

Grâce à cette balise, vous pouvez aussi prendre en compteplusieurs valeurs dans une liste. Attention, il faut que lapropriété qui gère l'ensemble des valeurs choisies soit unecollection.

Page 41: 08 - JavaServer Faces 2.0

<h:column>#{couleur}</h:column> </h:dataTable> </h:panelGroup></h:panelGrid>

@ManagedBeanpublic class Test { private ArrayList<Color> couleurs = new ArrayList<Color>();

public ArrayList<Color> getCouleurs() { return couleurs; }

public void setCouleurs(ArrayList<Color> couleurs) { this.couleurs = couleurs; }}

<h:panelGrid columns="2" border="1" cellspacing="0"> <h:panelGroup> <h:selectOneMenu value="#{test.couleur}" > <f:selectItem itemLabel="Rouge" itemValue="#FF0000"/> <f:selectItem itemLabel="Jaune" itemValue="#FFFF00" /> <f:selectItem itemLabel="Bleu" itemValue="#0000FF" /> <f:selectItem itemLabel="Vert" itemValue="#00FF00" /> <f:selectItem itemLabel="Orange" itemValue="#FF6600" /> </h:selectOneMenu> </h:panelGroup> <h:panelGroup> <h:commandButton value="Choisissez votre couleur" /> <hr /> <h:inputText value="#{test.couleur}" readonly="true" style="background: #{test.couleur}" size="23"/> </h:panelGroup></h:panelGrid>

Une dernière solution pour faire un choix parmi plusieurséléments est la liste déroulante, souvent appelé menu dans lesapplications web.

La balise <f:selectItem>Dans tous les exemples que nous venons de voir, la balise <f:selectItem> représente un seul élément de l'ensemble de la sélection. Pour connaître tous leschoix possibles, vous devez donc proposer un ensemble de balise <f:selectItem> imbriqués à l'intérieur du type de réprésentation que vous désirez obtenir.

Dans l'exemple ci-dessus, une des valeurs : #FF0000, #FFFF00, #0000FF, etc. va être transmise à la propriété couleur du bean test, lorsque le choix esteffectué et lorsque l'ordre de soumission a été envoyé.

L'attribut itemValue représente une de ces valeurs. Si cette valeur est celle que vous désirez visualiser dans le rendu de la page web, vous n'avez pasbesoin d'autre attribut. Si par contre, vous souhaitez proposer un intitulé différent de la valeur à envoyer, vous pouvez alors utiliser l'attributitemLabel.

Avec la valeur et son étiquette, dans un élément de sélection, vous pouvez aussi lui proposer une description ou même le désigner temporairementinactif. Par ailleurs, avec JSF 2.0, il existe un attribut supplémentaire noSelectionOption qui permet de désigner l'élément comme une invitation àchoisir une sélection et non comme une valeur à prendre en compte. Cet attribut s'utilise en conjonction avec la phase de validation. Dans le cas d'unnon choix de la par de l'utilisateur, un message d'erreur peut alors être proposé.

<h:panelGrid columns="1" style="background: darkgreen" cellpadding="3"> <h:panelGroup> <h:selectOneMenu value="#{test.couleur}" id="choix" required="true" requiredMessage="Faites votre choix !"> <f:selectItem itemLabel="Choisissez votre couleur" noSelectionOption="true" /> <f:selectItem itemLabel="Rouge" itemValue="#FF0000" itemDisabled="true"/> <f:selectItem itemLabel="Jaune" itemValue="#FFFF00" /> <f:selectItem itemLabel="Bleu" itemValue="#0000FF" /> <f:selectItem itemLabel="Vert" itemValue="#00FF00" /> <f:selectItem itemLabel="Orange" itemValue="#FF6600" /> </h:selectOneMenu> <h:commandButton value="Ok" /> </h:panelGroup> <h:message for="choix" /> <h:inputText value="#{test.couleur}" readonly="true" style="background: #{test.couleur}" size="30" /></h:panelGrid>

Attributs Description

itemDescriptionDescription de l'élément utile uniquement avec un outil adapté.

itemDisabled Permet de rendre temporairement un élément inactif.

itemLabel Texte envoyé pour le rendu de l'élément (partie visuelle).

itemValue Valeur prise en compte par la requête soumise au serveur d'applications.

escape Permet d'intégrer des caractères spéciaux qui ne doivent pas être interpréter par JSF.

value Expression EL qui identifie un objet de type SelectItem.

<f:selectItem value="#{test.couleurRouge}" />

Page 42: 08 - JavaServer Faces 2.0

SelectItem getCouleurRouge() { return new SelectItem("Rouge", "#FF0000"); }

// Constructeurs possiblesSelectItem(Object value)SelectItem(Object value, String label)SelectItem(Object value, String label, String description)SelectItem(Object value, String label, String description, boolean disabled)SelectItem(Object value, String label, String description, boolean disabled, boolean escape)SelectItem(Object value, String label, String description, boolean disabled, boolean escape, boolean noSelectionOption)

noSelectionOption Proposer la valeur true si cet élément n'est pas un choix possible dans la liste de sélection.

La balise <f:selectItems>La balise <f:selectItem> est polyvalente, mais cela peut s'avérer rapidement fastidieux d'écrire systématiquement l'ensemble des choix possibles sur la vue.Nous pouvons réduire considérablement le code en proposant plutôt la balise <f:selectItems>. Dans ce cas, c'est le modèle qui doit prendre le relais et sepréoccuper de spécifier l'ensemble des éléments que comporte la sélection.

La vue

<h:body style="background-color: green; color: yellow; font-weight: bold"> <h:form> <h:panelGrid columns="1" style="background: darkgreen" cellpadding="3"> <h:panelGroup> <h:selectOneMenu value="#{test.couleur}" id="choix" required="true" requiredMessage="Faites votre choix !"> <f:selectItems value="#{test.couleurs}" /> </h:selectOneMenu> <h:commandButton value="Ok" /> </h:panelGroup> <h:message for="choix" /> <h:inputText value="#{test.couleur}" readonly="true" style="background: #{test.couleur}" size="30" /> </h:panelGrid> </h:form></h:body>

Le modèle

import javax.faces.bean.*;import javax.faces.model.SelectItem;

@ManagedBeanpublic class Test { private String couleur; private SelectItem[] couleurs = { new SelectItem(null, "Choisissez votre couleur", "", false, false, true), new SelectItem("#FF0000", "Rouge", "", true), new SelectItem("#FFFF00", "Jaune"), new SelectItem("#0000FF", "Bleu"), new SelectItem("#00FF00", "Vert"), new SelectItem("#FF6600", "Orange") };

public String getCouleur() { return couleur; } public void setCouleur(String couleur) { this.couleur = couleur; } public SelectItem[] getCouleurs() { return couleurs; } }

L'attribut value de la balise <f:selectItems> doit posséder une expression EL qui représente l'un des quatre points suivants : une instance d'un seulSelectItem, une collection, un tableau ou une carte où chaque entrée représente une étiquette suivie de sa valeur.

Une balise <f:selectitems> est très souvent plus facile à manipuler que la balise <f:selectItem>. Dans le cas où le nombre d'éléments varie, avec<f:selectItems>, généralement vous avez besoin de changer uniquement que le modèle, alors qu'avec la balise <f:selectItem>, vous devez modifier à lafois la vue et le modèle.

Attributs Description

value Expression EL qui représente un seul élément, une collection, un tableau ou une carte d'entrées.

var Nom de la variable qui va être utilisée pour récupérer les propriétés d'un élément de la collection pour renseigner en une seule foisson intitulé et sa valeur, respectivement exprimés au travers des attributs itemLabel et itemValue.

itemLabel Intitulé de l'élément associé à l'attribut var.

itemValue Valeur de l'élément associé à l'attribut var.

itemDescription Description de l'élément associé à l'attribut var.

itemDisabled Rendre l'élément associé à l'attribut var momentanément inactif.

itemLabelEscape Permettre à l'élément associé à l'attribut var de ne pas interpréter le code interne.

noSelectionOption Elément associé à l'attribut var qui ne fait pas parti de la sélection.

Avant JSF 2.0, les collections et les tableaux devaient contenir impérativement des instances de type SelectItem, comme l'exemple proposé plus haut.Nous remarquons tout de suite que là aussi cela peut être assez fastidieux. Depuis lors, il est maintenant possible de proposer une collection ou untableau de n'importe quel type d'objets, ce qui est largement plus intéressant.

Si vous utilisez une classe quelconque comme élément de votre collection, les intitulés de vos sélections sont générés automatiquement à partir de laméthode toString() de votre classe. A vous de redéfinir cette méthode pour que tout se fasse automatiquement.

<h:selectOneMenu value="#{test.jour}"> <f:selectItems value="#{test.jours}" /></h:selectOneMenu>

@ManagedBeanpublic class Test {

Page 43: 08 - JavaServer Faces 2.0

private enum JourSemaine {Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi, Dimanche}; private JourSemaine[] jours = JourSemaine.values(); private JourSemaine jour;

public JourSemaine[] getJours() { return jours; } public JourSemaine getJour() { return jour; } public void setJour(JourSemaine jour) { this.jour = jour; }}

D'une autre façon, vous pouvez utiliser l'attribut var pour définir une variable qui représente chaque élément particulier de la collection. Nous pouvonsfaire correspondre à cette variable, l'intitulé ainsi que la valeur associée, en prenant en compte les propriétés liées à l'élément, en spécifiant ainsi lesattributs itemLabel et itemValue.

Dans le même ordre d'idée, vous pouvez définir l'élément qui portera une description, qui sera momentanément inactif ou qui ne fera pas parti de lasélection au moyen des attributs respectifs : itemDescription, itemDisabled et noSelectionOption.

<style type="text/css"> body { background-color: green; color: yellow; } .fond, .droite { background: yellow; font-weight: bold; } .droite { text-align: right; }</style>

<h:body> <h:form> <h:panelGrid columns="2" style="background: darkgreen" cellpadding="3"> <h:selectOneMenu value="#{test.nombreJours}" onchange="submit()" styleClass="fond"> <f:selectItems value="#{test.mois}" var="mois" itemValue="#{mois.numéroMois}" /> </h:selectOneMenu> <h:inputText value="#{test.nombreJours}" readonly="true" size="3" styleClass="droite"/> </h:panelGrid> </h:form></h:body>

@ManagedBeanpublic class Test { public enum Mois { Janvier, Février, Mars, Avril, Mai, Juin, Juillet, Août, Septembre, Octobre, Novembre, Décembre; public int getNuméroMois() { return ordinal()+1; } }; private Mois[] mois = Mois.values(); private int nombreJours;

public Mois[] getMois() { return mois; } public int getNombreJours() { return nombreJours; } public void setNombreJours(int nombreJours) { this.nombreJours = nombreJours; } }

Liaison entre l'attribut value et la propriété du bean géréLorsque vous utilisez un ensemble de cases à cocher, des menus ou des listes, vous avez toujours besoin de récupérer l'élément sélectionné par rapport àl'ensemble proposé. Comme nous venons de le voir, vous devez alors utiliser l'attribut value associée à une propriété du bean géré au travers d'uneexpression EL. Cette propriété correspond ainsi à la valeur délivrée par l'attribut itemValue de l'élément.

ATTENTION, lorsque la requête est soumise, le serveur d'application reçoit la chaîne sélectionnée (protocole HTTP) et doit le convertir dans le typeapproprié. L'implémentation JSF sait comment convertir un nombre ou une énumération, mais vous êtes obligé de prévoir un convertisseur dans tousles autres cas.

Les messages d'erreur

Les beans gérés traitent de la logique métier, appellent les EJB, utilisent les bases de données, etc. Parfois, cependant, un problème peut survenir et, en cecas, l'utilisateur doit être informé par un message qui peut être un message d'erreur de l'application (concernant la logique métier ou la connexion à la baseou au réseau) ou un message d'erreur de saisie (un ISBN incorrect ou un champ vide par exemple).

Les erreurs d'application peuvent produire une page particulière demandant à l'utilisateur de réessayer dans un moment, par exemple, alors que leserreurs de saisie peuvent s'afficher dans la même page avec un texte décrivant l'erreur. Nous pouvons également utiliser des messages pour informerl'utilisateur qu'un livre a été correctement ajouté à la base de données.

Typiquement, pour les erreurs de saisie, les messages sont associés avec un composant particulier et précise qu'une erreur de conversion ou devalidation est survenue. Bien que nous utilisons les messages souvent de la même façon, il existe en réalité quatre variétés de message : Information,Avertissement, Erreur et Fatal.

Tous les types de message comporte une description sommaire et une description détaillée. Par exemple, de façon sommaire nous pourrions dire quel'entrée est invalide, alors que dans le détail nous pourrions indiquer que le nombre saisi est plus grand que la valeur maximal prévue. Lesapplications JSF utilise deux balises pour représenter ces messages : <h:messages> et <h:message>.

1. <h:messages> : Cette balise affiche tous les messages d'erreur survenant dans l'ensemble de la page.

2. <h:message> : Cette balise affiche un seul message d'erreur associé à un composant en particlier. Ce composant est spécifié au travers de l'attributfor, lui-même devra proposer un identifiant.

Attributs Description

Page 44: 08 - JavaServer Faces 2.0

Attributs Description

errorClass, errorStyle, fatalClass,fatalStyle, infoClass, infoStyle,warnClass, warnStyle

Styles CSS associés aux quatre types de message d'erreur.

for Identifiant désignant le composant à prendre en compte pour afficher un éventuel message d'erreur leconcernant. (<h:message> uniquement).

globalOnly Instruction imposant d'afficher uniquement les messages d'erreur globaux, les messages particuliers étant alorsdésactivés. (<h:messages> uniquement).

layout Permet de spécifier l'orientation de l'ensemble des messages d'erreur survenant : "table" ou "list". (<h:messages>uniquement).

showDetail Booléen qui détermine si le message d'erreur doit être affiché sous forme détaillé. Par défaut, les valeurs sontfalse pour <h:messages> et true pour <h:message>.

showSummary Booléen qui détermine si le message d'erreur doit être affiché sous forme simplifiée. Par défaut, les valeurs sonttrue pour <h:messages> et false pour <h:message>.

tooltip Booléen qui détermine si un message détaillé doit être rendu visible dans une petite bulle d'avertissement. Cetavertissement ne sera toutefois visible uniquement à la condition que les attributs showDetail et showSummarysoient validés.

<style type="text/css"> body { background-color: green; color: yellow; font-weight: bold; } .cadre { background: darkgreen; } .erreur { color: chartreuse; font-style: italic; text-align: left; }</style>

<h:body> <h:form> <h:panelGrid columns="3" styleClass="cadre"> <f:facet name="header"> <h:messages styleClass="erreur"/> </f:facet> Nom : <h:inputText id="nom" value="#{test.nom}" required="true" label="Nom"/> <h:message for="nom" errorClass="erreur" /> Âge : <h:inputText id="âge" value="#{test.âge}" size="3" label="Âge" /> <h:message for="âge" errorClass="erreur" /> <f:facet name="footer"> <hr /> <h:commandButton value="Soumettre" /> </f:facet> </h:panelGrid> </h:form></h:body>

Les messages d'erreurs proposées sont automatiquement traduite dans la langue locale. Ils sont relativement adaptés à la situation. Il est égalementpossible de proposer un message personnalisé sur chaque balise de saisie au moyen des attributs converterMessage, validatorMessage etrequiredMessage.

<style type="text/css"> body { background-color: green; color: yellow; font-weight: bold; } .cadre { background: darkgreen; } .erreur { color: chartreuse; font-style: italic; text-align: left; }</style>

<h:body> <h:form> <h:panelGrid columns="3" styleClass="cadre"> Nom : <h:inputText id="nom" value="#{test.nom}" required="true" requiredMessage="Erreur : indispensable" /> <h:message for="nom" errorClass="erreur" /> Âge : <h:inputText id="âge" value="#{test.âge}" size="3" converterMessage="Erreur : valeur entre 0 et 120" /> <h:message for="âge" errorClass="erreur" /> <f:facet name="footer"> <hr /> <h:commandButton value="Soumettre" /> </f:facet> </h:panelGrid>

</h:form>

Page 45: 08 - JavaServer Faces 2.0

</h:form></h:body>

Les données sous forme de tableau dynamique

Les données doivent souvent être affichées sous forme de tableau. JSF fournit donc le marqueur <h:dataTable> permettant ainsi de parcourir une liste d'éléments (dontla taille est variable) afin de générer automatiquement un tableau. Typiquement, un tableau dynamique de données possède la structure suivante :

<h:dataTable value="#{éléments}" var="élément"> <h:column> #{élément.premièrePropriété} </h:column> <h:column> #{élément.deuxièmePropriété} </h:column>...</h:dataTable>

L'attribut value représente l'ensemble des données que pourra parcourir par itération la balise <h:dataTable>. Les données que peut exploiter l'attribut value estde l'une des natures suivantes : un simple objet Java, un tableau, une instance de java.util.List, une instance de java.sql.ResultSet, une instance dejavax.faces.model.DataModel.

1. La balise <h:dataTable> prend en compte l'ensemble des éléments constituant la collection choisie. Du coup, la longueur du tableau est totalement variable etdépend du contenu en cours de la collection. Il s'agit donc bien d'un tableau dynamique qui affiche les données actuellement accessibles.

2. Chaque élément de la collection est représenté par une ligne de la table. Il est possible d'identifier l'élément de la ligne courante en spécifiant l'attribut var dela balise <h:dataTable>. Cet élément représente généralement un simple objet avec lequel nous pouvons ensuite manipuler chaque propriété séparément,représentée dans une colonne distincte.

3. Plus rarement, au lien de proposer une collection, nous pouvons spécifier un seul objet Java dans l'attribut value de <h:dataTable>, auquel cas une seule ligneapparaîtra puiqu'il n'existe qu'une seule occurrence.

4. Le corps de la balise <h:dataTable> ne peut contenir uniquement que des balises <h:column>. La balise <h:dataTable> ignore toutes les autres balises quevous placerez. Par contre, chaque colonne peut contenir un nombre indéfini de composants internes.

La balise <h:dataTable> est en relation avec un composant de type UIData qui s'occupe du rendu de la table. Cette combinaison permet de générer des tablesrobustes qui supportent les styles CSS, l'accès aux bases de données, la personnalisation des modèles de table, et bien d'autres. Nous allons commencer notreexploration de ce marqueur <h:dataTable> en élaborant tout d'abord une simple table.

<style> body { background-color: green; color: yellow; font-weight: bold; } .cadre { background: darkgreen; border-radius: 5px; padding: 7px; box-shadow: -1px -1px 3px lightgreen, 1px 1px 2px black; } .saisie { background: yellow; color: darkgreen; text-align: right; padding-right: 5px; font-weight: bold; }</style>

<h:body> <h:form> <h:panelGrid columns="2" styleClass="cadre"> <h:outputText value="Prénom : " /> <h:inputText value="#{gestion.personne.prénom}" styleClass="saisie"/> <h:outputText value="Nom : " /> <h:inputText value="#{gestion.personne.nom}" styleClass="saisie" /> <f:facet name="footer"> <hr /> <h:commandButton value="Nouveau" action="#{gestion.nouveau()}"/> <h:commandButton value="Enregistrer" action="#{gestion.ajout()}" /> </f:facet> </h:panelGrid> <br /> <h:dataTable value="#{gestion.personnes}" var="personne" styleClass="cadre" rendered="#{gestion.pasVide}"> <h:column>#{personne.prénom}</h:column> <h:column>#{personne.nom}</h:column> </h:dataTable> </h:form></h:body>

@ManagedBean@SessionScopedpublic class Gestion { private Personne personne = new Personne(); private ArrayList<Personne> personnes = new ArrayList<Personne>();

public Personne getPersonne() { return personne; } public void setPersonne(Personne personne) { this.personne = personne; }

public ArrayList<Personne> getPersonnes() { return personnes; } public void ajout() { personnes.add(personne); } public void nouveau() { personne = new Personne(); } public boolean isPasVide() { return !personnes.isEmpty(); }}

public class Personne { private String nom; private String prénom;

Page 46: 08 - JavaServer Faces 2.0

public String getNom() { return nom; } public String getPrénom() { return prénom; } public void setNom(String nom) { this.nom = nom.toUpperCase(); }

public void setPrénom(String prénom) { if (prénom.isEmpty()) return; StringBuilder chaine = new StringBuilder(prénom.toLowerCase()); chaine.setCharAt(0, Character.toUpperCase(chaine.charAt(0))); this.prénom = chaine.toString(); }}

Dans l'exemple ci-dessus, le bean géré gestion permet de gérer l'ensemble des personnes à enregistrer et possède donc une collection personnes quiest donc rattachée à l'attribut value de la balise <h:dataTable>. Ensuite, grâce à l'attribut var de cette balise, nous pouvons visulaiser chaque personneen particulier sur chacune des lignes du tableau. A l'intérieur de ce tableau, nous rajoutons deux balises <h:column> qui vont nous permettre devisualiser ainsi séparément, sous formes de colonnes, le nom et le prénom de chaque personne.

Attributs Description des attributs de la balise <h:dataTable>

bgcolor Couleur de fond de la table.

border Largeur de la bordure de la table.

captionClass Style CSS associé au titre de la table.

cellpadding Espacement minimum à l'intérieur de chaque cellule.

cellspacing Espacement entre les cellules.

columnClasses Liste des styles CSS pour les colonnes de la table.

dir Direction du texte : LTR (Left to Right) ou RTL (Right to Left).

first Index de la collection à partir duquel nous commençons à afficher la première ligne du tableau.

footerClass Style CSS associé au pied du tableau.

frame Spécification pour déterminer le comportement du cadre par rapport à son environnement. Valeurs attendues : none, above, below,hsides, vsides, lhs, rhs, box, border.

headerClass Style CSS pour spécialement prévue pour la partie en-tête.

rowClasses Liste des styles CSS pour les lignes de la table.

rows Nombre de lignes affichable dans la table. Généralement en relation avec l'attribut first. Si vous proposez la valeur 0, toute les lignes de latable vont être affichées.

rules Règles spécifique aux tracés des lignes entre les cellules. Valeurs possibles : groups, rows, columns, all.

summary Sommaire de la table non visible, pour une utilisation en coulisse.

var Nom proposé qui représente la ligne courante, une valeur spécifique de l'ensemble de la collection.

Attributs Description des attributs de la balise <h:columns>

footerClass Style CSS associé au pied du tableau.

headerClass Style CSS pour spécialement prévue pour la partie en-tête.

En-tête, pied et titre sur une table

Si nous affichons la liste des noms et prénoms comme nous venons de le faire dans le projet précédent, ce n'est pas très agéable car il n'est par toujoursfacile de s'y retrouver entre le nom et le prénom d'une personne. Il serait souhaitable de proposer au moins un titre à chacune des colonnes visibles.

A l'image de la balise <h:panelGrid>, nous avons la possiblité de rajouter des facettes pour spécifier une partie en-tête, un pied sur chacune descolonnes et un titre sur l'ensemble de la table.

<style> body { background-color: green; color: yellow; font-weight: bold; } .cadre { background: darkgreen; border-radius: 5px; padding: 7px; box-shadow: -1px -1px 3px lightgreen, 2px 2px 5px black; } .saisie { background: yellow; color: darkgreen; text-align: right; padding-right: 5px; font-weight: bold; } .en-tete { background: lightgreen; color: darkgreen; } .colonne { padding: 4px; width: 124px; }</style>

<h:body> <h:form> <h:panelGrid columns="2" styleClass="cadre" > <h:outputText value="Prénom : " /> <h:inputText value="#{gestion.personne.prénom}" styleClass="saisie"/> <h:outputText value="Nom : " /> <h:inputText value="#{gestion.personne.nom}" styleClass="saisie" /> <f:facet name="footer"> <hr /> <h:commandButton value="Nouveau" action="#{gestion.nouveau()}"/> <h:commandButton value="Enregistrer" action="#{gestion.ajout()}" /> </f:facet> </h:panelGrid> <h:dataTable value="#{gestion.personnes}" var="personne" styleClass="cadre" headerClass="en-tete" captionClass="cadre" columnClasses="colonne, colonne" rules="all" > <f:facet name="caption">Liste des personnes</f:facet> <h:column> <f:facet name="header">Prénom</f:facet> #{personne.prénom} </h:column> <h:column> <f:facet name="header">Nom</f:facet>

#{personne.nom}

Page 47: 08 - JavaServer Faces 2.0

#{personne.nom} </h:column> </h:dataTable> </h:form></h:body>

Composants dans une table et mode d'édition

Jusqu'à présent, nous n'avons placé uniquement des composants pour afficher du texte. En réalité, vous pouvez introduire une très grande variété decomposants graphiques, des zones de saisie, des boutons, des images, des menus, des cases à cocher, des boutons radio, des listes, etc.

En prévoyant tous ces types de composant, il devient possible d'avoir des tables éditables, pour saisir de nouvelles entrées, modifier celles qui sontdéjà présentes, supprimer des lignes, etc.

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <style> body { background-color: green; color: yellow; font-weight: bold; } .cadre { background: darkgreen; border-radius: 5px; padding: 7px; box-shadow: -1px -1px 3px lightgreen, 2px 2px 5px black; } input[type="text"] { background: yellow; color: darkgreen; font-weight: bold; } .en-tete { background: green; padding-left: 10px; padding-right: 10px; border-radius: 3px; text-shadow: 2px 2px 7px black; } </style>

<h:body> <h:form> <h:dataTable value="#{gestion.personnes}" var="personne" styleClass="cadre" columnClasses="en-tete"> <h:column headerClass="en-tete"> <f:facet name="header">Marié</f:facet> <h:selectBooleanCheckbox value="#{personne.marié}" /> </h:column> <h:column headerClass="en-tete"> <f:facet name="header">Prénom</f:facet> <h:inputText value="#{personne.prénom}" /> </h:column> <h:column headerClass="en-tete"> <f:facet name="header">Nom</f:facet> <h:inputText value="#{personne.nom}" /> </h:column> <h:column><h:commandButton value="Enregistrer" /></h:column> <h:column> <h:commandButton value="Supprimer" action="#{gestion.supprimer(personne)}" /> </h:column> <f:facet name="footer"> <hr /> <h:commandButton value="Ajouter" action="#{gestion.ajout()}" /> </f:facet> </h:dataTable> </h:form> </h:body></html>

@ManagedBean@SessionScopedpublic class Gestion { private ArrayList<Personne> personnes = new ArrayList<Personne>(); public ArrayList<Personne> getPersonnes() { return personnes; } @PostConstruct public void ajout() { personnes.add(new Personne()); } public void supprimer(Personne personne) { personnes.remove(personne); if (personnes.isEmpty()) personnes.add(new Personne()); }}

Dans cet exemple, nous avons placés des composants différents dans l'ensemble des colonnes, des cases à cocher, des zones de saisie et pour finir desboutons de commande.

Vous remarquez qu'il est même possible de supprimer une ligne. Il suffit de faire appel à la méthode qui permet cette suppression en passant enparamètre l'objet correspondant à la ligne courante, celui qui est donc déclaré par l'attribut var de la balise <h:dataTable>. Pour ajouter une nouvelleligne, il suffit de rajouter un nouvel objet vierge à votre collection et de rafraîchir la page, et le tour est joué.

Page 48: 08 - JavaServer Faces 2.0

Projet de conclusion

Pour conclure cette première partie sur JSF, je vous propose de mettre en oeuvre un dernier projet qui valide les différents concepts que nous venons de découvrir. Laprochaine étude nous permettra d'aller un peu plus loin dans le domaine. Nous verrons notamment comment :

1. Réaliser des modèles de page,

2. Créer de nouveau composants,

3. Construire des convertisseurs et des validateurs personnalisés,

4. S'occuper de toute la partie événementielle,

5. Intégrer des modules sous Ajax,

6. etc.

Le projet que je vous propose permet de réaliser une série de conversions monétaires. L'ensemble des conversions sont systématiquement enregistrées dans unebase de données. Elles sont accessibles dans un tableau limité à quatre conversions visibles en même temps. Vous pouvez par contre naviguer dans l'ensembledes pages.

Page 49: 08 - JavaServer Faces 2.0

Voici maintenant l'ensemble des éléments qui constitue le projet, respectivement :

1. L'entité Conversion qui rend persistant l'ensemble des conversions,

2. Le bean géré CDI Gérer qui est également un bean session qui sert de modèle pour l'application web et qui s'occupe de la persistance de l'entitéConversion.

3. La feuille de style principal.css utile pour la vue,

4. La page unique du site index.xhtml qui sert de vue à l'application web

L'entité entité.Conversion

package entité;

import java.io.Serializable;import javax.persistence.*;

@Entity@NamedQuery(name="toutesLesConversions", query="SELECT conversion FROM Conversion conversion")public class Conversion implements Serializable { @Id @GeneratedValue private long id; private double euro; private double franc; private char sens;

public long getId() { return id; } public double getEuro() { return euro; } public double getFranc() { return franc; } public char getSens() { return sens; } public void setSens(char sens) { this.sens = sens; }

Page 50: 08 - JavaServer Faces 2.0

public Conversion(char sens, double euro, double franc) { this.sens = sens; this.euro = euro; this.franc = franc; } public Conversion() { }}

Le bean session stateful et CDI bean.Gérer

package bean;

import entité.Conversion;import java.util.List;import javax.annotation.PostConstruct;import javax.ejb.Stateful;import javax.enterprise.context.SessionScoped;import javax.inject.Named;import javax.persistence.*;

@Named@SessionScoped@Statefulpublic class Gérer { @PersistenceContext private EntityManager bd; private List<Conversion> conversions; private final double TAUX = 6.55957; private double euro; private double franc; private char sens = 'F'; private int pages; private int page;

public double getEuro() { return euro; } public void setEuro(double euro) { this.euro = euro; }

public double getFranc() { return franc; } public void setFranc(double franc) { this.franc = franc; }

public char getSens() { return sens; } public void setSens(char sens) { this.sens = sens; } public List<Conversion> getConversions() { return conversions; }

public int getPages() { return pages; } public int getPage() { return page; } @PostConstruct public void liste() { Query requête = bd.createNamedQuery("toutesLesConversions"); conversions = requête.getResultList(); pages = ((conversions.size() - 1) / 4) + 1; } public void convertir() { switch (sens) { case '€' : euro = franc / TAUX; break; case 'F' : franc = euro * TAUX; break; } bd.persist(new Conversion(sens, euro, franc)); liste(); } public void supprimer(Conversion conversion) { bd.remove(bd.find(Conversion.class, conversion.getId())); liste(); } public void changerPage(int décalage) { page += décalage; }}

La feuille de style web/css/principal.css

root { display: block;}

body { background-color: green; color: yellow; font-weight: bold; }

.cadre { background: darkgreen; border-radius: 5px; padding: 7px; box-shadow: -1px -1px 3px lightgreen, 2px 2px 5px black; }

.saisie, .resultat, .pages {

Page 51: 08 - JavaServer Faces 2.0

background: yellow; color: darkgreen; font-weight: bold; text-align: right; padding-right: 7px; padding-left: 7px;}

.saisie { margin-right: 15px; margin-left: 15px;}

.resultat, .pages { border-radius: 5px; box-shadow: 1px 1px 3px black inset; margin-left: 20px;}

.resultat { width: 170px; display: block; }

.fond { background: black; padding: 6px; border-radius: 5px; opacity: 0.9; }

La vue index.xhtml

<?xml version='1.0' encoding='UTF-8' ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <h:head /> <h:outputStylesheet name="principal.css" library="css" />

<h:body> <h:form> <h:dataTable value="#{gérer.conversions}" var="conversion" styleClass="cadre" footerClass="fond" headerClass="fond" rows="4" first="#{gérer.page * 4}"> <f:facet name="header"> <h:inputText value="#{gérer.euro}" styleClass="saisie"> <f:convertNumber type="currency" currencySymbol="Euros"/> </h:inputText> <h:selectOneMenu value="#{gérer.sens}"> <f:selectItem itemLabel="en Euro" itemValue="€" /> <f:selectItem itemLabel="en Franc" itemValue="F" /> </h:selectOneMenu> <h:inputText value="#{gérer.franc}" styleClass="saisie"> <f:convertNumber type="currency" currencySymbol="Francs"/> </h:inputText> <h:commandButton value="Convertir" action="#{gérer.convertir()}" /> </f:facet> <h:column headerClass="en-tete"> <h:outputText value="#{conversion.euro}" styleClass="resultat"> <f:convertNumber type="currency" currencySymbol="Euros" /> </h:outputText> </h:column> <h:column headerClass="en-tete"> <h:selectOneRadio value="#{conversion.sens}"> <f:selectItem itemLabel="€" itemValue="€" /> <f:selectItem itemLabel="F" itemValue="F" /> </h:selectOneRadio> </h:column> <h:column headerClass="en-tete"> <h:outputText value="#{conversion.franc}" styleClass="resultat"> <f:convertNumber type="currency" currencySymbol="Francs" /> </h:outputText> </h:column> <h:column> </h:column> <h:column> <h:commandButton value="Supprimer" action="#{gérer.supprimer(conversion)}" /> </h:column> <f:facet name="footer"> <h:outputFormat value="{0} page{0, choice, 0#|2#s}" styleClass="pages"> <f:param value="#{gérer.pages}" /> </h:outputFormat> <h:commandButton value="Page précédente" disabled="#{gérer.page == 0}" action="#{gérer.changerPage(-1)}"/> <h:commandButton value="Page suivante" disabled="#{gérer.page == gérer.pages-1}" action="#{gérer.changerPage(1)}" /> <h:outputFormat value="{0} page{0, choice, 0#|2#s}" styleClass="pages">

Page 52: 08 - JavaServer Faces 2.0

<f:param value="#{gérer.pages}" /> </h:outputFormat> </f:facet> </h:dataTable> </h:form> </h:body></html>