Académique Documents
Professionnel Documents
Culture Documents
JSFEclipse PDF
JSFEclipse PDF
FrançoisXavier SENNESAL
Résumé
Ce livre sur JSF traite de la mise en œuvre de la technologie Java Server Faces avec l’environnement de développement Eclipse. Les aspects
théoriques, étayés par de nombreux exemples, montrent comment l’usage de composants JSF permet de faciliter la conception et la
maintenance des applications web, tout en offrant aux utilisateurs des services plus adaptés à leurs attentes.
Le livre s’adresse tout particulièrement à des lecteurs maîtrisant le langage de programmation Java et familiarisés par ailleurs avec le
développement d’applications web basées sur la technologie JSP.
Les principaux points développés dans ce livre couvrent la validation et la conversion des données, la gestion évènementielle, la conception de
composants JSF personnalisés, ainsi que l’internationalisation des applications.
Après un rappel des notions essentielles liées à la conception d’applications web en environnement J2EE, l’ouvrage présente dans le détail le
langage d’évaluation d’expressions propre à la technologie JSF, ainsi que les bibliothèques de composants utilisées. Les chapitres suivants
montrent comment exploiter efficacement les composants en question, tout en s’attardant sur les méthodes utilisables pour définir les règles de
navigation des applications web.
L'auteur
François-Xavier Sennesal est responsable informatique au sein d'un organisme de recherche publique. Il assure par ailleurs des
enseignements dans le domaine des nouvelles technologies à l'École Supérieure d'Ingénieurs Léonard de Vinci à Paris, ainsi qu'à
l'université de Versailles St Quentin. À travers ce livre, le lecteur profite d'une riche expérience professionnelle axée sur le développement
d'applications web avec JSF et Eclipse.
Ce livre numérique a été conçu et est diffusé dans le respect des droits d’auteur. Toutes les marques citées ont été déposées par leur éditeur respectif. La loi du 11 Mars
1957 n’autorisant aux termes des alinéas 2 et 3 de l’article 41, d’une part, que les “copies ou reproductions strictement réservées à l’usage privé du copiste et non destinées
à une utilisation collective”, et, d’autre part, que les analyses et les courtes citations dans un but d’exemple et d’illustration, “toute représentation ou reproduction intégrale,
ou partielle, faite sans le consentement de l’auteur ou de ses ayants droit ou ayant cause, est illicite” (alinéa 1er de l’article 40). Cette représentation ou reproduction, par
quelque procédé que ce soit, constituerait donc une contrefaçon sanctionnée par les articles 425 et suivants du Code Pénal. Copyright Editions ENI
1. Éléments constitutifs d’une application
Une application web est composée d’un descripteur de déploiement, et d’un ensemble de ressources. Ces ressources
peuvent être de types variés : les plus caractéristiques sont les pages web (statiques ou dynamiques), les classes
correspondant à des servlets, et les classes personnalisées.
Le descripteur de déploiement est un fichier conventionnellement nommé web.xml. Il regroupe diverses informations
concernant l’application, comme la déclaration des servlets, la définition des paramètres initiaux ou la déclaration de
listeners.
2. Vie d’une application
Le fonctionnement d’une application web basée sur la technologie J2EE requiert l’utilisation d’un moteur de servlets
tenu de la prendre en charge. Le moteur de servlets le plus populaire est Apache Tomcat.
Lorsqu’une page JSP de l’application web est appelée pour la première fois par un internaute, celleci est dans un
premier temps traduite en servlet par le moteur de servlets. Une tentative de compilation de cette servlet est ensuite
assurée. Si la compilation réussit, la servlet est exécutée : cela a le plus souvent pour effet de restituer un contenu
dans le navigateur de l’internaute. Si la compilation de la servlet aboutit à un échec, un message d’erreur est généré
par le moteur de servlets, puis restitué à l’internaute. Ce processus de traduction/compilation est par ailleurs réalisé
chaque fois qu’une modification est apportée dans le code source de la page JSP.
1. Présentation
Une servlet est une classe implémentant l’interface javax.servlet.Servlet. Elle fonctionne par l’intermédiaire du
moteur de servlets, en réceptionnant les requêtes émises par les clients web, et en y répondant.
Il existe actuellement deux classes standards implémentant Servlet : il s’agit de classes abstraites nommées
GenericServlet et HttpServlet. La première caractérise une servlet indépendante de tout protocole, alors que la
seconde est spécifique au protocole HTTP. Enfin, l’interface Servlet est également implémentée en standard par une
classe non abstraite nommée FacesServlet : celleci gère le cycle de vie des applications web exploitant des
composants Java Server Faces.
2. Cycle de vie
Une servlet assure le traitement des requêtes émises par les clients par l’intermédiaire de deux objets, issus des
classes ServletRequest et ServletResponse. Ces objets sont fournis en paramètre d’une méthode abstraite nommée
service, qu’il convient d’implémenter pour permettre la prise en charge des requêtes clientes.
Outre cette méthode service, dont l’invocation est assurée à chaque fois qu’une requête cliente est émise, une
servlet implémente deux méthodes entrant spécifiquement en jeu dans son cycle de vie. Il s’agit des méthodes init
et destroy. La première est appelée par le moteur de servlets juste après la création de la servlet, et uniquement à
ce moment. La seconde de ces deux méthodes est invoquée juste avant la destruction de la servlet, et uniquement
dans ce cas.
L’exemple suivant illustre la conception d’une servlet basée sur la classe GenericServlet. Sa méthode service
exploite l’objet de type ServletResponse pour retourner une chaîne de caractères vers le flux de sortie.
package perso;
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
arg1.getWriter().println("Bienvenue");
}
}
3. Cas particulier des servlets répondant spécifiquement au protocole HTTP
Le meilleur moyen de concevoir une servlet capable de prendre en charge les requêtes HTTP consiste à créer une
classe dérivée de HttpServlet.
Cette classe réalise, au travers de sa méthode init, un traitement répartissant les requêtes compte tenu de leur
nature. Ainsi, une requête GET pourra être prise en charge au travers de la méthode doGet, alors qu’une requête
POST le sera grâce à la méthode doPost.
Il convient alors de surcharger l’une de ces deux méthodes, compte tenu de la nature de la requête réalisée, pour
tirer convenablement profit des informations fournies par le client. Ces méthodes acceptent en argument un objet de
type HttpServletRequest contenant toutes les caractéristiques de la requête initiale, ainsi qu’un objet de type
HttpServletResponse utilisable pour renvoyer une réponse au client. L’objet de type HttpServletRequest peut en
particulier être exploité pour prendre connaissance des informations passées dans la chaîne requête au moment de
la soumission d’un formulaire de saisie, grâce à l’une ou l’autre des méthodes getParameter, getParameterNames, et
getParameterValues.
1. Une brève description du mode de fonctionnement
La technologie JSP est conçue pour faciliter la génération de pages web dynamiques s’appuyant sur Java. Elle est
directement associée à la notion de servlets, et permet d’obtenir une séparation entre la logique métier et la couche
de présentation, principalement par l’usage des JavaBeans.
Lorsqu’une page JSP située dans une application web particulière est demandée par un client web, le conteneur qui la
gère (moteur de servlets) capture et analyse la requête. Si la page en question n’a jamais été appelée, ou si son code
source a été modifié, le conteneur la traduit sous la forme d’une servlet. Cette servlet est alors compilée puis exécutée
pour fournir une réponse à la requête du client web. Par contre, si la page a déjà été utilisée et si son code source n’a
pas été modifié, la servlet qui lui correspond existe déjà : il suffit alors au conteneur d’exécuter cette servlet pour
répondre au client.
2. Les composants d’une page JSP
Le code source le plus simple d’une page JSP peut correspondre à celuici :
<html>
...
<body>
<%
out.println("Ceci est un cours de développement web avec les JSP");
%>
...
</body>
</html>
D’une manière générale, une page JSP se compose d’éléments statiques, caractérisés par des balises HTML, et
d’éléments dynamiques. Ces derniers peuvent être classés en quatre catégories : les directives, les actions, les objets
implicites, et les zones de scripting.
a. Les directives
Ces éléments fournissent des informations globales concernant la page JSP. La forme générale de la syntaxe utilisée
pour définir une directive est la suivante :
Il convient de préciser qu’une page JSP particulière peut comporter plusieurs directives.
Les spécifications JSP proposent trois types de directives, nommées page, include et taglib. Chaque type de
directive dispose d’un jeu d’attributs spécifiques, dont voici un bref récapitulatif :
Principaux attributs de la directive page
● language : langage utilisé pour la compilation de la JSP. Actuellement, uniquement Java.
● import : ensemble des paquetages Java à mettre à disposition de la page JSP.
● session : indique si les données de session sont disponibles pour la page (valeur par défaut : true).
● error_page : URL de la JSP prenant en charge les exceptions rencontrées.
● extends : classe parente dont dérivera la servlet générée.
● isErrorPage : indique si la page courante est une errorPage. Default=false.
L’instruction suivante illustre l’importation de paquetages au sein d’une page JSP :
Attribut de la directive include
La directive include ne possède qu’un unique attribut dénommé file. Celuici indique le nom d’un document HTML ou
d’une page JSP à inclure automatiquement dans la page courante.
Principaux attributs de la directive taglib
● uri : identifie de manière unique le descripteur d’une bibliothèque de balises personnalisées à utiliser dans
la page JSP.
● prefix : chaîne utilisée pour distinguer des instances de balises personnalisées.
La directive taglib permet donc d’étendre le jeu de balises JSP standard par l’emploi de bibliothèques de balises
personnalisées.
b. Les actions
Les actions standards constituent un moyen technique destiné à encapsuler les tâches réalisées les plus
couramment. Elles se présentent sous la forme de balises incorporées dans les pages JSP. Au cours de la compilation
de la servlet, le conteneur rencontre ces balises et les remplace par le code Java correspondant.
Voici les différents types d’actions standards :
L’action <jsp:useBean>
Les attributs de cette action permettent de faire correspondre un nom de variable au JavaBean, et de lui affecter une
durée de vie grâce à la notion de portée (page, session, application). Suivant la portée choisie, le JavaBean peut ou
non être accessible à partir d’autres pages JSP.
L’action <jsp:setProperty>
Cette action est utilisée conjointement à <jsp:useBean>. Elle permet de définir les valeurs des propriétés d’un
JavaBean.
La définition des propriétés d’un bean peut être assurée de plusieurs manières :
● À l’aide des paramètres de requêtes. Toutes les propriétés du bean sont spécifiées grâce aux informations
fournies :
http://www.monserveur.fr/maPage.jsp?nom=dupond&prenom=paul
<jsp:setProperty name="nomBean" property="*" />
● Grâce à l’utilisation explicite d’un nom de propriété :
L’action <jsp:getProperty>
Cette action est également utilisée conjointement à <jsp:useBean>. Elle permet d’accéder aux valeurs des propriétés
d’un JavaBean.
L’exemple suivant illustre l’utilisation conjointe des actions <jsp:useBean>, <jsp:getProperty> et <jsp:setProperty>
dans une page JSP :
L’action <jsp:forward>
Elle permet la redirection de la requête, au moment de l’exécution, vers une ressource statique, une servlet, ou une
autre JSP. Son usage interrompt l’exécution de la page courante. Cette action peut ellemême contenir des actions
<jsp:param>.
<jsp:forward page="pageSuivante.jsp">
{<jsp:param .../>}
</jsp:forward>
L’action <jsp:include>
Cette action fournit un mécanisme pour inclure dans la page des ressources statiques ou dynamiques externes (par
exemple, autres pages JSP ou HTML). Elle peut ellemême contenir des actions <jsp:param>, constituant les
paramètres à passer à la ressource à inclure.
<jsp:include page="hautPage.jsp">
{<jsp:param ... />}
</jsp:include>
L’action <jsp:plugin>
L’action <jsp:param>
Cette action est utilisée uniquement conjointement à <jsp:include>, <jsp:forward> ou <jsp:plugin> : elle permet de
créer des paires nom/valeur, qui tiennent lieu de paramètres passés aux actions dans lesquelles elles sont placées.
<jsp:params>
<jsp:param name="nom" value="DUPONT" />
</jsp:params>
c. Les objets implicites
Les objets implicites sont des objets accessibles dans toute page JSP, sans qu’il soit nécessaire de les instancier au
préalable. Les spécifications JSP précisent que tous les langages de scripts pouvant servir à créer des pages JSP
doivent permettre d’utiliser ces objets.
Ces objets implicites sont bien sûr instanciés à partir de classes ou interfaces disponibles dans le JDK (Java
Development Kit) ou dans le JSDK (Java Servlet Development Kit) Package javax.servlet.
Voici un récapitulatif des principaux objets implicites :
application
Représente le contexte d’exécution des servlets. Il s’agit d’un objet de type javax.servlet.ServletContext
disposant de la portée session.
out
Correspond au JspWriter rattaché au flux de sortie. Il dispose de la portée page.
page
Correspond à l’objet "this" représentant la page en cours. Il dispose de la portée page.
pageContext
Représente le contexte de la page en cours. Sa portée est page.
request
Représente la requête soumise au moteur de servlet par le client (navigateur). Cet objet est issu de
javax.servlet.ServletRequest. Sa portée est request.
response
Représente la réponse retournée par le moteur de servlet au client. Il s’agit d’un objet implémentant l’interface
javax.servlet.http.HttpServletResponse, dont la portée est page.
session
Représente la session propre au client. De type javax.servlet.http.HttpSession, cet objet dispose de la portée
session.
d. Les scripting JSP
Les déclarations
Les déclarations sont utilisées pour déclarer des variables et des méthodes au sein d’une page JSP. Elles sont
initialisées lors de l’initialisation de la page JSP. Dès que cette opération est réalisée, elles sont disponibles pour
toutes les autres déclarations et expressions, ainsi que pour les scriptlets.
Les expressions
Les expressions permettent d’évaluer le résultat d’une instruction sous la forme d’une chaîne de caractères, et de
l’inscrire immédiatement sur le flux de sortie. Lorsque le résultat de l’instruction ne peut pas être converti en chaîne
de caractères, une exception est levée.
<HTML><BODY>
...
Bonjour Monsieur <%= getNom()%>
</BODY></HTML>
Les scriptlets
Les scriptlets servent à regrouper tous les éléments de scripts entre les balises <% et %>. Ils peuvent contenir toute
instruction de code compatible avec le langage mentionné dans l’attribut language de la directive page.
L’installation de l’environnement se fait en deux étapes :
1. Choix d’une implémentation JSF
Il existe différentes implémentations permettant d’exploiter la technologie Java Server Faces, notamment MyFaces et
Sun JSF 1.2 RI. Les exemples et illustrations présentés dans cet ouvrage ont été réalisés à partir de cette dernière
implémentation, à laquelle ont été joints quelques autres composants destinés à faciliter la conception des
applications web. Au final, les fichiers suivants ont été utilisés pour implémenter JSF dans le cadre des exemples
présentés dans cet ouvrage :
common-annotations.jar
commons-beanutils.jar
commons-collections.jar
commons-digester.jar
commons-logging.jar
jsf-api.jar
jsf-impl.jar
jstl.jar
standard.jar
Ces fichiers peuvent être obtenus sur le site des Éditions ENI : www.editionseni.fr
2. Installation et configuration de Eclipse et de la Web Tool Platform
Pour installer l’IDE Eclipse, il suffit de télécharger l’une des versions de ce produit prenant en charge J2EE. La version
utilisée dans le cadre de cet ouvrage est Eclipse Europa (Eclipse v3.3.2) disponible à l’adresse
http://www.eclipse.org/downloads/packages/release/europa/winter
Une fois le produit installé et activé, il est possible de créer un premier projet exploitant la technologie JSF en suivant
les étapes suivantes :
■ Déclarer l’implémentation JSF, évoquée précédemment, à partir du menu Window Preferences. En déployant le
nœ ud Web and Xml de l’arborescence, on accède successivement aux nœ uds Java Server Faces Tools, puis
Libraries. Il est alors possible de définir la bibliothèque d’archives Jar mettant en œ uvre les composants JSF. Le
nom de cette bibliothèque peut être choisi librement. Par contre, il est indispensable de cocher la case intitulée Is
JSF Implementation.
■ La création d’un projet web dynamique se fait ensuite par utilisation du menu File New Project. La fenêtre qui
apparaît permet de sélectionner le choix Dynamic Web Project proposé dans l’arborescence du nœ ud Web. Il faut
alors mentionner un nom de projet, préciser le nom et la localisation du moteur de servlets dans la zone Target
Runtime, et sélectionner la configuration JavaServer Faces v1.2 Project depuis la zone Configurations.
Il est ensuite possible d’accepter toutes les options proposées dans les deux écrans suivants (visibles en cliquant
successivement deux fois sur le bouton Next). Lorsque la rubrique d’options dénommée JSF Capabilities est
affichée, il est indispensable de préciser l’implémentation JSF à utiliser dans le cadre de ce nouveau projet : cela se
fait grâce aux boutons radio JSF Libraries. Attention, il est impératif de cocher la case Deploy avant de cliquer sur
le bouton Finish.
■ Une fois ces opérations réalisées, le nouveau projet web dynamique est convenablement configuré. Il est donc
possible de lui adjoindre différentes ressources, telles que des classes, des pages JSP ou HTML.
● Deux bibliothèques de balises spécifiques, étendant le jeu de balises standards JSP. Cellesci sont conçues
pour faciliter l’intégration des composants graphiques dans les pages JSP, ainsi que pour permettre leur liaison
avec les composants côté serveur.
● Une API spécifique permettant de disposer d’une représentation des composants graphiques côté serveur,
d’assurer la gestion des événements et la validation des données saisies. Cette API offre également un
support pour l’internationalisation des applications web.
Grâce à une évolution des spécifications JSP et l’introduction d’un langage d’expressions spécifique à JSF, il est
aujourd’hui possible de développer une application web Java dont l’interface prend instantanément en charge les
événements générés par les actions de l’internaute. Alors qu’une application JSP standard ne supporte qu’un unique
cycle de vie de type requête/réponse, une application JSF s’appuie sur un cycle de vie à phases multiples permettant la
gestion événementielle, la liaison de composants visuels avec des JavaBeans, ainsi que la mise en place de processus
automatiques de conversion et de validation des données saisies.
L’exploitation de ces fonctionnalités est particulièrement facilitée par l’usage du langage d’expressions propre à JSF,
unifié au langage d’expressions initialement conçu pour JSP. Là où le langage ne permettait auparavant que l’accès en
lecture seule des propriétés de JavaBeans, il est maintenant possible d’accéder en lecture comme en écriture à ces
propriétés. En outre, ce langage unifié permet d’invoquer les méthodes de JavaBeans et d’évaluer les expressions en
instantané comme en différé.
1. Principe
Globalement, il est possible de considérer le cycle de vie d’une page JSF comme semblable à celui d’une page JSP : un
client web émet une requête HTTP vers la page en question, puis le serveur qui l’héberge répond en renvoyant une
page traduite en HTML. Mais en réalité, le cycle de vie d’une page JSF est partitionné en plusieurs phases, dans le but
de pouvoir répondre efficacement aux attentes liées à cette technologie : capture d’événements au niveau des
composants graphiques, validation ou conversion de composants, liaison entre composants d’interface et objets
s’exécutant côté serveur.
Deux types de requêtes doivent être distingués :
● la requête initiale au cours de laquelle l’internaute accède pour la première fois à la page JSF,
● la requête dite postback correspondant le plus souvent à la validation d’un formulaire précédemment chargé
dans le navigateur du client.
Lorsque l’application web traite une requête initiale, seules les phases de restitution de la vue et de traduction de la
réponse sont exécutées. Le traitement d’une requête postback requiert quant à lui le passage par chacune des
phases du cycle de vie de la page JSF, sauf en cas d’erreur, dans le but de réaliser toutes les conversions et
validations nécessaires. La page est ensuite restituée au client.
2. Présentation des différentes phases
a. Phase Restitution de la vue (Restore view)
Dès qu’un internaute tente d’atteindre une page JSF, la phase de restitution de vue est exécutée. Son but est
d’associer une vue à la page visitée. L’application web crée une vue vierge dans le cas d’une requête initiale ; elle
restitue la vue précédemment associée à la page dans le cas d’une requête postback. Tous les gestionnaires
d’événements ainsi que les validateurs requis par les composants graphiques de la page sont liés à la vue. Un arbre
de composants est constitué. La vue est ensuite sauvegardée dans l’objet prédéfini FacesContext.
Dans le cas d’une requête initiale, le déroulement du cycle de vie se poursuit par la phase de traduction de la
réponse : un appel de la méthode renderResponse sur l’objet FacesContext provoque la traduction de la vue, puis sa
restitution au client.
Si l’accès à la page JSF se fait par l’intermédiaire d’une requête postback, la restitution de la vue se fait compte tenu
des informations fournies dans la requête. Celleci prend également en charge les données éventuellement stockées
sur le serveur à l’occasion d’une précédente consultation de la page. JSF assure en effet la conservation des
informations de requêtes sur le serveur : ce mécanisme permet, par exemple, de restituer facilement à un internaute
les données que celuici a déjà saisies dans un formulaire.
b. Phase Application des paramètres de requête (Apply request values)
À l’issue de la phase précédente, une vue est associée à la page JSF visitée. Cette vue dispose obligatoirement d’un
arbre de composants. Ces composants sont alors parcourus successivement pour invoquer leur méthode decode().
Celleci est chargée d’analyser la requête pour attribuer au composant la valeur qui doit lui être affectée.
Il est courant que cette affectation de valeur nécessite une conversion préalable : c’est le cas notamment lorsqu’une
zone de texte de formulaire est associée à une propriété de composant dont le type est numérique. Si cette
conversion échoue, un message d’erreur est automatiquement attribué au composant en question, puis placé en
attente de traitement dans l’objet prédéfini FacesContext. Ce message est ensuite pris en charge durant la phase de
traduction de la réponse pour être présenté à l’internaute, en même temps que les éventuels messages de
validation produits lors de la phase Processus de validation (voir cidessous). Un comportement similaire se produit si
l’affectation d’une valeur au composant est soumise à une validation préalable, par exemple pour s’assurer qu’une
valeur numérique saisie dans une zone de texte est bien comprise entre deux valeurs V1 et V2.
En plus de permettre l’analyse de la requête et l’attribution de valeurs aux composants, la phase Application des
paramètres de requête transmet les événements générés au niveau des composants graphiques présentés dans la
page JSF au contexte JSF.
À la fin de cette phase, tous les composants associés à la vue disposent d’une nouvelle valeur. Les messages et les
événements éventuels sont en attente de traitement par l’objet FacesContext.
c. Phase Processus de validation (Process Validations)
Dans cette étape, l’application JSF effectue toutes les validations attendues pour chacun des composants de l’arbre
associé à la vue.
Pour cela, les attributs de composant définissant les règles de validation sont examinés, puis comparés à la valeur
du composant. Lorsque cette valeur est effectivement incorrecte, un message d’erreur est ajouté à l’objet
FacesContext et le cycle de vie se poursuit directement par la phase de traduction de la réponse : la page web est
alors restituée à l’internaute, accompagnée du message d’erreur issu du processus de validation.
d. Phase Mise à jour du modèle (Update Model Values)
Chaque composant d’interface JSF peut être associé à un JavaBean côté serveur. Après s’être assurée de la validité
des données saisies lors de la phase Processus de validation, l’application JSF parcourt à nouveau l’arbre de
composants pour affecter la valeur de chaque composant graphique au JavaBean qui lui est associé. Là encore, si un
problème de conversion survient au moment de la mise à jour de la propriété du JavaBean, le cycle de vie de la page
se poursuit directement par la phase de traduction de la réponse et un message d’erreur adapté est présenté à
l’internaute.
e. Phase Appel de l’application (Invoke application)
Lorsque l’internaute valide un formulaire, ou clique sur un lien hypertexte, l’application JSF génère respectivement un
objet de type "événement de formulaire" ou un objet de type "événement de commande". Ces objets sont qualifiés
d’événements de niveau application : ils sont pris en charge par des gestionnaires spécifiques au cours de cette
phase dont le rôle est de mentionner une URL vers laquelle la navigation est dirigée.
f. Phase Restitution de la réponse (Render response)
Cette phase correspond au moment où l’implémentation Java Server Faces rend la main au conteneur en charge des
pages JSP de l’application web. Tous les composants sont alors présentés dans l’interface utilisateur, dans l’état qui
est le leur au moment où survient la phase Render response.
1. Évaluation instantanée d’une expression
Une demande d’évaluation instantanée d’expression au sein d’une page JSP se fait à l’aide de la syntaxe ${}. Elle
peut être utilisée directement dans le texte brut de la page, ou être représentée en tant valeur de l’attribut value
d’une balise. Il faut alors, dans ce deuxième cas, que la TLD (Tag Library Description) de la balise en question autorise
effectivement l’utilisation d’une expression en tant que valeur de l’attribut value.
Le code source cidessous est un exemple dans lequel sont présentés ces deux modes de prise en charge de
l’évaluation instantanée :
Dans cet exemple, une première utilisation de l’évaluation instantanée dans un texte brut est effectuée par
l’instruction ${sessionScope.leNom} : l’expression à évaluer concerne la variable de session leNom, instanciée par le
biais de une balise <c:set>, dont l’accès est rendu possible par l’exploitation de l’objet implicite sessionScope. Une
seconde utilisation de l’évaluation instantanée dans un texte brut est présentée à la fin du code source au travers de
l’instruction ${laPersonne.nom} : cette fois, l’expression à évaluer concerne la propriété nom d’un JavaBean instanciée
dans la page par l’intermédiaire d’une balise <jsp:useBean>.
Cette expression est par ailleurs également utilisée en tant que valeur de l’attribut value d’une balise <c1.out>.
Qu’une demande d’évaluation instantanée d’expression soit directement faite dans un texte brut, ou qu’elle le soit au
travers de l’attribut value d’une balise particulière, elle ne peut concerner que des tentatives d’accès en lecture
uniquement. Il n’est notamment pas possible d’utiliser une évaluation instantanée d’expression pour mettre à jour
une propriété spécifique d’un JavaBean.
Ce mode d’évaluation, introduit avec la technologie Java Server Faces, peut être exploité à n’importe quel moment du
cycle de vie d’une page web. Une expression à évaluation différée est symbolisée dans le code source d’une page
par la syntaxe #{}. Elle ne peut pas être utilisée directement dans le texte brut d’une page web, contrairement à
l’expression à évaluation immédiate. Dans l’exemple ciaprès, l’attribut value d’une balise <h:inputText> représentant
un champ de saisie de type HtmlInputText possède la valeur #{laPersonne.nom} : il s’agit d’une expression à
évaluation différée permettant d’accéder, en lecture comme en écriture, à la propriété nom d’un JavaBean nommé
laPersonne.
L’utilisation d’une expression à évaluation différée permet toujours d’accéder en lecture et en écriture à une
donnée particulière.
<html><head><title>Test de<html>
<head>
<title>Test de l’évaluation différée</title>
</head>
<jsp:useBean id="laPersonne" class="premierProjetJSF.Personne"
scope="session"></jsp:useBean>
<body>
<f:view>
<h:form>
<h:panelGrid border="0" columns="1">
<h:panelGroup>
<h:panelGrid border="0" columns="2">
<h:outputText value="Votre nom:" id="idotxt1">
</h:outputText>
<h:inputText id="itxtNom"
value="#{laPersonne.nom}">
</h:inputText>
</h:panelGrid>
</h:panelGroup>
<h:commandButton id="btnValider" value="Valider">
</h:commandButton>
</h:panelGrid>
</h:form>
</f:view></body>
</html>"
Lorsque la page correspondant au code source précédent est invoquée pour la première fois, l’évaluation de
l’expression #{laPersonne.nom} se fait au moment la phase de restitution de la réponse. Un accès en mode lecture à
la propriété nom du JavaBean est alors assuré : si cette propriété possède effectivement une valeur, celleci est
présentée à l’internaute dans le champ de saisie.
En dehors de l’accès initial à la page web, en particulier lors de la soumission du formulaire, l’expression est évaluée
à différents stades du cycle de vie, afin de permettre la mise à jour de la propriété nom du JavaBean en fonction de la
saisie réalisée par l’internaute. Cette opération est en particulier assurée lors des processus de validation et de
conversion de l’information.
Dans l’exemple proposé, l’évaluation différée d’expression est utilisée pour accéder aux propriétés d’un objet
particulier. Mais l’évaluation différée peut également s’appliquer à une expression permettant d’invoquer une
méthode particulière d’un objet. Ces deux notions sont abordées plus précisément dans les paragraphes qui suivent.
Les objets utilisables dans les expressions (que leurs évaluations soient immédiates ou différées) sont de quatre
types : ils peuvent être des JavaBeans, des collections, des énumérations, ou l’un des objets implicites définis par la
spécification. Définir une expression faisant appel à un objet particulier revient à mentionner l’identifiant de l’objet en
question, tel qu’il a été déclaré d’une manière ou d’une autre auprès de l’application web. Ainsi, les expressions
${laPersonne} et #{laPersonne} sont deux expressions valables pour accéder à un objet dont l’identifiant est
laPersonne. Cet objet a par exemple pu être préalablement instancié en tant que JavaBean grâce à une balise
<jsp:useBean> située dans une page JSP, ou déclaré en tant que bean managé de l’application web, par l’intermédiaire
des lignes suivantes définies dans le fichier de configuration de l’application (en général nommé facesconfig.xml).
<managed-bean>
<managed-bean-name>
laPersonne</managed-bean-name>
<managed-bean-class>
premierProjetJSF.Personne
</managed-bean-class>
<managed-bean-scope>
Session
</managed-bean-scope>
</managed-bean>
Concrètement, l’évaluation d’une expression comportant uniquement l’identifiant d’un objet est assurée par
l’application web au travers de l’invocation de la méthode findAttribute sur l’objet représentant le contexte
d’application luimême. L’identifiant de l’objet est passé en paramètre de cette méthode. Celleci se charge alors de
rechercher successivement l’objet en question dans les différentes portées : page, request, session et enfin
application. Si l’objet est trouvé, sa valeur est convertie en chaîne de caractères, puis renvoyée à l’internaute. Dans le
cas où l’objet n’existe pas, la valeur null est renvoyée.
Comme cela a déjà été évoqué dans les exemples proposés précédemment, l’accès aux propriétés d’un JavaBean se
fait par l’intermédiaire de l’opérateur point ("."). Il est également possible de faire appel à la notation par crochets
("[…]") pour obtenir le même résultat. Bien sûr, pour faire écho à la remarque faite plus haut à propos des types
d’objets exploitables, ces notations peuvent également servir à obtenir une instance particulière d’une énumération,
ou un élément spécifique d’une collection. Ainsi, les deux expressions qui suivent sont équivalentes : elles permettent
toutes deux d’atteindre la propriété nom d’un JavaBean dont l’identifiant est laPersonne :
${laPersonne.nom}
${laPersonne["nom"]}
Lorsqu’une propriété particulière correspond ellemême à une instance de classe, il est également possible d’atteindre
les propriétés de cette instance. L’exemple suivant illustre deux moyens d’afficher le nom de la ville du lieu de
résidence d’une personne : l’objet laPersonne dispose d’une propriété adresse, issue d’une classe personnalisée
possédant une propriété ville.
${laPersonne.adresse["ville"]}
${laPersonne.adresse.ville}
Dans le cas de l’utilisation d’expressions en tant que valeur de l’attribut value d’un composant JSF, il est possible de
combiner de multiples expressions, en les associant éventuellement avec du texte brut, comme le montre l’exemple
suivant :
<h:outputText
value="#{laPersonne.nom} (#{laPersonne.age} ans)"
id="idotxt2">
</h:outputText>
<f:view>
<h:form>
<h:inputText
id="txtCommentaire"
validator="#{beanAttributValidator.checkName}"
label="Commentaire"
required="true"
requiredMessage="Saisie obligatoire!">
</h:inputText>
<h:commandButton
id="btnValidation"
value="Valider"
actionListener="#{beanAction.traitementClic}">
</h:commandButton>
</h:form>
</f:view>
Le code source cidessus montre qu’une balise <h:inputText>, représentant un champ de saisie de type zone de texte,
possède un attribut validator. La valeur de celuici correspond à une expression de méthode, dont l’interprétation
provoque l’appel de la méthode checkName d’un bean managé nommé beanAttributValidator. Cette méthode peut par
exemple être chargée de vérifier que l’information saisie dans la zone de texte contient au moins une occurrence de la
lettre F.
De même, le code source présente une balise <h:commandButton>. Celleci est restituée graphiquement sous la forme
d’un bouton de soumission de formulaire. Elle dispose d’un attribut actionListener, dont la valeur correspond à une
expression de méthode. La méthode en question se nomme traitementClic et est définie dans une classe dont le
bean managé beanAction est une instance. Le rôle de la méthode est d’assurer la gestion des clics réalisés par
l’utilisateur sur le bouton de soumission.
L’évaluation des expressions de méthodes indiquées a lieu de manière différée : cela doit systématiquement
être le cas, dans la mesure où les traitements demandés peuvent être assurés à différentes étapes du cycle
de vie de la page JSP. Par exemple, la méthode mentionnée dans l’attribut validator de la balise <h:inputText> est
appelée durant la phase Process Validation, alors que la méthode traitementClic est invoquée pendant la phase
Invoke Application.
Dans l’exemple proposé, les beans managés évoqués peuvent être d’un type quelconque. Par contre, les méthodes
mentionnées dans les expressions doivent se conformer aux contraintes indiquées dans la TLD (Tag Library Description).
En l’occurrence, la signature de la méthode utilisée comme valeur de l’attribut actionListener d’une balise
<h:commandButton> doit obligatoirement posséder un argument de type ActionEvents. De même, une expression de
méthode utilisée comme valeur de l’attribut validator d’une balise <h:inputText> doit impérativement faire référence à
une méthode possédant trois arguments : le premier de type FacesContext, le second de type UIComponent et le
troisième de type Object.
D’une manière générale, la signature d’une méthode utilisée dans une expression de méthode dépend donc de
l’attribut de balise dans lequel elle est placée. L’ensemble des contraintes à respecter peut être retrouvé sur le web,
dans les pages de documentation concernant les TLD (par exemple, à l’adresse
http://java.sun.com/javaee/javaserverfaces/1.2/docs/tlddocs/index.html).
Opérateurs logiques : and, &&, or, ||, not, !
Opérateurs relationnels : ==, eq, !=, ne, <, lt, >, gt, <=, ge, >=, le.
Il existe en outre un opérateur particulier noté empty, permettant de savoir si la valeur d’une propriété ou le résultat
d’une méthode est null.
Voici un exemple de page JSP, illustrant l’exploitation de ces différents opérateurs dans des expressions :
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-
8859-1">
<title>Test des opérateurs dans les expressions</title>
</head>
<jsp:useBean id="laPersonne1" class="premierProjetJSF.Personne"
scope="session"></jsp:useBean>
<jsp:useBean id="laPersonne2" class="premierProjetJSF.Personne"
scope="session"></jsp:useBean>
<body>
La personne n°1 est-elle un client de la boutique ayant commandé
dans le mois en cours?
${laPersonne1.clientBoutique and laPersonne1.achatMoisCourant}
<br>
La personne n°2 a-t-elle le même âge que la personne n°1?
${laPersonne1.age == laPersonne2.age}
<br>
La personne n°2 habite-t-elle dans la même ville que la personne
n°1?
${laPersonne1.adresse.ville ne laPersonne2.adresse.ville}
<br>
La personne n°2 dispose-t-elle d’une adresse email ?
${!empty laPersonne2.email}
</body>
</html>
1. Principaux attributs communs aux balises de la bibliothèque HTML
Attribut binding
Sert à indiquer une expression permettant de lier le composant représenté par la balise avec une propriété de
JavaBean.
Attribut id
Permet d’indiquer l’identifiant associé au composant représenté par la balise.
2. Présentation des balises et de leurs principaux attributs spécifiques
a. Balise column
Cette balise restitue une colonne particulière d’un composant de type UIData. Ses principaux attributs sont :
footerClass
Contient une liste de classes de styles appliquées au pied de colonne. Les noms de classes de styles sont séparés
les uns des autres par le caractère espace.
headerClass
Contient une liste de classes de styles appliquées à l’entête de colonne. Les noms de classes de styles sont
séparés les uns des autres par le caractère espace.
b. Balise commandButton
Cette balise sert à représenter un bouton de soumission de formulaire ou un bouton de réinitialisation des champs
d’un formulaire. Voici ses principaux attributs spécifiques :
action
Permet de définir le cas de navigation utilisé lorsque l’internaute clique sur le composant. S’il est nécessaire
d’obtenir une génération dynamique du cas de navigation, la valeur de l’attribut action doit référencer une méthode
capable de renvoyer un objet : l’invocation de la méthode toString() de cet objet doit alors correspondre à l’un des
cas de navigation prévus dans l’application web.
actionListener
Permet de mentionner une méthode d’expression identifiant un gestionnaire d’événements capable de prendre en
charge le clic sur le composant. Ce gestionnaire d’événements est obligatoirement une méthode de type void
acceptant en argument un objet de type ActionEvent.
value
Sert à indiquer le texte affiché sur le composant. La valeur utilisée pour cet attribut peut correspondre à une
expression pointant sur une propriété de bean managé.
disabled
La valeur de cet attribut est un booléen indiquant si le composant peut, ou non, être utilisé par l’internaute. Dans le
cas où le composant n’est pas utilisable, il est graphiquement représenté par un bouton grisé.
Sert à préciser le type du composant. Les valeurs possibles sont submit, pour représenter un bouton de soumission
de formulaire, et reset, pour obtenir un bouton d’effacement des champs de formulaire. La valeur par défaut est
submit.
c. Balise form
Cette balise restitue une balise HTML correspondant à un formulaire de saisie. Elle accepte les principaux arguments
suivants :
styleClass
Liste des classes de styles appliquées lorsque ce composant est restitué graphiquement dans l’interface web. Les
noms des classes de styles sont séparés les uns des autres par le caractère espace.
target
Indique la frame dans laquelle le résultat de la soumission du formulaire sera affiché.
d. Balise inputHidden
Cette balise permet de représenter un champ de formulaire caché. Parmi ces attributs, les plus remarquables sont
les suivants :
converter
Cet attribut sert à associer un convertisseur spécifique au composant. Le convertisseur en question doit être défini
dans le fichier de configuration des ressources de l’application web, ou correspondre à l’un des convertisseurs
standards.
converterMessage
La valeur de cet attribut correspond à un message à présenter à l’utilisateur en cas d’échec de la conversion. Ce
message vient surcharger celui qui est éventuellement défini par le convertisseur associé au composant.
required
Cet attribut est un flag permettant de préciser si le composant doit, ou non, posséder une valeur au moment de la
soumission du formulaire.
requiredMessage
Cet attribut permet d’indiquer le message à présenter à l’internaute lorsque le composant, dont l’attribut required
est positionné sur true, ne possède pas de valeur au moment de la soumission du formulaire.
validator
Cet attribut sert à associer un validateur spécifique au composant. Le validateur en question doit être défini dans le
fichier de configuration des ressources de l’application web, ou correspondre à l’un des validateurs standards.
validatorMessage
La valeur de cet attribut correspond à un message à présenter à l’utilisateur en cas d’échec de la validation. Ce
message vient surcharger celui qui est éventuellement défini par le validateur associé au composant.
value
Cet attribut permet de spécifier la valeur du composant.
valueChangeListener
La valeur de cet attribut doit contenir une méthode d’expression référençant un gestionnaire d’événement capable
e. Balise inputSecret
Cette balise est utilisée pour restituer une zone de texte de type mot de passe. Outre ses attributs converter,
converterMessage, required, requiredMessage, validator, validatorMessage, value, valueChangeListener, dont le
rôle est identique à celui qu’ils jouent dans le cadre de la balise inputHidden, la balise inputSecret peut exploiter
les attributs suivants :
disabled
Cet attribut accepte une valeur booléenne chargée d’indiquer si le composant est utilisable ou non par l’internaute.
maxlength
La valeur de cet attribut correspond au nombre maximum de caractères pouvant être saisis dans ce composant.
redisplay
Cet attribut est utilisé pour indiquer que le mot de passe éventuellement précédemment saisi dans le composant
doit être réaffiché à chaque nouvelle présentation du formulaire. Pour des raisons évidentes de sécurité, la valeur
par défaut de cet attribut est false.
f. Balise inputText
Cette balise représente un champ de saisie de type texte. Ses attributs sont identiques à ceux de la balise
inputSecret.
g. Balise inputTextArea
Cette balise représente une zone de texte multilignes, et dispose des attributs cités précédemment concernant la
balise inputHidden. Elle présente en outre les deux attributs suivants :
cols
Cet attribut accepte une valeur numérique correspondant au nombre de colonnes caractérisant le composant.
rows
Cet attribut accepte une valeur numérique correspondant au nombre de lignes caractérisant le composant.
h. Balise message
Cette balise représente un message individuel, obligatoirement associé à un composant graphique situé dans la
page web. Elle permet notamment de présenter les raisons qui ont provoqué une erreur de conversion ou de
validation de la valeur saisie dans le composant associé. Les attributs de cette balise les plus couramment utilisés
sont :
for
Cet attribut sert à préciser l’identifiant du composant JSF concerné par les messages.
errorClass, fatalClass, infoClass, warnclass
Ces quatre attributs sont utilisés pour désigner les classes de style CSS à appliquer pour des messages de niveau
de sévérité "ERROR", "FATAL", "INFO" et "WARN".
i. Balise messages
La balise messages est utilisée pour l’affichage des messages d’erreur de conversion ou de validation de la valeur
saisie dans l’un des composants JSF présent sur la page web. La plupart des attributs de cette balise sont les
j. Balise outputLink
Cette balise sert à restituer une ancre HTML. Son attribut le plus important est value : il permet de définir la valeur
de l’attribut href de l’ancre. Les principaux autres attributs sont :
converter
Cet attribut est utilisé pour affecter une instance de la classe Converter au composant.
disabled
L’utilisation de cet attribut est nécessaire pour indiquer que le composant ne doit jamais être en mesure de recevoir
le focus, ou être pris en compte au moment de la soumission du formulaire.
target
Comme c’est le cas pour la balise HTML représentant une ancre, cet attribut target permet de spécifier le nom de la
frame dans laquelle le document ciblé par le composant devra s’afficher.
k. Balise outputText
Cette balise sert à représenter un texte brut au sein d’une page web. Dans le cas où l’un des attributs styleClass,
style, dir ou lang est utilisé, le texte brut en question est restitué dans la page en étant encadré par des balises
<span> et </span>.
converter
Cet attribut est utilisé pour associer un convertisseur au composant.
value
Permet de spécifier la chaîne correspondant au texte brut à présenter dans la page.
l. Balise panelGrid
Cette balise est chargée de restituer un tableau HTML composé d’un certain nombre de colonnes. Le nombre de
lignes est déterminé dynamiquement compte tenu du nombre de composants à positionner dans le tableau. Dans
l’exemple suivant, la balise panelGrid rassemble quatre composants, représentés par des balises outputText.
La restitution correspondante est un tableau HTML de deux lignes et deux colonnes.
Voici les principaux attributs disponibles pour cette balise :
bgcolor
Cet attribut sert à indiquer la couleur de fond du tableau.
border
width
Cet attribut permet de spécifier, comme en HTML, la largeur du tableau.
footerClass, headerClass
Ces attributs servent à mentionner la liste des classes de styles applicables aux entêtes et pieds de colonnes.
m. Balise selectBooleanCheckbox
Cette balise permet de restituer un champ de saisie de type case à cocher. Elle dispose des attributs converter,
converterMessage, required, requiredMessage, validator, validatorMessage, value, valueChangeListener, déjà
évoqués pour la balise inputHidden.
n. Balise selectManyCheckbox
Ce composant permet de restituer un tableau HTML contenant un ensemble de cases à cocher. Chaque case à
cocher individuelle peut être représentée par le biais d’une balise <f:selectItem>, issue de la bibliothèque Core.
Si de nombreuses cases à cocher doivent être présentées, il est alors préférable d’utiliser une unique balise
<f:selectItems>, plutôt qu’un ensemble de balises <f:selectItem>. La présentation de la balise
selectManyListBox, située plus loin dans ce paragraphe, montre un usage possible de la balise <f:selectItems>.
La restitution dans une page HTML peut correspondre au code source suivant :
Les attributs de la balise selectManyCheckbox sont identiques à ceux de la balise selectBooleanCheckbox. Il est
néanmoins possible d’indiquer, grâce à un attribut layout, le sens d’affichage des cases à cocher : si la valeur de
cet attribut est égale à pageDirection, alors les cases seront présentées en colonne. Si l’attribut en question n’est
o. Balise selectOneListbox
Cette balise sert à représenter une zone de liste non déroulante à choix unique, correspondant à la balise HTML
<select>. Chacun des éléments sélectionnables est identifié par une balise <f:selectItem>, dont les attributs
permettent de spécifier la valeur et le label de l’élément en question. Il est aussi possible de restituer tous les
éléments au travers d’une unique balise <f:selectItems>.
Les principaux attributs de la balise selectOneListbox sont les mêmes que ceux de la balise selectBooleanCheckbox.
Un attribut size permet toutefois de définir le nombre d’éléments visibles dans la zone de liste.
p. Balise selectManyListbox
Cette balise permet de générer une zone de liste non déroulante à choix multiples. Elle est donc restituée par une
balise HTML <select> disposant d’un attribut multiple. Comme c’est le cas pour la balise selectOneListbox, les
éléments sélectionnables peuvent être représentés soit par plusieurs balises <f:selectItem>, soit par une unique
<f:selectItems>.
<h:selectManyListbox size="12">
<f:selectItems value="#{mesPrix}"/>
</h:selectManyListbox>
Dans l’exemple cidessus, les éléments de la zone de liste sont définis par une balise <f:selectItems>, dont
l’attribut value référence un bean managé nommé mesPrix. Ce bean peut, par exemple, être issu d’une classe
dérivée de ArrayList et contenir la totalité des éléments sélectionnables, qui sont en réalité des instances de la
classejavax.faces.model.SelectItem.
package premierProjetJSF;
import java.util.ArrayList;
import javax.faces.model.SelectItem;
public Prix()
{
SelectItem element;
for (int i=1;i<=100;i++)
{
element=new SelectItem(
new Integer(i),
i+".00 euros",
"Produit à "+i+".00 euros");
add(element);
}
}
}
En dehors, notamment, de l’attribut size qui permet d’indiquer le nombre d’éléments visibles dans la zone de liste,
les principaux attributs de la balise selectManyListbox sont les mêmes que ceux de la balise
selectBooleanCheckbox.
q. Balise selectOneMenu
Cette balise s’utilise pour restituer une zone de liste déroulante à choix unique. Elle ne dispose d’aucun attribut
permettant de préciser le nombre d’éléments visibles : celuici est automatiquement fixé à 1 au moment de la
restitution. De manière identique à ce qui a été précisé pour les balises selectOneListBox et selectManyListBox, les
éléments de la zone de liste déroulante à choix unique peuvent être représentés par un groupe de balises
Les principaux attributs de la balise selectOneMenu sont les mêmes que ceux de la balise selectBooleanCheckbox.
r. Balise selectManyMenu
Tout comme la balise selectManyListBox, la balise selectManyMenu permet de restituer une zone de liste non
déroulante à choix multiples. Elle dispose cependant de la particularité de ne permettre la visualisation que d’un
seul élément à la fois. La balise HTML restituée est donc <select>, avec un attribut multiple, ainsi qu’un attribut
size de valeur égale à 1.
s. Balise selectOneRadio
Cette balise permet de représenter un groupe de boutons radio. Les choix possibles peuvent être définis à l’aide
d’un ensemble de balises <f:selectItem> ou par l’intermédiaire d’une unique balise <f:selectIems>.
Les principaux attributs de la balise selectOneRadio sont les mêmes que ceux de la balise selectBooleanCheckbox. Il
existe toutefois un attribut layout permettant d’indiquer le sens de l’affichage des boutons radio (en ligne ou en
colonne).
<h:selectOneRadio id="choix5">
<f:selectItem itemValue="1" itemLabel="choix n°1"/>
<f:selectItem itemValue="2" itemLabel="choix n°2"/>
<f:selectItem itemValue="3" itemLabel="choix n°3"/>
</h:selectOneRadio>
1. Balise actionListener
L’attribut type permet de mentionner le nom complet de la classe chargée de gérer l’ActionEvent. Cette classe doit
obligatoirement implémenter l’interface javax.faces.event.ActionListener.
2. Balise convertDateTime
La balise convertDateTime est utilisée pour affecter un convertisseur de type DateTimeConverter à un composant
particulier. Cela peut permettre, par exemple, de s’assurer que la valeur saisie dans un champ correspond bien à une
date spécifiée dans un format donné. L’exemple suivant montre l’association d’une balise convertDateTime avec une
balise inputText.
a. Attribut dateStyle
Cet attribut permet de spécifier comment la date doit être formatée. Les valeurs autorisées sont default, short,
medium, long, et full. Cet attribut n’est pris en compte que si l’attribut type est positionné sur date ou both.
b. Attribut pattern
L’attribut pattern est employé pour mentionner un format de date personnalisé. Ce format doit respecter la syntaxe
mentionnée dans la classe java.text.SimpleDateFormat.
c. Attribut timeStyle
Cet attribut sert à préciser comment l’heure doit être formatée. Cet attribut n’est pris en compte que si l’attribut
type vaut time ou both. Les valeurs autorisées pour l’attribut timeStyle sont default, short, medium, long, et full.
d. Attribut type
Permet de préciser le type de conversion : date uniquement, heure uniquement, ou les deux. Les valeurs que peut
prendre cet attribut sont date, time ou both.
3. Balise convertNumber
Cette balise permet d’associer un convertisseur de type NumberConverter à un composant JSF particulier, pour
assurer un formatage correct des nombres, pourcentages et devises. Le code source suivant montre l’association
d’une balise convertNumber avec une balise inputText.
Les principaux attributs de cette balise sont les suivants :
a. Attribut pattern
Cet attribut permet de personnaliser le format à utiliser pour convertir la valeur du composant JSF.
b. Attribut type
Cet attribut sert à indiquer le type de la valeur du composant. Les valeurs autorisées sont number, currency et
percentage.
4. Balise converter
La balise converter est utilisée pour associer un convertisseur à un composant JSF particulier.
<h:inputText id="txtSaisie">
<f:converter converterId="monConvertisseurNombrePairPositif"/>
</h:inputText>
Le principal attribut de cette balise est converterId. Celuici référence un convertisseur personnalisé déclaré dans le
fichier de configuration des ressources de l’application web. Ce convertisseur est obligatoirement issu d’une classe
implémentant l’interface javax.faces.conver.Converter.
5. Balise loadBundle
Cette balise permet d’instancier un ResourceBundle particulier au sein d’une page web donnée.
<f:view>
<f:loadBundle
basename="premierProjetJSF.messages"
var="mesMessagesPerso"/>
...
</f:view>
Cette balise ne possède que les deux attributs suivants :
a. Attribut baseName
Cet attribut sert à préciser le nom de la famille du ResourceBundle à instancier.
b. Attribut var
Il est utilisé pour attribuer un identifiant spécifique au ResourceBundle créé, de manière à le rendre utilisable dans la
page JSP.
6. Balise selectItem
Cette balise permet d’associer une instance de la classe UISelectItem à un composant JSF particulier.
Comme cela a été expliqué précédemment dans la section Principaux éléments de la bibliothèque HTML de ce
chapitre, cette balise peut notamment être associée aux balises selectManyCheckbox, selectManyListbox,
a. Attribut itemDisabled
Cet attribut permet d’indiquer si l’élément sélectionnable, représenté par la balise selectItem, peut ou non être
utilisable par l’internaute.
b. Attribut itemLabel
La valeur de cet attribut correspond au label présenté à l’utilisateur dans l’interface web.
c. Attribut itemValue
La valeur de cet attribut correspond à la valeur renvoyée au serveur si l’élément en question est sélectionné au
moment de la soumission du formulaire.
7. Balise selectItems
Cette balise permet d’associer une instance de la classe UISelectItems à un composant JSF particulier. Elle peut donc
notamment servir à définir l’ensemble des éléments sélectionnables d’une zone de liste (déroulante ou non), cases à
cocher ou boutons radio. Un exemple d’utilisation de cette balise est présenté à la section Principaux éléments de la
bibliothèque HTML de ce chapitre, dans la rubrique relative à la balise selectManyListbox.
L’attribut le plus important de cette balise est value : il est utilisé pour identifier une List ou une ArrayList dans
laquelle est regroupée la totalité des éléments sélectionnables du composant JSF associé.
8. Balise validateDoubleRange
Cette balise permet d’associer une instance de la classe DoubleRangeValidator à un composant JSF particulier. Cette
action est destinée à contrôler la valeur de ce composant, qui peut notamment être un nombre décimal. L’exemple
suivant correspond à l’association de la balise validateDoubleRange avec une balise inputText.
<h:inputText id="txtDuree">
<f:validateDoubleRange minimum="10" maximum="100">
</f:validateDoubleRange>
</h:inputText>
Les deux principaux attributs de cette balise sont minimum et maximum. Ils permettent de définir respectivement les
valeurs minimales et maximales autorisées pour le composant JSF associé.
9. Balise validateLength
Cette balise permet d’associer une instance de la classe LengthValidator à un composant JSF particulier, dans le but
de contrôler la longueur de la chaîne de caractères saisie dans le composant en question.
<h:inputText id="txtCommentaire"
label="Commentaire impératif"
required="true">
<f:validateLengthminimum="5"
maximum="10">
</f:validateLength>
</h:inputText>
Les deux principaux attributs de cette balise sont minimum et maximum. Ils permettent de définir respectivement les
longueurs de chaîne minimale et maximale autorisées pour le composant JSF associé.
Cette balise joue un rôle similaire à celui de la balise validateDoubleRange : associée à un composant JSF particulier,
elle sert à définir un validateur chargé de contrôler la valeur du composant. Ce validateur est de type
LongRangeValidator : si celuici est capable d’assurer le contrôle des valeurs numériques entières, il ne peut en aucun
cas prendre en charge le traitement de valeurs numériques décimales, contrairement au DoubleRangeValidator.
Les deux principaux attributs de la balise validateLongRange sont minimum et maximum. Ils permettent de définir
respectivement les valeurs minimales et maximales autorisées pour le composant JSF associé.
11. Balise validator
Cette balise permet d’associer un validateur personnalisé à un composant JSF spécifique. Dans l’exemple suivant, la
balise validator est associée à une balise inputSecret : le validateur personnalisé peut par exemple être chargé de
vérifier la conformité d’un mot de passe compte tenu d’un certain nombre de contraintes.
Le principal attribut de cette balise est validatorId. Celuici identifie le validateur personnalisé, tel qu’il a été défini
dans le fichier de configuration des ressources de l’application web. Ce validateur doit obligatoirement être issu d’une
classe implémentant l’interface javax.faces.validator.Validator.
12. Balise valueChangeListener
Cette balise sert à associer une instance de classe implémentant l’interface ValueChangeListener à un composant JSF
particulier, dans le but de capturer les événements de type ValueChangeEvent générés par ce composant. Le code
suivant montre comment une balise valueChangeListener peut être associée à une balise inputTextarea.
<h:inputTextarea id="itaCommentaires">
<f:valueChangeListener type="premierProjetJSF.listeners.BeanValueChange
Listener"/>
</h:inputTextarea>
Le principal attribut de cette balise est type : il sert à indiquer le nom complet de la classe représentant le
ValueChangeListener.
13. Balise view
Cette balise tient lieu de conteneur pour l’ensemble des balises issues des bibliothèques HTML et Core.
Elle présente deux attributs principaux : beforePhase et afterPhase.
L’attribut beforePhase permet de spécifier une méthode dont l’invocation se produit systématiquement avant chaque
changement de phase (hormis la phase de restauration de la vue). La méthode en question doit obligatoirement être
de type void et accepter un argument de type javax.faces.event.PhaseEvent.
Il existe également de nombreux composants JSF instanciés à partir de classes dérivées de UIOutput. Les classes en
question sont représentées dans le diagramme suivant :
Outre les habituels éléments de formulaire (zones de texte, cases à cocher, zone de liste, etc.), la page principale de
l’application comporte des contraintes destinées à garantir la fiabilité des données saisies. En l’occurrence :
● Les champs Nom, Date de naissance et Sexe doivent obligatoirement être renseignés.
● Le champ Nom doit contenir un texte de longueur comprise entre 5 et 100 caractères. Une telle contrainte est,
par exemple, tout à fait envisageable dans le cas où le nom doit être par la suite stocké dans un champ de
base de données dont la longueur ne peut pas excéder 100 caractères.
● Le champ Date de naissance doit obligatoirement être au format JJ/MM/AAAA. Par exemple, 17/07/2008.
En cas de nonrespect des contraintes, des messages d’erreurs explicites devront être présentés à l’internaute, en
regard des champs de saisie concernés, dès la validation du formulaire.
1. Architecture d’une application JSF
Une application Java Server Faces doit obligatoirement respecter la spécification relative aux servlets (version 2.3 ou
plus récente), ainsi que la spécification Java Server Pages (version 1.2 ou plus récente). En conséquence,
l’architecture d’une application JSF est similaire à celle d’une application web classique mise en œ uvre par un
conteneur de servlets : l’arborescence est constituée de trois dossiers :
● Le premier, par défaut nommé src, est destiné au stockage du code source des classes Java utilisées par
l’application (JavaBean, écouteurs, validateurs personnalisés, convertisseurs personnalisés, etc.). Il sert aussi
à l’archivage des fichiers d’extension .properties, exploités notamment par l’application pour faciliter son
internationalisation.
● Le second regroupe le code compilé des classes Java évoquées précédemment. Ce dossier se nomme build.
● Le dernier dossier, appelé par défaut WebContent, contient les ressources destinées à être publiées par le
moteur de servlets, principalement les pages JSP/JSF. Ce répertoire a également pour rôle de regrouper les
fichiers de configuration de l’application web, à savoir le descripteur de déploiement, ainsi que le(s) fichier(s)
de configuration des ressources de l’application (voir cidessous).
La figure suivante montre l’architecture d’une application JSF, telle qu’elle se présente dans l’explorateur de projets
de l’environnement de développement Eclipse.
Le nom des répertoires src et WebContent peut être choisi librement au moment de la création de l’application. Dans
le cas où les valeurs par défaut ne sont pas utilisées, les choix réalisés sont mémorisés dans le fichier de
configuration du projet.
De même, lorsque le nom du fichier de configuration des ressources de l’application JSF est personnalisé (son nom
par défaut est facesconfig.xml), ou s’il existe plusieurs fichiers de configuration de ressources, les changements
sont répertoriés au sein du descripteur de déploiement par l’intermédiaire d’une balise <context-param>, comme le
montre le code source suivant :
2. Fichiers de configuration des ressources d’une application JSF
La technologie Java Server Faces est conçue pour permettre la configuration des ressources exploitables par une
application web au moyen d’un ou de plusieurs fichiers de configuration. Ces fichiers sont appelés fichiers de
configuration des ressources : ils servent à répertorier et initialiser les ressources telles que les JavaBeans et les
règles de navigation.
a. Localisation du/des fichier(s) de configuration des ressources
Comme cela a été précisé dans le paragraphe précédent, une application JSF de base utilise un unique fichier de
configuration des ressources dénommé facesconfig.xml, mais il est possible d’en définir davantage. Ces fichiers
XML contiennent tous une balise racine <faces-config> encadrant d’autres balises enfants représentant les
ressources gérées. Un exemple de contenu de fichier de configuration de ressources est présenté plus loin dans ce
chapitre.
Au moment du démarrage de l’application web, le ou les fichiers de configuration des ressources sont recherchés
dans l’arborescence selon l’un des procédés suivants :
● Recherche d’un fichier /METAINF/facesconfig.xml dans l’un des fichiers JAR éventuellement présents
dans le répertoire /WEBINF/lib de l’application web. Si ce fichier est trouvé, il est exploité en tant que
fichier de configuration des ressources.
● Recherche d’un paramètre initial nommé javax.faces.application.CONFIG_FILES dans le descripteur de
déploiement de l’application web. Lorsque ce paramètre est trouvé, sa valeur contient la liste des noms de
fichiers de configuration des ressources, séparés par des virgules. Ce mode de déclaration est pratique
lorsque l’application JSF est de taille importante et que son architecture est confiée à plusieurs personnes.
● Recherche d’un fichier facesconfig.xml dans le répertoire /WEBINF de l’application. C’est le moyen le plus
simple de configurer une application JSF ; c’est aussi le choix retenu par l’environnement Eclipse lorsque les
paramètres proposés par défaut au moment de la création d’un projet JSF sont retenus.
b. Mode d’exploitation
Toutes les applications JSF sont représentées en mémoire sous la forme d’une instance de la classe
javax.faces.application.Application. Cet objet est utilisé notamment pour regrouper toutes les ressources
utilisables.
Au démarrage de l’application, le(s) fichier(s) de configuration des ressources sont parcourus pour déterminer la
liste des objets à créer puis ajouter à l’objet Application. Plusieurs méthodes distinctes de la classe Application
sont utilisées pour réaliser ces opérations. Voici leurs signatures :
Les méthodes nommées createConverter(…) sont utilisées pour instancier les convertisseurs personnalisés, alors
que la méthode createValidator(…) sert à mettre à la disposition de l’application les validateurs personnalisés.
Quant aux méthodes createComponent(…), elles sont destinées à assurer la création des autres types de
composants JSF personnalisés.
Le code source cidessous est un extrait de fichier de configuration de ressources, dans lequel sont déclarés un
convertisseur personnalisé, un validateur personnalisé, un bean managé et une règle de navigation. Ces notions
seront étudiées plus en détail dans la suite de ce chapitre, section Navigation entre les pages, ainsi qu’au chapitre
Convertisseurs et validateurs.
<faces-config
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-facesconfig_1_2.xsd"
version="1.2">
<converter>
<display-name>
convertisseurNombrePairPositif</display-name>
<converter-id>
monConvertisseurNombrePairPositif</converter-id>
<converter-class>
premierProjetJSF.NombrePairPositifConverter</converter-class>
</converter>
<validator>
<display-name>
Validation du mot de passe</display-name>
<validator-id>
monValidateurDeMotDePasse</validator-id>
<validator-class>
premierProjetJSF.ValidatorPassword</validator-class>
</validator>
<managed-bean>
<managed-bean-name>
tirage</managed-bean-name>
<managed-bean-class>
premierProjetJSF.Tirage</managed-bean-class>
<managed-bean-scope>
session</managed-bean-scope>
<managed-property>
<property-name>
maximum</property-name>
<property-class>
int</property-class>
<value>
10</value>
</managed-property>
<managed-property>
<property-name>
minimum</property-name>
<property-class>
int</property-class>
<value>
0</value>
</managed-property>
</managed-bean>
c. Types de ressources configurables
Dans un souci de clarté du texte dans le reste de l’ouvrage, nous considérerons que les ressources des
applications web évoquées sont configurées grâce à un unique fichier de configuration des ressources.
Javabeans
La déclaration d’un JavaBean ou d’un bean managé dans le fichier de configuration des ressources se fait à l’aide de
la balise <managed-bean>. Celleci regroupe un ensemble de balises enfants dont le nom et le rôle sont précisés ci
dessous :
<managed-bean-name>
Définit la clé attribuée au JavaBean. Cette clé, valable sur la portée prévue pour le JavaBean, pourra être utilisée
dans toutes les pages web de l’application JSF pour référencer ce JavaBean en particulier.
<managed-bean-class>
Indique le nom de la classe à partir de laquelle doit être instancié le JavaBean. Cette classe doit bien sûr être
rendue accessible par l’application.
<managed-bean-scope>
Précise la portée dans laquelle le JavaBean est instancié. Les valeurs possibles pour ce paramètre sont none,
request, session et application. L’utilisation de la portée none permet d’instancier systématiquement un nouveau
JavaBean à chaque fois que celuici est référencé dans la page. Dans ce cas bien sûr, le JavaBean n’est rattaché à
aucune portée particulière.
<managed-property>
Sert à définir la valeur d’initialisation d’une propriété particulière du JavaBean.
La définition d’un JavaBean peut contenir plusieurs définitions de propriétés.
La valeur de la propriété est déclarée grâce à une balise enfant nommée <value>. Son type est indiqué par la balise
enfant <property-class>, alors que le nom même de la propriété est mentionné par la balise enfant <property-
name>.
Le fait de déclarer les JavaBeans au sein du fichier de configuration des ressources présente plusieurs avantages.
Notamment la possibilité de faire les déclarations dans un unique fichier utilisable par l’ensemble de l’application, et
la possibilité de préciser facilement la valeur des propriétés sans écrire de lignes de code Java supplémentaires.
De plus amples détails concernant l’usage de l’élément <managed-bean> sont donnés dans le chapitre Exploitation
des composants standards JSF.
Messages et labels personnalisés
Comme présenté plus loin dans ce chapitre, les applications JSF sont conçues pour faciliter l’affichage des messages
d’erreurs survenant au cours des processus de validation ou de conversion des données. Les contenus de ces
messages, qui peuvent être exposés à l’internaute par l’intermédiaire des balises <h:message> ou <h:messages>,
peuvent être définis de manière dynamique compte tenu de la logique métier de l’application. Ils peuvent aussi être
définis de manière statique au sein d’un ou plusieurs fichiers de propriétés, dont les références sont mentionnées
dans le fichier de configuration des ressources.
name=Nom
password=Mot de passe
clientcode=Code client
welcome=Bienvenue!
submit=Validez
login=Se connecter
Pour que ce fichier de propriétés soit utilisable par l’application JSF, celleci doit en connaître la référence par
l’intermédiaire du fichier de configuration des ressources. Par exemple, le fichier de propriétés dont le contenu est
présenté cidessus peut être déclaré de la façon suivante :
<faces-config 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-facesconfig_1_2.xsd"
version="1.2">
...
<application>
<message-bundle>
premierProjetJSF.messages
</message-bundle>
...
</application>
...
</faces-config>
La déclaration se fait donc à l’aide d’une balise <message-bundle>, ellemême contenue dans un élément
<application>, directement placé sous <faces-config>. Le fichier de propriétés se nomme messages.properties et
se trouve placé dans le sousrépertoire src/premierProjetJSF de l’application web.
Pour information (ce point est abordé plus en détail au chapitre Internationalisation d’une application web), l’usage
de ces messages dans une page web de l’application peut se faire en chargeant la ressource grâce à une balise
<f:loadBundle>, puis en utilisant la référence de cette ressource pour afficher une étiquette de champ de saisie. Le
code source suivant illustre cette situation :
Malgré l’intérêt que peut présenter cette forme d’utilisation des messages personnalisés, l’emploi de la balise
<f:loadBundle> dans chaque page susceptible d’exploiter le fichier de propriétés contenant les messages peut
paraître fort contraignant, en particulier lorsque le nombre des pages concernées est important. Pour lever cette
contrainte, la référence aux fichiers de propriétés peut se faire d’une autre manière dans le fichier de configuration
<application>
...
<ressource-bundle>
<base-name>
premierProjetJSF.messages
</base-name>
<var>
mesMessagesPerso
</var>
</ressource-bundle>
...
</application>
L’usage initial de l’élément <message-bundle> a été remplacé par celui de la balise <ressource-bundle>, à laquelle
sont associées les éléments enfants <base-name> et <var>. Le contenu de ce dernier élément précise l’identifiant du
fichier de propriétés, tel qu’il pourra être employé dans les différentes pages web de l’application sans qu’il soit fait
usage de la balise <f:loadBundle>.
Validateurs personnalisés
L’implémentation JSF fournit un jeu de validateurs par défaut, qui peuvent être utilisés pour répondre aux besoins
les plus courants. Cependant, ces validateurs peuvent s’avérer insuffisants dans le cadre d’applications
professionnelles où la logique métier peut imposer la mise en place de contrôles plus poussés. JSF offre donc la
possibilité de définir des validateurs personnalisés, par la création de classes Java implémentant l’interface
javax.faces.validator.Validator.
Le caractère non standard de ce type de ressource implique obligatoirement sa déclaration au sein du fichier de
configuration des ressources de l’application, grâce à l’élément <validator> directement placé sous <faces-
config> :
<validator>
<display-name>
Validation du mot de passe</display-name>
<validator-id>
monValidateurDeMotDePasse</validator-id>
<validator-class>
premierProjetJSF.ValidatorPassword</validator-class>
<attribute>
...
<attribute-name>longueurMinimale</attributeName>
<attribute-class>java.lang.Integer</attribute-class>
<default-value>5</default-value>
<attribute-name>nombreCaracteresSpeciaux</attributeName>
<attribute-class>java.lang.Integer</attribute-class>
</attribute>
</validator>
L’exemple cidessus présente la déclaration d’un validateur personnalisé nommé monValidateurDeMotDePasse. Cet
identifiant est celui qui doit être utilisé dans les pages de l’application web pour exploiter le validateur en question.
La classe à partir de laquelle est instancié le validateur est mentionnée grâce à l’élément <validator-class>. Son
nom doit être indiqué intégralement, package compris. Si le validateur requiert des attributs, ceuxci sont précisés
par leur nom et leur type grâce aux éléments <attribute>, <attribute-name> et <attribute-class>.
Pour information, un tel validateur personnalisé peut être constitué pour vérifier que la saisie d’un mot de passe
répond à certains critères précis, comme le respect d’un nombre de caractères minimal, ainsi que l’obligation de
contenir un certain nombre de caractères spéciaux (%, #, $, etc.).
L’étude des validateurs personnalisés est assurée de manière plus approfondie dans le chapitre Convertisseurs et
validateurs de cet ouvrage.
Convertisseurs personnalisés
Pour les mêmes raisons que celles évoquées à propos des validateurs personnalisés, il est indispensable de
déclarer les convertisseurs non standards dans le fichier de configuration des ressources, afin qu’ils soient
disponibles dans l’ensemble de l’application. Un convertisseur est une classe Java implémentant l’interface
javax.faces.convert.Converter, dont les références sont précisées à l’aide d’une balise <converter>. Le code ci
<converter><description>
Utilisé pour s’assurer qu’un nombre précis peut être
Stocké dans une propriété de JavaBean ne pouvant
Accueillir qu’un nombre pair positif.
</description>
<display-name>
convertisseurNombrePairPositif</display-name>
<converter-id>
monConvertisseurNombrePairPositif</converter-id>
<converter-class>
premierProjetJSF.NombrePairPositifConverter</converter-class>
</converter>
Là encore, les propriétés principales du convertisseur personnalisé se limitent à son identifiant, tel qu’il sera
exploité au sein des pages de l’application, et la classe à partir de laquelle il est instancié. Ces deux informations
sont données respectivement par l’usage des balises <converter-id> et <converter-class>.
Règles de navigation
Le fichier de configuration des ressources est aussi exploité par l’architecte de l’application pour mentionner le flot
de navigation. La navigation au sein d’une application JSF se définit à l’aide de règles de navigation qui spécifient
comment il est possible d’aller d’une page web vers une autre lorsque l’internaute active un bouton ou un lien
hypertexte.
Concrètement, une règle de navigation concerne une page source en particulier, et indique les différentes situations
qui peuvent provoquer la navigation de cette page source vers d’autres pages de l’application. Ces différentes
situations, nommées cas de navigation dans la terminologie JSF, sont le plus souvent caractérisées par un
identifiant (chaîne de caractères) et le nom de la page cible correspondante.
Voici comment se déclare une règle de navigation simple, dans le fichier de configuration des ressources :
<navigation-rule>
<display-name>
inscription</display-name>
<from-view-id>
/inscription.jsp</from-view-id>
<navigation-case>
<from-outcome>succesInscription</from-outcome>
<to-view-id>
/confirmationInscription.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>echecInscription</from-outcome>
<to-view-id>
/inscriptionImpossible.jsp</to-view-id>
</navigation-case>
</navigation-rule>
Une règle de navigation spécifique se définit donc à l’aide d’une balise <navigation-rule> directement placée sous
l’élément <faces-config>. La page source concernée par la règle est indiquée par le contenu de l’élément <from-
view-id>. Dans le cas où cet élément n’est pas précisé, la règle s’applique à toutes les pages de l’application. Si une
chaîne générique est utilisée comme valeur de cet élément (par exemple, /administration/*), seules les pages qui
y correspondent sont concernées par la règle de navigation (ici, toutes les pages situées dans le sous
répertoire /administration de l’application).
Les cas de situations répondant à la règle correspondent aux balises <navigation-case>, auxquelles sont le plus
souvent associées les balises <from-outcome> et <to-view-id>. La première contient la chaîne de caractères
identifiant le cas de navigation, alors que la seconde mentionne la page cible correspondante.
L’exemple présenté cidessus correspond à une unique règle de navigation concernant la page source
inscription.jsp. Cette règle est composée de deux cas de navigation permettant de passer de la page source vers
la page cible confirmationInscription.jsp lorsque le cas nommé succesInscription est employé et de passer vers la
page inscriptionImpossible.jsp en utilisant le cas echecInscription.
D’autres détails concernant la mise en œ uvre du modèle de navigation JSF sont présentés plus loin dans ce
chapitre.
● création d’une instance de la FacesServlet ;
● conception des pages web en utilisant les différents composants graphiques ainsi que les éléments de la
bibliothèque Core ;
● spécification de la navigation au sein de l’application web ;
● développement des beans nécessaires au bon fonctionnement de l’application.
L’un des intérêts de la technologie Java Server Faces est qu’elle permet une répartition des tâches de développement
entre trois types d’intervenants. En l’occurrence :
● Le designer web, qui prend en charge la création des pages JSP/JSF et l’ergonomie générale de l’application.
Son travail est largement facilité par l’emploi des bibliothèques de balises JSF.
● Le développeur de l’application, dont le rôle consiste à créer les différents beans. Celuici est également amené
à mettre en place les éventuels composants personnalisés non graphiques, tels que les convertisseurs, les
validateurs et les écouteurs d’événements.
● Le concepteur de composants graphiques personnalisés. Naturellement, sa tâche comprend également la
gestion du rendu de ces composants graphiques.
1. Création d’une instance de la FacesServlet
Toutes les applications web basées sur JSF exploitent une instance de la FacesServlet. Celleci est utilisée pour
prendre en charge les requêtes entrantes, les analyser et les insérer dans le cycle de vie de l’application web. Elle
assure également l’initialisation des multiples ressources utilisées dans l’application.
Pour qu’une application Java Server Faces soit en mesure d’exécuter une première page JSP, le conteneur web
invoque l’instance de FacesServlet. Cela a pour effet d’enclencher le cycle de vie de l’application. L’instance en
question est identifiée au niveau de l’application par un mapping qui peut être :
● un préfixe : par exemple, /faces/* ;
● une extension : par exemple, *.faces.
Ce mapping est utilisé pour repérer les pages JSP susceptibles de contenir des éléments Java Server Faces.
Le code cidessous présente les lignes correspondant à la déclaration d’un mapping de la FacesServlet, au sein du
descripteur de déploiement d’une application web :
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
Dans cet exemple, toutes les pages JSP situées dans le sousrépertoire faces de l’application web sont susceptibles
de contenir des composants Java Server Faces. Il s’agit donc d’un mapping par préfixe qui peut, par exemple, être
facilement exploité depuis la barre d’adresse d’un navigateur web :
http://localhost:8080/monApplicationJSF/faces/index.jsp
L’exemple suivant illustre le mapping de la FacesServlet par l’extension *.faces :
Lorsque le conteneur web récupère une requête adressée à une page JSP dont le nom se termine par l’extension
faces, il la transmet à l’instance de FacesServlet. Celleci recherche alors dans l’arborescence de l’application web la
page JSP correspondant au nom mentionné, en remplaçant l’extension faces par l’extension jsp. Par exemple, si
l’utilisateur demande la ressource http://localhost:8080/monApplicationJSF/index.faces, c’est la page index.jsp qui
sera recherchée puis prise en charge par l’instance de FacesServlet.
2. Création des pages web
Cette étape consiste à réaliser les opérations suivantes :
● Positionner les composants Java Server Faces sur la page.
● Lier les composants à des propriétés de beans, lorsque c’est nécessaire.
● Référencer les éventuels convertisseurs, validateurs et écouteurs auprès des composants graphiques qui
requièrent leur existence.
a. Déclaration des bibliothèques de balises Java Server Faces
Ces actions, théoriquement à la charge du designer web, imposent la déclaration des deux bibliothèques standards
de balises JSF en entête de chaque page web. En effet, l’exploitation de composants graphiques Java Server Faces
dans les pages JSP ne peut se faire qu’à condition de savoir comment restituer à l’écran l’apparence de ces
composants : la bibliothèque HTML fournit cette information. Il est également impératif de savoir comment gérer les
actions réalisées au niveau de chaque composant graphique : c’est le rôle de la bibliothèque Core. Il faut donc
systématiquement mentionner l’accès à ces deux bibliothèques dans les pages JSP, grâce aux directives taglib
suivantes, dès lors que les pages en question font usage des balises JSF.
L’attribut uri de chacune de ces directives référence la TLD décrivant les balises contenues dans la bibliothèque
concernée. L’attribut prefix identifie le préfixe utilisé dans la page JSP pour faire référence à l’une ou l’autre des
bibliothèques. Le nom de ce préfixe peut être choisi librement.
b. Positionnement des balises view et form
Tous les composants JSF d’une page web sont regroupés dans un arbre de composants. Dans la nomenclature Java
Server Faces, cet arbre est nommé vue. La racine de cet arbre est un composant JSF issu de la classe UIViewRoot,
dont la représentation au sein des pages web se fait grâce à une balise view. Cette balise est déclarée dans la
bibliothèque Core. Au moment du développement des pages de l’application, la balise view doit impérativement être
positionnée en tant qu’élément parent de toute autre balise JSF, et en particulier de celles correspondant aux
composants graphiques.
Par ailleurs, si les pages web présentent des composants permettant aux utilisateurs de réaliser des saisies (zones
de texte, zones de liste déroulantes, cases à cocher, boutons d’options…), il est impératif d’intercaler une balise
form entre la balise view et les différentes balises représentant les composants de saisie. Cette balise form est
issue de la bibliothèque HTML et peut comporter un attribut id dont le rôle consiste à identifier de manière unique le
formulaire au sein de la page web.
Voici le contenu type d’une page JSP exploitant JSF, avant insertion de tout composant autre que view et form.
c. Ajout de composants graphiques dans une page web
Les éléments principaux des pages web sont, bien entendu, les composants graphiques à partir desquels
l’internaute est amené à interagir avec l’application web. Ces composants, décrits plus en détail dans la section Les
composants graphiques de ce chapitre, sont des objets issus de classes dérivées de la classe parente
javax.faces.component.UIComponentBase. À chacun d’eux est associée une balise spécifique de la bibliothèque
HTML. L’ajout de composants graphiques JSF à une page web consiste donc simplement à positionner dans le code
source de cette page les balises correspondant aux éléments que l’on souhaite visualiser. Il faut toutefois s’assurer
que ces balises sont bien insérées entre les éléments <f:view> et </f:view>, et que les attributs impérativement
requis sont bien renseignés.
Dans le formulaire de saisie utilisé pour illustrer ce chapitre, plusieurs composants graphiques sont utilisés :
● Les champs texte de sortie, qui servent à afficher des informations textuelles sur l’interface web. Ce type de
composant graphique est utilisé ici pour présenter l’invite située en entête de formulaire, ainsi que les
différents labels des champs de saisie. La balise à utiliser pour les champs texte de sortie est
<h:outputText>.
● Les champs de saisie de type texte : la balise qui leur correspond est <h:inputText>.
● Les zones de liste déroulantes à choix unique, représentées par la balise <h:selectOneListBox>. Cette
balise dispose de balises enfants <f:selectItem>, qui correspondent aux éléments de listes.
● Les boutons radio, générés grâce à une balise <h:selectOneRadio>. À cette balise sont associées une ou
plusieurs balises enfants <f:selectItem> pour représenter chacun des choix possibles.
● Les boutons de commande. La balise qui leur correspond est <f:commandButton>.
● Les messages qui apparaissent lorsque la validation du formulaire échoue, du fait d’une contrainte non
respectée (nombre de caractères insuffisant, mauvais format de chaîne, etc.). Ces messages sont insérés
dans la page web sous la forme d’une balise <h:message>.
Le code source de la page JSP représentant le formulaire à concevoir est situé cidessous. Tous les composants JSF
qui viennent d’être cités y sont mentionnés : ils sont accompagnés d’attributs obligatoires ou optionnels, dont la
signification sera expliquée plus loin dans ce chapitre. Notez que tous ces composants graphiques JSF sont
intercalés avec du code HTML classique, pour permettre notamment un affichage sous la forme de tableau.
<f:view>
<h:form id="formulaireInscription">
<table align="center">
<tr>
<td colspan="3">
<h:outputText value="Saisissez les paramètres suivants pour valider
votre inscription:" style="color: #0000FF; text-decoration:
underline">
</h:outputText>
<br><br>
</td>
</tr>
<tr>
<tr>
<td>
<h:outputText id="otxtPrenom" value="Prénom">
</h:outputText>
</td>
<td>
<h:inputText id="itxtPrenom" value="Prénom par défaut">
</h:inputText>
</td>
<td>
<h:message id="msgPrenom" for="itxtPrenom" style="color: #FF0000;
background-color: #FFFF00">
</h:message>
</td>
</tr>
<tr>
<td>
<h:outputText id="otxtDateNaissance" value="Date de naissance*">
</h:outputText>
</td>
<td>
<h:inputText id="itxtDateNaissance" >
</h:inputText>
</td>
<td>
<h:message id="msgDateNaissance" for="itxtDateNaissance"
style="color: #FF0000; background-color: #FFFF00">
</h:message>
</td>
</tr>
<tr>
<td>
<h:outputText id="otxtSexe" value="Sexe*">
</h:outputText>
</td>
<td>
<h:selectOneRadio id="radioSx">
<f:selectItem id="sexeChoix1" itemLabel="Masculin" itemValue="Masc" />
<f:selectItem id="sexeChoix2" itemLabel="Féminin" itemValue="Fem" />
</h:selectOneRadio>
</td>
<td>
<h:message id="msgSexe" for="radioSx" style="color: #FF0000;
background-color: #FFFF00">
</h:message>
</td>
</tr>
<tr>
<td>
<h:outputText id="otxtNombreEnfants" value="Nombre d’enfants">
</h:outputText>
</td>
<td>
<tr>
<td colspan="3" align="center">
<h:commandButton id="cmdValider" value="Valider votre inscription">
</h:commandButton>
</td>
</tr>
</table>
</h:form>
</f:view>
</body>
</html>
Les composants graphiques sont constitués côté serveur par des classes spécifiques, dérivées de la classe parente
javax.faces.component.UIComponentBase. Ces composants peuvent être associés à diverses interfaces permettant
notamment :
● le maintien de l’état entre les pages web ;
● la prise en charge de la gestion événementielle ;
● la restitution de rendus visuels spécifiques, variables suivant le composant graphique concerné.
1. Classes correspondant aux composants graphiques
Comme toutes les classes Java, la classe UIComponentBase a la possibilité d’être dérivée dans le but de permettre la
constitution de composants graphiques entièrement personnalisés. Ce point fait l’objet de l’intégralité du chapitre
Composants graphiques personnalisés de cet ouvrage.
La liste suivante présente les principales classes correspondant à des composants graphiques standards JSF. Le rôle
de ces composants y est précisé, ainsi que celui de leurs principaux attributs, modifiables par appel de méthode (ou
par précision d’un attribut spécifique dans la balise représentant le composant). Les classes sont présentées ici selon
l’ordre alphabétique.
UIColumn
Représente une colonne unique du composant UIData.
Attributs caractéristiques éventuels :
contenus de l’entête et du pied de colonne (méthodes setHeader(…) et setFooter(…)).
UICommand
Représente un composant pouvant être utilisé au niveau de l’interface web pour provoquer une action particulière. En
général, ce type de composant est restitué visuellement par un bouton, un élément de menu ou un lien hypertexte.
La méthode decode() de cette classe assure la détection de l’activation du contrôle (clic de souris, par exemple) et
place un événement de type ActionEvent en file d’attente de traitement.
La méthode broadcast() assure la diffusion de cet événement à tous les écouteurs concernés.
La méthode getActionExpression() renvoie l’expression de méthode (c’estàdire l’expression pointant une méthode
particulière d’un objet spécifique) permettant d’entreprendre l’action à réaliser lorsque l’internaute active le
composant. Suivant la valeur de la propriété immediate (voir ciaprès), l’exécution de cette action intervient soit
durant la phase Apply Request Values, soit durant la phase Invoke Application).
Attributs caractéristiques éventuels :
Liste des écouteurs d’événements associés à cette source.
Flag indiquant si le traitement des événements doit être traité immédiatement ou non (méthodes isImmediate() et
setImmediate(…)).
UIData
Ce composant est conçu pour être lié à une collection de données et en afficher le contenu suivant un rendu
particulier.
Le composant UIData le plus courant est le tableau HTML, instancié sous la forme d’un objet de type HtmlDataTable
(classe dérivée de UIData).
Contenus de l’entête et du pied de tableau (méthodes setHeader(…) et setFooter(…).
Nombre de lignes (getRowCount()), donnée située au rang courant (getRowData()).
UIForm
Représente un formulaire destiné à être présenté à l’internaute. Ce composant dispose d’un ensemble de
composants "enfants", correspondant aux différents champs de saisie utilisés dans le formulaire.
Attributs caractéristiques éventuels :
Famille à laquelle le composant est rattaché (getFamily()).
UIGraphic
Il s’agit d’un composant chargé de présenter une image à l’utilisateur. Cette image ne peut en aucun cas être
manipulée.
Attributs caractéristiques éventuels :
L’URL de l’image à présenter.
UIInput
Cette classe est dérivée de la classe UIOutput (voir cidessous).
Elle représente un composant graphique capable à la fois d’éditer du contenu (cette capacité provient de l’héritage
de UIOutput) et de recevoir des informations en saisie.
L’information stockée dans un champ UIInput est prise en charge lors de la validation du formulaire qui le contient.
Durant la phase Apply request values du cycle de vie, la valeur du composant (habituellement une chaîne de caractère)
doit être stockée au moyen de l’appel de la méthode setSubmittedValue(). À ce niveau, la valeur du composant n’a
pas encore été prise en charge par un éventuel convertisseur (voir la section Conversions de données cidessous).
Lorsque le composant UIInput ne dispose d’aucune valeur au moment de la soumission du formulaire, il a la capacité
de ne rien faire, ou de soumettre la valeur null.
Lorsque la méthode validate() de UIInput détecte un changement de valeur, et que cette nouvelle valeur subit avec
succès les processus de validation et de conversion, un événement javax.faces.event.ValueChangeEvent est placé
en file d’attente. Cet événement est par la suite propagé à l’ensemble des écouteurs concernés, par appel de la
méthode broadcast(). Cette propagation intervient en général durant la phase Process Validators, mais elle peut
toutefois intervenir pendant la phase Apply Request Values si la propriété immediate du composant UIInput est
positionnée sur la valeur true.
Attributs caractéristiques éventuels :
Liste des validateurs, modifiables par appel des méthodes addValidator(…) et removeValidator(…).
Flag indiquant si la précision d’une valeur pour ce champ est obligatoire (méthode setRequired(…)).
Message renvoyé à l’internaute en cas de non précision d’une valeur, dans le cas où celleci est requise (méthodes
getRequiredMessage() et setRequiredMessage(…)).
Message renvoyé à l’internaute en cas d’échec du processus de conversion de la valeur du champ (méthodes
getConverterMessage() et setConverterMessage(…)).
Message renvoyé à l’internaute en cas d’échec du processus de validation de la valeur du champ (méthodes
UIMessage
Ce composant assure l’affichage de messages concernant un autre composant graphique (le client) situé sur
l’interface web. Le contenu du message à afficher s’obtient à partir d’un FacesMessage généré, par exemple, par un
validateur ou un convertisseur.
Attributs caractéristiques éventuels :
L’identifiant du client, c’estàdire du composant concerné par le message (méthode setFor(…)).
UIMessages
Permet l’affichage d’un ensemble de messages dans l’interface web. Un composant UIMessages est en mesure de
présenter à l’utilisateur les éventuels messages relatifs à l’ensemble des autres composants disposés sur la page
web.
Famille à laquelle le composant est rattaché (getFamily()).
UIOutput
Ce composant est conçu pour permettre l’affichage de sa valeur dans l’interface utilisateur. Cette valeur, qui peut
notamment être obtenue dynamiquement depuis un JavaBean ou un bean managé, n’est pas modifiable par
l’internaute.
Pendant la phase Render response du cycle de vie, la valeur du composant doit être convertie en chaîne de caractères
pour pouvoir être présentée à l’écran. Cette conversion peut être assurée de deux manières :
● Dans le cas où l’objet UIOutput dispose d’un convertisseur défini (objet issu d’une classe implémentant
l’interface javax.faces.convert.Converter), la méthode getAsString() de celuici est invoquée.
● Lorsqu’aucun convertisseur spécifique n’est associé au UIOutput, la conversion est assurée par l’appel de la
méthode toString() du composant.
Si la conversion échoue, une ConverterException est générée.
Attributs caractéristiques éventuels :
Convertisseur éventuellement associé au composant (méthode getConverter()).
UIPanel
Composant jouant le rôle de conteneur d’autres composants graphiques. Il est chargé de contrôler la disposition
visuelle de ces composants.
Attributs caractéristiques éventuels :
Famille à laquelle le composant est rattaché (getFamily()).
UISelectBoolean
Cette classe dérive de la classe UIInput.
Elle correspond à un champ permettant de saisir une valeur booléenne. Le plus souvent, ce champ est représenté
par une case à cocher.
Attributs caractéristiques éventuels :
Flag indiquant si le champ est sélectionné (méthodes setSelected(…) et isSelected()).
UISelectItem
Peut être positionné au sein d’un composant graphique conteneur de type UISelectMany ou UISelectOne. L’utilisation
Attributs caractéristiques éventuels :
La description de l’élément (méthode getItemDescription()), son label (getItemLabel()) et sa valeur (getItemValue
()).
Flag indiquant si l’élément de liste est sélectionnable ou non (méthode isItemDisabled()).
UISelectItems
Ce composant peut être positionné au sein d’un composant graphique conteneur de type UISelectMany ou
UISelectOne. L’utilisation de ce composant provoque la création d’une ou de plusieurs instances issues de la classe
SelectItem. Ces instances viennent s’ajouter à la liste des autres éléments sélectionnables déjà rattachés au
composant conteneur.
La propriété value d’un UISelectItems peut contenir :
● Une unique instance de la classe SelectItem ;
● Un tableau d’instances de la classe SelectItem. Les instances en question sont alors placées dans l’ordre
numérique croissant ou dans l’ordre alphabétique.
● Une collection d’instances de la classe SelectItem ;
● Une carte (instance de la classe Map). Chaque élément de la carte est utilisé pour créer une instance de la
classe SelectItem. La clé de l’élément de carte est identifiée au label du SelectItem, alors que sa valeur est
associée à la valeur du SelectItem.
Attributs caractéristiques éventuels :
Famille à laquelle le composant est rattaché (getFamily()).
UISelectMany
Cette classe dérive de la classe UIInput.
Ce composant permet à l’internaute de réaliser une sélection multiple parmi un ensemble de valeurs prédéfinies. Ce
composant est généralement restitué visuellement selon l’une des deux formes suivantes :
● Un groupe de cases à cocher (instance la classe HtmlSelectManyCheckbox) ;
● Une zone de liste à choix multiples (instance la classe HtmlSelectManyListbox).
Un composant UISelectMany peut être configuré pour que certains des éléments qu’il contient soient présélectionnés
par défaut.
Attributs caractéristiques éventuels :
Liste des éléments sélectionnés (méthode getSelectedValues()).
UISelectOne
Cette classe dérive de la classe UIInput.
Ce composant est utilisé pour permettre la sélection d’un unique élément parmi un ensemble de valeurs prédéfinies.
Ce composant est généralement restitué visuellement sous la forme d’une zone de liste déroulante à choix unique,
ou sous la forme d’un groupe de boutons radio.
Un composant UISelectOne peut être configuré pour qu’un élément particulier soit présélectionné par défaut.
Attributs caractéristiques éventuels :
Famille à laquelle le composant est rattaché (getFamily()).
UIViewRoot
Représente la racine de l’arbre de composants.
2. Interfaces mises en œuvre par les composants graphiques
En complément du fait que les classes représentant les composants graphiques héritent de la classe
UIComponentBase, ces classes implémentent une ou plusieurs interfaces chargées de définir le comportement des
composants graphiques visàvis de certains événements. Ces interfaces de comportement, toutes issues du
package javax.faces.component, sont les suivantes :
● ActionSource : cette interface peut être implémentée par les composants susceptibles d’être la source
d’événements de type javax.faces.event.ActionEvent. Les classes standards implémentant cette interface
sont HtmlCommandButton, HtmlCommandLink et UICommand.
● ActionSource2 : cette interface étend l’interface ActionSource et fournit donc des fonctionnalités identiques.
Elle permet cependant aux composants qui l’exploitent d’utiliser le langage d’expressions pour référencer les
méthodes chargées de capturer les événements.
● EditableValueHolder : cette interface étend l’interface ValueHolder (voir cidessous). Elle propose davantage
de fonctionnalités comme la prise en charge de l’événement javax.faces.event.ValueChangeEvent et le
support de la validation des données (voir la section Validation de données de ce chapitre).
● StateHolder : cette interface permet au composant qui l’implémente de conserver son état entre les
différentes requêtes.
● ValueHolder : le composant exploitant cette interface maintient une valeur locale, et supporte la conversion
entre le type String et le type de la donnée associée, située dans la couche métier de l’application. Pour plus
d’informations sur la notion de conversion de données, voir la section Conversions de données de ce
chapitre.
La liste suivante récapitule le nom des interfaces de comportement, et précise pour chacune d’elles le(s) composant
(s) graphique(s) qui l’implémente(nt). Naturellement, les classes dérivées des classes de composants mentionnées
exploitent également les interfaces correspondantes.
Nom de l’interface Classe(s) de composant(s) implémentant l’interface
ActionSource, ActionSource2 UICommand
EditableValueHolder UIInput, UISelectBoolean, UISelectMany, UISelectOne
NamingContainer UIData, UIForm
StateHolder UIColumn, UICommand, UIData, UIForm, UIGraphic, UIInput,
UIMessage, UIMessages, UIOutput, UIPanel, UISelectBoolean,
UISelectItem, UISelectItems, UISelectMany, UISelectOne, UIViewRoot
ValueHolder UIInput, UIOutput, UISelectBoolean, UISelectMany, UISelectOne
Sur un plan purement organisationnel pour la conception de l’application web, seuls les concepteurs de composants
graphiques sont amenés à connaître/manipuler les différentes classes de composants et leurs interfaces. En
l’occurrence, il n’est pas nécessaire que ces détails techniques soient connus du designer web, puisque celuici peut
exploiter les différents composants graphiques en utilisant les balises des bibliothèques Core et HTML qui leur
correspondent.
Ce paragraphe traite du fonctionnement de la gestion du rendu des composants graphiques. Il montre également
comment les designers web peuvent mettre en œ uvre l’un ou l’autre des modes de restitution par l’utilisation de
balises adaptées.
1. Intérêt de la gestion du rendu
L’architecture de composants proposée par la technologie Java Server Faces est constituée de telle sorte que le
comportement et l’apparence des composants ne sont pas gérés ensemble. Comme cela a été présenté
précédemment, le comportement des composants graphiques est décrit au sein de classes dérivées de la classe
UIComponentBase. L’apparence des composants, quant à elle, est prise en charge par la gestion du rendu. Cette
séparation présente plusieurs avantages, notamment :
● Les développeurs de composants graphiques peuvent définir le comportement des composants qu’ils
conçoivent, et proposer pour ceuxci différentes façons de les représenter. Il est alors possible de disposer
de composants dont l’apparence peut être adaptée au client qui les affiche (un navigateur web classique sur
ordinateur, un navigateur adapté aux téléphones mobiles, par exemple).
● Les designers web peuvent rapidement changer l’apparence du composant sur une page donnée, en utilisant
une balise qui associe de manière appropriée un composant particulier et un rendu spécifique.
2. Kit de rendu Classes de rendu
Un kit de rendu définit comment les classes de composants doivent être associées aux balises de composants,
suivant le client qui les exploite. La technologie JSF inclut en standard un kit de rendu assurant la restitution des
composants graphiques pour les clients HTML.
Un kit de rendu comprend un ensemble de classes de rendu, pour chaque type de composant supporté. Chaque
classe de rendu précise la manière dont doit être restitué un composant graphique spécifique, compte tenu du type
de client mentionné dans le kit de rendu. À titre d’illustration, un composant de type UISelectOne peut être restitué
de trois façons : sous la forme d’un jeu de boutons radio, sous la forme d’une zone de liste déroulante (combo box)
ou sous la forme d’une zone de liste déroulante avec ascenseur.
Chaque balise JSP définie dans le kit de rendu standard HTML comprend à la fois les fonctionnalités du composant
concerné (définies dans la classe dérivée de UIComponentBase qui lui correspond), et les attributs de rendu, précisés
dans la classe de rendu.
3. Bibliothèque de balises pour le rendu des composants
L’implémentation JSF fournit en standard une bibliothèque de balises destinées à la restitution des composants
graphiques pour les clients HTML. Il s’agit de la bibliothèque HTML déjà traitée au chapitre Composants graphiques
personnalisés, dont les points essentiels sont rappelés ici :
Présentée sous la forme d’un
Les messages en tant que tels
sont représentés par des
chaînes de caractères.
Le chapitre Exploitation des composants standards JSF traite de façon plus approfondie la restitution des
composants graphiques au sein des pages web. Vous pourrez notamment y trouver toutes les informations
nécessaires en vue de l’intégration de composants JSF dans les pages.
1. Principe de fonctionnement de la validation
Pour exercer son rôle, un validateur doit obligatoirement être associé à un composant graphique JSF. Au moment de
la soumission du formulaire, plus précisément dans la phase Process Validators du cycle de vie, la méthode validate
(…) du validateur est invoquée, dans le but de valider la valeur mentionnée dans le composant graphique associé.
La signature de cette méthode présente trois paramètres :
● context, correspondant au contexte de l’application ;
● component, identifiant le composant associé au validateur ;
● value, représentant la valeur à contrôler.
Lorsque la validation échoue, la méthode validate(…) génère une ValidatorException, à laquelle est associé un
message explicite, fourni sous la forme d’un objet de type javax.faces.application.FacesMessage. La génération de
cette exception a pour effet d’interrompre le processus de validation du formulaire : le message rattaché à l’exception
peut alors éventuellement être présenté dans la page web, si celleci contient une balise <h:messages> ou une balise
<h:message> associé au composant graphique contrôlé.
2. Différents types de validateurs
Il existe plusieurs validateurs standards : ils permettent par exemple de contrôler la longueur d’une chaîne
(LengthValidator), de vérifier qu’une valeur numérique est bien située dans un intervalle précis
(DoubleRangeValidator ou LongRangeValidator). Les principaux validateurs standards sont présentés dans le chapitre
Exploitation des composants standards JSF.
Il est également possible de créer ses propres validateurs, en créant une classe implémentant l’interface Validator.
Ce point est traité au chapitre Convertisseurs et validateurs.
3. Exemple d’utilisation d’un validateur
Dans le cadre de l’application illustrant ce chapitre, il est nécessaire d’associer un validateur au champ permettant de
saisir le nom de la personne à inscrire. Il faut en effet, d’après les contraintes énoncées, que ce nom ait un nombre
de caractères compris entre 5 et 100. Le validateur standard apte à réaliser ce type de contrôle est un
LengthValidator.
Pour cela, le designer de la page web doit positionner une balise spécifique, issue de la bibliothèque Core,
correspondant à ce composant JSF. Il s’agit de <f:validateLength>, qui accepte deux attributs nommés minimum et
maximum, bien évidemment chargés de représenter les nombres de caractères minimaux et maximaux.
Pour associer un validateur à un composant graphique particulier, il faut placer la balise qui lui correspond entre les
balises ouvrantes et fermantes du composant. Ainsi, pour associer un LengthValidator au UIInput représentant le
champ de saisie Nom, la balise <f:validateLength> doit être insérée entre les balises <h:inputText> et
</h:inputText>.
Les modifications apportées au code source de la page sont représentées cidessous :
1. Pourquoi parler de conversion de données?
La technologie JSF est conçue pour permettre l’association entre un composant graphique présent sur l’interface web,
et une propriété d’un objet situé côté serveur (un JavaBean ou un bean managé). La section Liaison de composants
à des beans managés du chapitre Exploitation des composants standards JSF présente une mise en application de
cet artifice technologique.
Lorsque ce genre d’association est mis en œ uvre dans un processus de saisie (par exemple, si un champ UIInput est
associé à une propriété de bean managé), il est impératif qu’il y ait adéquation entre le type de la valeur saisie dans
le composant, et celui de la propriété du bean. De même, lorsqu’une telle association est utilisée dans un processus
d’affichage (par exemple, un champ UIOutput est lié à une propriété de bean), il faut que la valeur de la propriété soit
affichable ; en d’autres termes, il faut que le type de la propriété du bean managé soit compatible ou convertible en
String.
Pour respecter ces contraintes, la notion de conversion de données est mise en application. On dit qu’une conversion
est réalisée entre la vue Modèle du composant JSF, caractérisée par le type de la propriété du bean managé, et la
vue Présentation de ce même composant, visible sous la forme d’une chaîne de caractères dans l’interface web.
Il existe une autre situation dans laquelle les conversions de données peuvent être mises en œ uvre. Dans ce cas
particulier, il n’y a pas nécessairement de liaison entre un composant graphique et une propriété de JavaBean, et
l’usage de la conversion se limite au contrôle du format de la valeur saisie par l’utilisateur dans le champ de saisie
concerné. L’exemple proposé dans le cadre de ce chapitre illustre ce type d’application de la conversion de données
(le format de la date de naissance doit impérativement être jj/mm/aaaa).
2. Conversions implicites et spécifiques
Dans la plupart des situations, l’implémentation Java Server Faces assure une conversion automatique qui permet de
s’assurer de la compatibilité des types de données. C’est le cas par exemple lorsque qu’une case à cocher
(composant JSF de type UISelectBoolean) est liée à une propriété de bean booléenne : une conversion s’effectue de
manière transparente entre le type String et le type boolean.
Mais il est possible que la conversion ne soit pas réalisable automatiquement par JSF : cela se produit lorsqu’un
composant graphique est lié à une propriété dont le type n’est pas standard, ou lorsqu’il est nécessaire de
contrôler/modifier le format de la valeur saisie. Comme la mise en œ uvre de la conversion est impérative, le concept
de convertisseur est introduit par la technologie JSF. Il permet de réaliser une conversion spécifique de la valeur du
composant graphique auquel il est associé.
3. Convertisseurs standards et convertisseurs personnalisés
Un convertisseur est un objet issu d’une classe implémentant l’interface javax.faces.convert.Converter. Cette
interface présente les deux méthodes suivantes :
La méthode getAsObjet(…) entre en jeu dans un processus de saisie : elle sert à convertir la valeur de type String
saisie dans un composant graphique sous la forme d’un Object, compatible avec la propriété du bean managé lié au
composant. La valeur convertie est stockée dans la propriété en question durant la phase Apply request values du
cycle de vie.
La méthode getAsString(…) effectue l’opération inverse, permettant ainsi l’affichage dans l’interface web de la valeur
stockée dans la propriété d’un JavaBean ou d’un bean managé. L’exécution de cette méthode intervient durant la
phase Render Response du cycle de vie.
Lorsque la conversion échoue, ces méthodes déclenchent une javax.faces.convert.ConverterException, provoquant
ainsi l’interruption du cycle de vie. Le motif de l’échec de la conversion peut alors être placé dans un
javax.faces.application.FacesMessage en vue d’être présenté à l’internaute.
● Les convertisseurs numériques, adaptés aux situations faisant notamment intervenir des Integer, des Float,
des Long, etc.
● Les convertisseurs de dates, grâce auxquels il est possible de prendre en charge la conversion d’objets de
type String en objets de type Date, selon un format particulier (par exemple jj/mm/aaaa).
Il est par ailleurs possible de créer des convertisseurs personnalisés, en développant des classes implémentant
l’interface Converter. La personnalisation est alors assurée par la surcharge du comportement par défaut des
méthodes getAsString(…) et getAsObject(…).
Les convertisseurs standards sont étudiés plus en détail dans le chapitre Exploitation des composants standards JSF,
alors que le développement de convertisseurs personnalisés est traité au chapitre Convertisseurs et validateurs.
4. Exemple d’utilisation d’un convertisseur
L’exemple proposé dans le cadre de ce chapitre fait intervenir un convertisseur au niveau du champ de saisie de la
date de naissance. Il faut en effet imposer à l’internaute le respect du format jj/mm/aaaa. Comme précisé
précédemment, il ne s’agit pas ici d’assurer une conversion entrant dans le cadre d’une liaison entre le champ de
saisie "Date de naissance" et un éventuel bean managé : l’usage de la conversion se limite ici au contrôle du format
de la chaîne saisie.
Le convertisseur le plus approprié pour réaliser l’opération demandée est un composant de type DateTimeConverter
pour lequel on spécifie le format de date à respecter grâce à la méthode setPattern(…). Le designer de l’application
web, dont le métier ne l’amène pas à manipuler les classes Java, peut facilement mettre en œ uvre l’utilisation de ce
convertisseur en utilisant la balise <f:convertDateTime> de la bibliothèque Core, en précisant une valeur adaptée
pour son attribut pattern.
Pour associer ce convertisseur au champ de saisie de la date de naissance, la balise <f:convertDateTime> doit être
placée entre les balises <h:inputText> et </h:inputText> représentant le composant UIInput de la date.
Concrètement, les modifications à apporter dans le code source sont les suivantes :
<h:inputText id="itxtDateNaissance"
converterMessage="La date indiquée doit être au format JJ/MM/AAAA" >
<f:convertDateTime pattern="dd/MM/yyyy" />
</h:inputText>
Dans le cas où la conversion ne peut être réalisée (format non respecté par l’utilisateur), une ConverterException est
générée. Le motif de l’échec de conversion est généralement disponible sous la forme d’un FacesMessage, mais il est
éventuellement possible de surcharger simplement ce message si celuici ne convient pas (notamment lorsque la
langue utilisée pour le message n’est pas la même que celle employée au sein de l’interface web). Pour cela, le
designer web ajoute un attribut converterMessage à la balise <h:inputText> dont la valeur correspond au message à
afficher en cas d’erreur de conversion.
1. Principes mis en œuvre dans la gestion événementielle avec JSF
La classe de base à partir de laquelle sont définis les différents types d’événements est FacesEvent. Il s’agit d’une
classe abstraite qui permet à toutes ses classes dérivées de maintenir une référence sur l’objet à l’origine de
l’événement, ainsi que sur la description de l’événement luimême.
Pour qu’une application puisse réagir à des événements, celleci doit disposer de classes implémentant des écouteurs
(listeners) et référencer ceuxci auprès des composants susceptibles de générer les événements.
Lorsqu’un utilisateur active un composant, en cliquant sur un bouton par exemple, un événement particulier est
déclenché. À ce moment, l’application JSF invoque la méthode de l’écouteur conçu pour prendre en charge l’événement
en question.
2. Deux types d’événements exploitables
Deux types d’événements peuvent actuellement être exploités au sein des applications JSF : les événements de type
action et les événements de type value-change.
Un événement de type action survient lorsque l’internaute active un composant graphique basé sur une classe
implémentant l’interface ActionSource. Parmi ces composants, on trouve les boutons et les hyperliens, tous deux
basés sur la classe UICommand.
Un événement de type value-change survient lorsque l’utilisateur change la valeur d’un composant graphique basé sur
la classe UIInput. Cela peut correspondre, par exemple, à la sélection d’une case à cocher, à la modification du texte
contenu dans une zone de texte. Les composants standards suivants sont en mesure de déclencher ce type
d’événement : UIInput, UISelectOne, UISelectMany et UISelectBoolean. Notez que les événements value-change ne
sont générés que si le processus de validation de la valeur du composant concerné s’est réalisé avec succès.
3. Rôle de la propriété "immediate" des composants générateurs d’événements
Tous les composants graphiques qui viennent d’être cités, susceptibles d’être à l’origine de la génération d’un
événement, disposent d’une propriété nommée immediate. Cette propriété peut être lue ou modifiée respectivement
par l’appel des méthodes isImmediate() et setImmediate().
Suivant la valeur de cette propriété, les événements de type action peuvent être traités durant la phase Application
phase ou durant la phase Apply Request Values. Les événements de type value-change sont, quant à eux, traités soit
durant la phase Process Validators, soit durant la phase Apply Request Values.
4. Réaction aux événements
Il existe deux moyens exploitables pour que les composants positionnés sur une page web puissent répondre aux
différents types d’événements :
● Un écouteur, qui est un objet issu d’une classe implémentant l’interface javax.faces.event.FacesListener, ou
l’une de ses interfaces dérivées, est chargé de capturer les événements d’un type précis. Cet écouteur doit
être associé aux composants susceptibles de provoquer l’événement, par l’ajout d’une balise
<f:valueChangeListener> ou d’une balise <f:actionListener> entre les balises délimitant la définition des
composants euxmêmes.
● Affecter une méthode particulière d’un bean managé ou d’un JavaBean à la prise en charge des événements.
Le nom de la méthode en question est connu des composants susceptibles de déclencher les événements, par
l’usage d’attributs spécifiques dans les balises définissant les composants.
De plus amples renseignements concernant la mise en œ uvre de la gestion événementielle sont fournis dans
le titre Association d’écouteurs aux composants présents dans la page du chapitre Exploitation des
1. Génération des messages d’erreur issus des processus de validation ou de
conversion
Il arrive qu’au moment la soumission d’un formulaire web, la validation et/ou la conversion des données saisies
échouent. Cela se produit par exemple lorsqu’une information ne respecte pas un format requis (échec de la
conversion), ou lorsqu’une valeur numérique saisie ne fait pas partie d’une plage de valeurs particulière (échec de la
validation). Dans ces situations, les convertisseurs et/ou les validateurs associés aux composants graphiques
génèrent une exception ayant pour effet d’interrompre la soumission du formulaire.
Ces exceptions, de type ConverterException ou ValidatorException, se chargent de mettre à disposition une chaîne
de caractère précisant le motif de l’échec de la conversion ou de la validation. Cette chaîne est utilisée pour instancier
un objet issu de la classe javax.faces.application.FacesMessage.
2. Affichage de messages dans l’interface web
Au moment du réaffichage du formulaire web, le contenu d’un FacesMessage a la possibilité d’être présenté à
l’utilisateur. Pour cela, au cours de la conception du formulaire, il est nécessaire de placer un composant graphique de
type UIMessage et de l’associer à un autre composant susceptible de provoquer un échec de validation ou de
conversion au cours de la soumission du formulaire. Cet UIMessage aura alors pour rôle de présenter le contenu des
FacesMessage concernant le composant graphique auquel il est rattaché.
Ainsi, les lignes suivantes correspondent à la mise en œ uvre des messages dans le code source du formulaire
proposé en illustration de ce chapitre :
Chaque composant de type UIMessage est représenté par une balise <h:message>, issue de la bibliothèque HTML.
Cette balise dispose d’un attribut for dont la valeur correspond à la valeur de l’attribut id du composant graphique
associé. Par exemple, le message msgNom est associé au champ de type UIInput dont l’identifiant est itxtNom. À
chaque fois qu’un problème de conversion ou de validation survient à propos de ce champ, le motif du problème
pourra être présenté à l’utilisateur par l’intermédiaire du message msgNom.
3. Surcharge des informations contenues dans les FacesMessage
Les composants graphiques de type UIMessage placés au sein des pages web servent donc à présenter à l’utilisateur
le contenu du message stocké dans les éventuels FacesMessage générés au cours des processus de validation et de
conversion. Il arrive cependant que le contenu brut du message en question ne convienne pas en vue d’un affichage.
C’est notamment le cas lorsque le message comporte des détails techniques n’intéressant pas l’utilisateur final de
l’application web, ou lorsque la langue utilisée dans le message n’est pas la même que celle employée dans le reste
du site.
Dans ces situations, il est possible de surcharger le message contenu dans le FacesMessage par un message plus
adapté. Ce nouveau message peut être précisé de manière simple par le designer de l’interface web, en ajoutant aux
balises correspondant à des composants UIInput l’un des attributs suivants :
● converterMessage : utilisé pour surcharger les erreurs de conversion.
● validatorMessage : utilisé pour surcharger les erreurs de validation.
● requiredMessage : utilisé pour préciser le message à présenter lorsqu’aucune information n’a été fournie dans
un champ obligatoire. Attention, pour que cet attribut soit pris en compte, il faut que la balise représentant le
Les lignes cidessous présentent les modifications à apporter au code source du formulaire proposé en illustration de
ce chapitre, pour mettre en œ uvre la surcharge de messages.
4. Les groupes de messages
Il est également possible d’utiliser un unique composant graphique JSF chargé d’afficher sous forme de liste
l’ensemble des messages d’erreurs générés lors de la soumission d’un formulaire. Ce composant, de type
javax.faces.component.UIMessages, n’est alors pas spécifique d’un champ de saisie particulier, au contraire des
champs de type UIMessage. Il prend en charge la totalité des messages d’erreurs éventuellement issus des processus
de validation et de conversion des données saisies dans le formulaire.
L’usage des UIMessages peut notamment être intéressant lorsque l’affichage des messages d’erreurs en regard des
champs de saisie ne présente pas d’avantages, ou lorsque sur un plan purement ergonomique, il est souhaitable que
les messages apparaissent toujours à la même position sur la page web (par exemple, toujours en haut du
formulaire de saisie). Il faut toutefois prendre garde à ce que les messages à afficher soient suffisamment explicites
pour que l’utilisateur soit capable de déterminer à quels éléments de formulaire ils se rapportent. En l’occurrence, il
est souhaitable que le label des champs en question soit mentionné dans les messages.
Dans l’exemple illustrant ce chapitre, le designer web de l’application peut insérer un composant de type UIMessages
en positionnant sur la page une balise <h:messages>. Différents attributs peuvent être ajoutés à cette balise, pour
permettre notamment de préciser le style à utiliser pour l’affichage des messages. Dans le code source cidessous, le
groupe de messages est présenté à l’internaute en italique, en majuscules, avec une taille de caractères de 10pt. Le
texte est écrit en bleu sur fond jaune.
<f:view>
<h:form id="formulaireInscription">
<table align="center">
...
<tr>
<td colspan="3">
<h:messages id="groupeDeMessages" style="color: #0000FF; text-transform:
uppercase; font-style: italic; font-size: 10px; background-color:
#FFFF00; font-weight: bold" layout="table">
</h:messages>
</td>
</tr>
</table>
</h:form>
</f:view>
5. Regroupement des contenus de messages dans des fichiers de ressources
Pour garantir une bonne cohérence des messages d’erreurs délivrés sur l’ensemble des pages d’une application web,
il est fortement recommandé de définir des messages d’erreur types au sein d’un fichier texte particulier. Il est par
exemple souhaitable que le message présenté à l’utilisateur lorsqu’il oublie de fournir une valeur dans un champ
obligatoire soit toujours le même, quel que soit le formulaire de l’application web affiché à l’écran.
Dans la terminologie Java Server Faces, le fichier texte contenant les messages types est un fichier de ressources,
dont le nom possède obligatoirement l’extension properties et dont l’existence est précisée à l’application web au
travers du fichier de configuration facesconfig.xml.
Ainsi, dans l’exemple illustrant le chapitre, il est possible de définir un fichier de ressources pour regrouper les
messages types à afficher lorsque l’utilisateur omet de renseigner un champ requis, ou lorsqu’il saisit une valeur
La déclaration du fichier de ressources auprès de l’application web se fait dans le fichier facesconfig.xml par l’ajout
des lignes suivantes :
<faces-config
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-facesconfig_1_2.xsd"
version="1.2">
<application>
<resource-bundle>
<base-name>
premierProjetJSF.inscriptionsMessages
</base-name>
<var>msgs</var>
</resource-bundle>
...
</application>
...
</faces-config>
Le contenu de ce fichier de configuration indique qu’un fichier de ressources nommé inscriptionsMessages.properties
est disponible dans le sousrépertoire src/premierProjetJSF de l’application web. Il précise également que le fichier
de ressources en question peut être référencé au sein des pages web par l’usage d’une variable nommée msgs.
De fait, si l’on veut exploiter le message type proposé dans le fichier de ressources pour indiquer à l’utilisateur qu’il a
oublié de saisir une valeur dans le champ UIInput correspondant à la date de naissance, les modifications suivantes
doivent être apportées par le designer web au code source du formulaire :
<h:inputText id="itxtDateNaissance"
validatorMessage="La valeur fournie est invalide."
converterMessage="La date indiquée doit être au format
JJ/MM/AAAA"
requiredMessage="#{msgs.valeurRequise}" required="true">
</h:inputText>
L’utilisation de fichiers de ressources pour les messages est également requise dans le cadre de l’internationalisation
des applications web. Pour plus d’informations à ce sujet, reportezvous au chapitre Composants graphiques
personnalisés de cet ouvrage.
● Validation de la donnée saisie dans un composant graphique.
● Prise en charge des événements générés par un composant.
● Réalisation du traitement permettant de définir vers quelle page la navigation doit se poursuivre après la
validation du formulaire.
Ces actions sont mises en œ uvre au travers de méthodes définies dans le bean.
Ce paragraphe illustre la déclaration, la configuration et l’utilisation d’un bean managé, dans le cadre de l’exemple
d’application web proposé en début de chapitre.
1. Création d’une classe de bean s’exécutant côté serveur
Comme tous les JavaBeans, un bean s’exécutant côté serveur doit disposer d’un constructeur sans argument. Celuici
doit nécessairement être déclaré, même si son contenu est vide, de manière à ce que le bean puisse être instancié
par l’application web : son absence provoque une erreur d’exécution.
Un bean managé doit également définir autant de propriétés que de champs de saisie auquel il peut potentiellement
être lié. Ces propriétés doivent être de portée privée, et disposer d’accesseurs en lecture et en écriture pour rendre
leur accès possible depuis les pages web de l’application, ou depuis d’autres beans ou classes. De surcroît, un bean
managé peut proposer des méthodes chargées de réaliser des contrôles ou actions spécifiques, comme cela vient
d’être précisé plus haut. Naturellement, toute classe déjà existante respectant ces conventions, applicables à
l’ensemble des JavaBeans, peut être utilisée en tant que bean managé d’une application web JSF.
Le code source cidessous présente le contenu d’une classe potentiellement utilisable en association avec le
formulaire web proposé en début de chapitre. Cette classe présente des propriétés privées en mesure de stocker les
valeurs saisies dans les différents champs du formulaire (nom, prénom, date de naissance, etc.), et expose des
accesseurs publics utilisables pour lire ou modifier les propriétés en question. Enfin, cette classe propose une
méthode publique dénommée inscriptionRealisee() dont le rôle peut être d’assurer une navigation dynamique
dans l’application web (voir le titre Navigation entre les pages de ce chapitre). La classe cidessous est bien conforme
aux conventions applicables aux JavaBeans ; elle peut être donc être exploitée en tant que bean managé dans
l’application web.
package premierProjetJSF;
import java.util.Date;
public BeanInscription()
{
//Constructeur par défaut, obligatoire,
//même si son contenu est vide.
}
Lorsqu’une propriété de bean managé est liée à un composant graphique de formulaire web, son type doit être
primitif, à moins que l’application puisse disposer d’un convertisseur adapté au type personnalisé de la propriété du
bean.
La liaison de composants graphiques à des propriétés de beans managés est étudiée au chapitre Exploitation des
composants standards JSF ; un exemple plus approfondi de création de bean personnalisé est présenté au chapitre
Convertisseurs et validateurs de cet ouvrage.
2. Configuration d’un bean managé
Une fois que la classe définissant le bean managé est constituée, elle doit être rendue disponible à l’application web
pour que celleci puisse l’exploiter. Cette action se fait au travers du fichier de configuration facesconfig.xml, dans
lequel il est possible de préciser :
● Le nom de la classe correspondant au bean managé.
● Le nom du bean tel qu’il pourra être utilisé dans les pages de l’application web.
● La portée du bean (page, session ou application).
● Les valeurs par défaut potentiellement prises par les propriétés du bean au moment de son initialisation.
La classe BeanInscription présentée cidessus peut ainsi être mise à la disposition de l’application web au moyen
des lignes suivantes, à insérer dans le fichier facesconfig.xml :
<faces-config
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-facesconfig_1_2.xsd"
3. Utilisation du langage d’expressions pour exploiter les beans managés
Dès lors que le fichier de configuration de l’application web comporte des éléments indiquant l’utilisant de beans
managés, ceuxci sont instanciés au moment du lancement de l’application web ellemême. À partir du moment où l’un
d’eux est utilisé par une page web quelconque de l’application, les éventuelles valeurs initiales des propriétés du
bean sont appliquées et le bean est positionné dans la portée prévue.
Dans l’exemple proposé cidessus, le bean managé nommé beanInscription est instancié à partir de la classe
BeanInscription au moment du lancement de l’application web. Lorsqu’un premier internaute accède à une page
utilisant ce bean managé, ce dernier est placé dans la portée session, et ses propriétés nom, prenom, nombreEnfants
et sexe sont initialisées avec les valeurs prévues dans facesconfig.xml.
Lorsque des composants graphiques JSF sont liés aux propriétés de beans managés, ils peuvent facilement être
utilisés pour lire ou mettre à jour ces propriétés. Le designer web met en œ uvre cette possibilité en utilisant le
langage d’expression comme valeur de certains attributs représentant les composants graphiques. Par exemple, pour
qu’un champ UIOutput placé dans une page web puisse afficher le contenu de la propriété prenom du bean managé
beanInscription, la balise suivante doit être utilisée :
La valeur de l’attribut value de cette balise exploite bien le langage d’expression, grâce auquel sont précisés entre
les séquences de caractères #{ et } le nom du bean managé et celui de la propriété recherchée.
● De gérer les événements survenant au niveau des composants graphiques.
● De valider les données mentionnées dans les champs de saisie.
● De convertir ces mêmes données.
Dans le code source présenté cidessous, le langage d’expression est utilisé au sein de l’attribut action de la balise
<h:commandButton>. Il permet l’invocation de la méthode inscriptionRealisee() du bean managé beanInscription,
pour déterminer dynamiquement le cas de navigation lors de la soumission du formulaire.
<h:commandButton
id="cmdValider"
value="Valider votre inscription"
action="#{beanInscription.inscriptionRealisee}"
></h:commandButton>
1. Définition de règles de navigation
Dans la terminologie JSF, la navigation est définie comme un ensemble de règles utilisé pour déterminer la page qui
doit être présentée à l’internaute une fois que celuici a cliqué sur un bouton de formulaire ou sur un lien hypertexte.
Ces règles sont précisées au sein du fichier de configuration des ressources de l’application, facesconfig.xml, à
partir d’un ensemble d’éléments XML.
La démarche à adopter pour mettre en œ uvre le processus de navigation JSF consiste donc tout d’abord à déclarer
dans le fichier facesconfig.xml les différentes règles, pour lesquelles sont notamment précisés le cas de navigation
qui leur correspond, ainsi que les pages sources et cibles. Ces choix, réalisés par l’architecte de l’application web,
doivent ensuite être pris en compte par le designer web au moment de la conception des pages de l’application.
Celuici doit en effet exploiter convenablement les cas de navigation dans les attributs action des boutons et liens
hypertexte qu’il met en place.
Deux types de navigation JSF sont couramment distingués : la navigation simple, dans laquelle les cas de navigation
sont mentionnés de manière statique au sein des pages web de l’application, et la navigation dynamique, qui fait
appel aux beans managés, chargés de générer dynamiquement les cas de navigation compte tenu du contexte. Quel
que soit le type de navigation, la définition des règles de navigation reste identique.
<faces-config
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-facesconfig_1_2.xsd"
version="1.2">
...
<navigation-rule>
<display-name>
inscription</display-name>
<from-view-id>
/inscription.jsp</from-view-id>
<navigation-case><from-outcome>succesInscription</from-outcome>
<to-view-id>
/confirmationInscription.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<display-name>
inscription</display-name>
<from-view-id>
/inscription.jsp</from-view-id>
<navigation-case><from-outcome>
echecInscription</from-outcome>
<to-view-id>
/inscriptionImpossible.jsp</to-view-id>
</navigation-case>
</navigation-rule>
...
</faces-config>
Ce code source présente deux règles de navigation, définies grâce aux balises <navigation-rule>. Pour chacune de
ces règles sont précisées les informations suivantes :
● Le nom de la page web à partir de laquelle l’internaute provoquera la navigation : cette page source est
mentionnée par l’intermédiaire de la balise <from-view-id>.
Le choix de la chaîne de caractères identifiant un cas de navigation spécifique (balise <from-outcome>) peut être fait
librement. Il existe cependant quelques valeurs communément utilisées dans les applications web :
● success : employé lorsque toutes les vérifications sont réalisées avec succès.
● failure : employé lorsqu’une erreur au moins est identifiée par le processus métier chargé de réaliser les
contrôles (voir le paragraphe Utilisation de la navigation dynamique). La navigation est alors renvoyée vers
une page d’erreur.
● Logon : signifie que l’internaute doit passer par une étape d’authentification avant de poursuivre la
navigation : il est réorienté vers une page comportant un formulaire d’authentification.
● no results : utilisé dans les cas où un processus de recherche (dans une base de données, par exemple)
aboutit à une absence de résultats. La navigation est redirigée vers le formulaire de recherche.
Compte tenu de ces explications, le code source présenté plus haut montre que les deux règles de navigation sont
applicables à partir d’une unique page web source nommée inscription.jsp. La navigation est rendue possible depuis
cette page, soit par navigation simple, soit par navigation dynamique, vers la page confirmationInscription.jsp
lorsque le cas de navigation succesInscription est utilisé, ou vers la page inscriptionImpossible.jsp si le cas de
navigation echecInscription est employé.
Pour ce cas particulier, deux règles de navigation distinctes ont été définies, alors que cellesci concernent la même
page web source. Dans une telle situation, il est tout à fait possible de ne définir qu’une seule règle, regroupant les
deux cas de navigation évoqués, de sorte que le code source suivant soit équivalent à celui montré précédemment :
<navigation-rule>
<display-name>
inscription</display-name>
<from-view-id>
/inscription.jsp</from-view-id>
<navigation-case><from-outcome>succesInscription</from-outcome>
<to-view-id>
/confirmationInscription.jsp</to-view-id>
</navigation-case>
<navigation-case><from-outcome>
echecInscription</from-outcome>
<to-view-id>
/inscriptionImpossible.jsp</to-view-id>
</navigation-case>
</navigation-rule>
Sous l’environnement de développement Eclipse, ces deux cas de navigation peuvent être visualisés graphiquement,
comme le montre la figure cidessous.
Comme cela a été précisé plus haut, la navigation simple concerne les situations où les cas de navigation sont
spécifiés de manière statique au sein des pages web de l’application. Pour cela, le designer web mentionne
simplement le nom du cas de navigation à exploiter grâce à l’attribut action des composants de type UICommand qu’il
dispose sur l’interface (boutons, liens hypertexte).
Ainsi, dans l’exemple proposé pour ce chapitre, la page web inscription.jsp peut être conçue de telle façon que la
navigation s’oriente systématiquement vers la page confirmationInscription.jsp, en cas de soumission du formulaire
d’inscription. Pour cela, il est nécessaire de faire appel au cas de navigation succesInscription, défini dans le fichier
facesconfig.xml pour permettre la navigation de la première page vers la seconde. L’attribut action de la balise
<h:commandButton> représentant le bouton de soumission du formulaire est donc positionné en conséquence :
<h:commandButton id="cmdValider"
value="Valider votre inscription"
action="succesInscription">
</h:commandButton>
3. Utilisation de la navigation dynamique
Mais il est courant que la navigation simple ne convienne pas, en particulier dans le cadre d’applications web à
vocation professionnelle ou commerciale. Bien souvent en effet, la navigation est rendue dépendante d’un ensemble
de facteurs liés au contexte dans lequel s’inscrit le système d’information mis en place. La navigation peut par
exemple varier suivant le profil de l’internaute, en autorisant la visualisation de certaines pages, tout en interdisant
l’accès à d’autres ressources. Pour permettre la conception de telles applications, Il est nécessaire de mettre en
œ uvre le concept de navigation dynamique.
Avec la technologie Java Server Faces, ce type de navigation est rendu possible par l’exploitation de JavaBeans, en
partie chargés de générer dynamiquement la chaîne identifiant le cas de navigation adapté au contexte.
Concrètement, c’est une méthode spécifique de ces JavaBeans qui est identifiée pour réaliser les traitements
nécessaires et renvoyer le cas de navigation attendu. Les traitements en question peuvent consister par exemple à
vérifier les paramètres d’authentification fournis par l’internaute en interrogeant une base de données. Compte tenu
de la réussite ou de l’échec de l’opération, deux chaînes de caractères distinctes peuvent être renvoyées par la
méthode : ces chaînes doivent bien entendu correspondre à des cas de navigations prévus par l’architecte de
l’application web, de manière à pouvoir être exploitées efficacement dans le cadre d’une navigation dynamique.
L’exemple proposé dans ce chapitre peut tout à fait être mis à profit pour illustrer ce type de navigation. Plutôt que
d’orienter systématiquement la navigation depuis la page inscription.jsp vers la page succesInscription.jsp, comme
cela a été vu dans le paragraphe précédent, la navigation peut être variable suivant les informations saisies par
l’internaute, ou suivant le contexte d’application luimême. Il est par exemple possible d’envisager le succès
systématique d’une inscription (et donc la navigation vers succesInscription.jsp) dans tous les cas de figure, sauf
lorsque l’une des situations suivantes se présente :
● Le nom mentionné ne correspond pas à l’une des valeurs autorisées, spécifiées dans une table de base de
données.
● La base de données permettant de contrôler le nom n’est pas disponible.
Dans ces cas particuliers, la navigation doit être orientée vers la page inscriptionImpossible.jsp.
Pour rendre possible une telle navigation, le bean managé dénommé BeanInscription (présenté au paragraphe
Création d’une classe de bean s’exécutant côté serveur de la section Déclaration et configuration de beans managés
de ce chapitre) peut être utilisé. En déléguant l’une de ses méthodes à la réalisation des contrôles requis au moment
d’une demande d’inscription, il est possible de générer dynamiquement la chaîne de caractères identifiant le cas de
navigation à utiliser, compte tenu du résultat des contrôles. La méthode inscriptionRealisee(), dont une partie du
code source est présentée cidessous, est un exemple de méthode assignée aux contrôles à entreprendre.
if (!baseDeDonneesDisponible) casNavigation="echecInscription";
if (nomInvalide) casNavigation="echecInscription";
return casNavigation;
Pour que cette méthode puisse être invoquée au moment de la soumission du formulaire d’inscription, le designer
web doit mentionner une expression de méthode adaptée, en tant que valeur de l’attribut action de la balise
<h:commandButton>. Cette expression de méthode doit faire référence au bean managé de type BeanInscription, tel
qu’il est déclaré au sein du fichier facesconfig.xml, ainsi qu’au nom de la méthode chargée de réaliser les contrôles.
<h:commandButton
id="cmdValider"
value="Valider votre inscription"
action="#{beanInscription.inscriptionRealisee}"
></h:commandButton>
4. Rôle des instances par défaut de ActionListener et de NavigationHandler dans la
navigation dynamique
Il peut être intéressant de s’attarder plus précisément sur la façon dont est géré le traitement de la navigation par le
modèle de navigation JSF.
Au moment où l’internaute active un bouton ou un lien hypertexte au niveau de l’interface, le composant
correspondant génère un événement de type action. Celuici est alors pris en charge par l’écouteur prévu par défaut
par l’implémentation JSF : il s’agit d’un écouteur implémentant l’interface javax.faces.event.ActionListener, dont le
rôle est d’appeler la méthode référencée par le composant à l’origine de l’événement, puis de récupérer la réponse
fournie par cette méthode, c’estàdire une chaîne de caractère correspondant normalement à un cas de navigation
prévu.
L’instance par défaut de ActionListener transmet ensuite cette chaîne de caractère à une instance de la classe
javax.faces.application.NavigationHandler (il en existe une fournie par défaut par l’implémentation JSF). Ce
NavigationHandler sélectionne alors la page suivante à afficher, en recherchant une correspondance entre le cas de
navigation qu’il a reçu de l’ActionListener et l’ensemble des règles de navigation définies dans le fichier de
configuration facesconfig.xml.
Lorsque le NavigationHandler trouve une correspondance valide, la phase de restitution de la vue commence, et la
nouvelle page à afficher est présentée à l’internaute.
Pour rappel, une page JSF diffère d’une page JSP par le fait qu’elle est représentée sous la forme d’un arbre de
composants basés sur la classe javax.faces.component.UIComponentBase. Dans la terminologie JSF, l’arbre en question
est appelé vue. Au cours du cycle de vie d’une page web ; l’implémentation JSF construit la vue, tout en prenant en
compte les états précédents des différents composants (en cas de réaffichage de la page). Lorsque l’internaute soumet
un formulaire, ou s’il engage une action impliquant une évolution de la navigation, deux tâches principales sont
assurées : la validation des données saisies dans les différents composants graphiques, et la conversion des types de
ces mêmes données en types compatibles avec les propriétés des Java Beans associés aux champs de saisie. Ces
actions sont prises en charge de manière séquentielle au cours du cycle de vie : leur traitement est réparti en
différentes phases dont le détail vous est présenté dans la suite de ce chapitre.
1. Les différents types de requêtes et leur mode de prise en charge
Les requêtes assurant la navigation au sein de l’application peuvent être vues de deux façons différentes par
l’implémentation JSF : il s’agit soit de requêtes initiales, soit de requêtes de retour, dites postback. Les premières
correspondent aux situations où les internautes consultent une page pour la première fois au cours d’une même
session. Les secondes se rencontrent principalement lorsque les internautes valident des formulaires contenus dans
des pages web, ellesmêmes résultant de la prise en charge d’une requête initiale.
a. Les objets FacesContext et FacesContextFactory
Un FacesContext est un type d’objet issu de la classe javax.faces.context.FacesContext. Il est conçu pour contenir
toutes les informations relatives à une requête JSF spécifique. Il est associé à la requête dès le début du processus
de traitement par un appel de la méthode getFacesContext() sur l’instance de la classe
javax.faces.context.FacesContextFactory, obligatoirement disponible pour l’application web. Le FacesContext est
ensuite transmis successivement dans chacune des phases du cycle de vie, pour y être potentiellement manipulé. Il
est notamment utilisé, comme cela a été vu précédemment dans le processus de validation des données saisies.
b. Traitement d’une requête initiale
Seules les phases Restore View et Render Response sont mises en œ uvre lors du traitement d’une requête initiale. En
effet, aucune action de l’utilisateur n’est à prendre en compte dans cette situation, au contraire de ce qui est fait
pour le traitement des requêtes postback, pour lesquelles la totalité des phases du cycle de vie est exploité.
Lorsqu’un internaute clique sur bouton ou un lien hypertexte pointant vers une page JSF, l’application web doit
fournir une réponse correspondant à la page JSF demandée. Pour cela, elle crée une nouvelle vue (un nouvel arbre
de composants) et la place dans une instance de la classe FacesContext.
Une fois la vue placée dans le FacesContext, l’application web récupère la référence des différents composants
graphiques constituant la page. Dans le cas d’une requête initiale, l’application poursuit son action en appelant la
méthode renderResponse() de l’objet FacesContext. Le traitement de la requête est alors directement transmis à la
phase Render Response, outrepassant les autres phases intermédiaires.
c. Traitement des requêtes visant des ressources externes à l’application
Il arrive parfois que l’application doive prendre en charge une requête qui ne lui est pas destinée. Cela se produit
notamment lorsque l’utilisateur tente d’atteindre un autre site web, ou lorsqu’une tentative d’accès à un service web
est réalisée. Dans ce cas, la méthode responseComplete() du FacesContext est invoquée et la phase Render
Response n’est pas traitée.
2. Les différentes phases du cycle de vie
La situation la plus courante est celle au cours de laquelle une action réalisée sur un composant graphique JSF
provoque l’appel d’une autre page JSF de l’application. La requête correspondante est alors capturée par l’application.
Elle est ensuite associée au FacesContext, puis transmise successivement aux différentes phases du cycle de vie pour
que les éventuelles validations et conversions soient réalisées.
Dès qu’une requête à destination d’une page JSF est émise, l’implémentation Java Server Faces active le cycle de vie
de la page en question par la phase Restore View.
Au cours de cette phase, l’arbre de composants de la page est constitué. Chaque composant graphique se voit
attribuer ses éventuels gestionnaires d’événements et validateurs, et l’arbre de composant est enfin sauvegardé
dans le FacesContext. Au sein de la page JSF, l’ensemble des composants, gestionnaires d’événements,
convertisseurs et validateurs peuvent avoir accès au FacesContext.
Si la requête ayant enclenché le cycle de vie est une requête initiale, une nouvelle vue est constituée et le cycle de
vie avance directement jusqu’à la phase Render Response.
Sinon, la requête est une requête postback et une vue correspondant à la page demandée existe déjà.
L’implémentation JSF restaure alors cette vue (d’où le nom de la phase) à partir des informations d’état
sauvegardées côté client et/ou côté serveur.
Concernant l’exemple proposé pour ce chapitre, la vue correspondant à la page inscriptions.jsp, dans laquelle se
trouve le formulaire d’inscription, est constituée d’un composant javax.faces.component.UIViewRoot, faisant office de
racine pour l’arbre de composants. Le premier composant enfant de cette racine correspond au formulaire
d’inscription, représenté par un composant de type javax.faces.component.UIForm. Ce dernier composant possède à
son tour plusieurs composants enfants, un pour chacun des éléments présentés dans le formulaire.
b. La phase Apply Request Values
À l’issue de la phase Restore View, l’arbre de composants correspondant à la page demandée est constitué ou
restauré. Chacun des composants de cette vue récupère depuis la chaîne de requête la nouvelle valeur susceptible
de lui être attribué. Cette opération se réalise au travers d’un appel à la méthode decode(), disponible dans la
classe UIComponentBase, et donc accessible à tous les composants graphiques JSF. Les nouvelles valeurs sont alors
stockées localement dans les composants euxmêmes, à moins que le processus de conversion engagé sur ces
valeurs provoque une erreur. Dans ce dernier cas, des messages d’erreurs sont alors constitués, puis placés dans le
FacesContext. Chaque message, qui contient la description de l’erreur et la référence du composant en cause, pourra
par la suite être restitué à l’internaute durant la phase Render Response, en même temps que les autres éventuels
messages d’erreurs issus du processus de validation des données.
Au cours de cette phase, il est possible que l’exécution de la méthode de l’un des composants provoque l’appel de la
méthode renderResponse() du FacesContext. Le cycle de vie évolue alors directement vers la phase Render Response.
Si des événements sont survenus durant la phase Apply Request Values, ceuxci sont transmis aux écouteurs
concernés. Par ailleurs, si certains des composants de l’arbre disposent d’un attribut immediate positionné sur la
valeur true, les processus de conversion, de validation, ainsi que les événements associés sont traités
immédiatement.
Par ailleurs, si l’application JSF est amenée à engager une navigation vers une ressource externe (autre site web,
service web…), ou si elle doit produire une page web ne comportant aucun composant JSF, alors la méthode
responseComplete() du FacesContext peut être invoquée.
À l’issue de cette phase, tous les composants contenus dans la vue possèdent leur nouvelle valeur. Les messages
d’erreurs issus du processus de conversion, ainsi que les événements éventuels, sont placés en attente de
traitement.
c. La phase Process Validations
Au cours de cette phase, tous les validateurs éventuellement affectés aux composants de l’arbre sont pris en
considération. L’implémentation JSF examine les attributs de composants décrivant les règles à respecter pour la
validation. Ces attributs sont alors comparés aux valeurs stockées localement dans le composant. La comparaison
est assurée par appel de la méthode validate() de la classe UIInput.
Lorsque cette comparaison, pour un composant donné, se solde par la mise en évidence du nonrespect de la règle
énoncée, le processus de validation échoue. Un message d’erreur est alors stocké dans le FacesContext et le cycle
de vie évolue directement vers la phase Render Response : la page est alors restituée à l’internaute, accompagnée
du (des) message(s) d’erreur.
Tout comme pour la phase Apply Request Values, si l’application JSF est amenée à engager une navigation vers une
ressource externe (autre site web, service web…) ou si elle doit produire une page web ne comportant aucun
composant JSF, alors la méthode responseComplete() du FacesContext peut être invoquée.
Dans le cas particulier de l’exemple choisi pour illustrer ce chapitre, un validateur standard est associé au champ de
saisie du nom. Celuici est utilisé pour vérifier que la longueur du nom est toujours comprise entre 5 et 100
caractères. Lorsque cette contrainte n’est pas respectée, une erreur de validation survient durant la phase Process
Validation. La page contenant le formulaire est alors restituée à l’internaute, et le message d’erreur est présenté par
l’intermédiaire des composants UIMessage ou UIMessages disposés sur l’interface web.
Une fois que l’ensemble des données saisies dans les composants graphiques a été validé, l’implémentation JSF
parcourt à nouveau tous les composants et tente d’affecter leurs valeurs aux propriétés de JavaBeans auxquels ils
sont liés. Si les valeurs en question ne peuvent pas être converties dans un type compatible avec celui des
propriétés qui leur correspondent, alors le cycle de vie de la page évolue directement vers la phase Render Response.
La page est alors de nouveau présentée à l’internaute. Les messages d’erreurs sont également affichés si des
composants UIMessage ou UIMessages sont présents.
Ce processus de mise à jour des propriétés des JavaBeans est concrètement assuré par appel de la méthode
updateModel() de chacun des composants graphiques issus de la classe UIInput. Il n’est donc appliqué qu’aux
éléments de formulaire permettant de réaliser une saisie.
Là encore, si l’application JSF est amenée à engager une navigation vers une ressource externe (autre site web,
service web…), ou si elle doit produire une page web ne comportant aucun composant JSF, alors la méthode
responseComplete() du FacesContext peut être invoquée.
Si des événements surviennent durant cette phase, ceuxci sont transmis aux écouteurs concernés.
e. La phase Invoke Application
Cette phase assure la prise en charge des événements de niveau application, tels que les clics sur les boutons ou
les liens hypertextes.
Par exemple, dans l’illustration proposée pour ce chapitre, le formulaire est en mesure de provoquer un événement
de niveau application. Celuici survient lorsque l’internaute clique sur le bouton de soumission du formulaire. Le
traitement de cet événement est assuré par l’ActionListener associé à l’application web, qui se charge de récupérer
le cas de navigation mentionné dans l’attribut action de la balise correspondant au bouton de soumission.
L’ActionListener transmet ensuite ce cas d’utilisation au NavigationHandler, afin de déterminer la règle de
navigation associée au cas de navigation spécifié. Le contenu de la règle de navigation ainsi identifiée précise le nom
de la page web à afficher par la suite. L’implémentation JSF prend alors en compte la vue correspondant à cette
page cible, et le cycle de vie se poursuit par la phase Render Response.
f. La phase Render Response
Il s’agit de la phase finale du cycle de vie, au cours de laquelle la responsabilité de la restitution de la page dans le
navigateur est transmise au conteneur JSP. Tous les composants contenus dans la vue sont restitués par ce
conteneur dans l’ordre des balises rencontrées dans la page.
Dans le cas d’une requête postback, des erreurs ont pu être détectées durant les phases Apply Request Values,
Process Validation, et Update Model Values. La page présentée initialement est restituée telle quelle à l’utilisateur ; les
messages d’erreurs sont affichés si des balises <h:message> ou <h:messages> sont présentes dans le code source de
la page web.
<f:view>
<h:form id="formulaireInscription">
<table align="center">
<tr>
<td colspan="3"><h:outputText
value="Saisissez les paramètres suivants pour valider
votre inscription:"
style="color: #0000FF; text-decoration:
underline"></h:outputText><br>
<br>
</td>
</tr>
<tr>
<td colspan="3"><h:messages id="groupeDeMessages"
style="color: #0000FF; text-transform: uppercase; font-style: italic;
font-size: 10px; background-color: #FFFF00; font-weight: bold"
layout="table"></h:messages></td>
</tr>
<tr>
<td><h:outputText id="otxtNom"
value="Nom*">
</h:outputText></td>
<td><h:inputText id="itxtNom"
requiredMessage="N’oubliez pas de fournir une valeur
dans ce champ!">
</tr>
</table>
</h:form>
</f:view>
</body>
</html>
1. La zone d’édition
Il s’agit de la partie principale de l’environnement de développement. Son rôle principal consiste à présenter à
l’utilisateur le contenu des divers fichiers listés dans l’explorateur de projets, ainsi qu’à lui faciliter la mise à jour de
ces fichiers.
En l’occurrence, cette zone est spécifiquement adaptée à la création de pages JSP : elle permet en effet la
présentation de la page en mode code source ou en mode design, et propose une palette d’outils autorisant le
glissédéposé d’objets divers, tels que des éléments de formulaires HTML, des composants JSP (balises taglig, balises
param, etc.), et bien sûr des composants JSF (zones de saisies, convertisseurs, validateurs, etc.). La prévisualisation
des pages JSP créées est également rendue possible par l’utilisation d’un onglet spécifique.
Enfin, la zone d’édition a la particularité de faciliter l’affichage et la mise à jour du fichier de configuration des
ressources des applications JSF, dénommé par défaut facesconfig.xml, par le biais de formulaires de saisie
particuliers.
a. Édition d’une page JSP
La figure suivante donne un aperçu de la zone d’édition, au moment de l’affichage d’une page JSP.
Il est possible que cet affichage ne soit pas activé par défaut au moment de l’affichage des pages JSP. Dans
ce cas, seul le code source de la page est visualisé à l’écran. Pour obtenir l’affichage présenté cidessus, il
est alors nécessaire d’indiquer à Eclipse que l’éditeur à utiliser est le Web Page Editor : cela se fait simplement en
cliquant droit sur le nom du fichier JSP depuis l’explorateur de projet, puis en sélectionnant le sousmenu Open
With Web Page Editor.
Dans cette situation, la zone d’édition est constituée de deux lignes. La première présente la zone d’affichage à
proprement parler, ainsi que la palette d’outils à partir de laquelle il est possible de sélectionner les objets à
positionner sur la page. La seconde ligne expose le code source de la page JSP affichée.
Deux onglets Design et Preview sont également visibles en bas de cette zone d’édition : leur usage permet de
basculer entre les modes développement et prévisualisation de la page.
En mode d’édition de pages JSP, la palette d’objets présente un contenu spécifique, regroupant divers objets
répartis en une vingtaine de catégories distinctes. Parmi ces catégories, il en existe quatre qui intéresseront
particulièrement les concepteurs d’applications web basées sur les technologies JSP/JSF : il s’agit des catégories
HTML, JSF HTML, JSFCore et JSP.
Elle regroupe tous les objets correspondant aux éléments de formulaires HTML (zones de textes, zones de listes
déroulantes, cases à cocher, etc.). L’utilisation de ces objets par glissédéposé permet de concevoir rapidement des
sections de pages web purement statiques, qui n’impliquent la mise en œ uvre d’aucun dynamisme particulier.
Catégorie JSF HTML
Elle contient des objets facilitant l’intégration des composants graphiques JSF dans les pages web. On y retrouve
donc la plupart des composants s’appuyant sur des classes dérivées de UIComponentBase, par exemple des objets
de type UICommande, UIForm ou UIInput. Comme cela sera présenté plus en détail dans la suite de ce chapitre, le
glissédéposé d’un de ces objets sur la page web à créer entraîne la génération automatique de la balise JSF
correspondante, dans le code source de la page. Il s’agit obligatoirement d’une balise issue de la bibliothèque
HTML.
Catégorie JSF Core
Elle regroupe principalement les objets JSF qui peuvent être associés aux composants graphiques listés dans la
catégorie JSF HTML. Il s’agit notamment des convertisseurs (objets implémentant l’interface Converter), des
validateurs (objets implémentant l’interface Validator), et des écouteurs (objets implémentant l’interface
FacesListener). Le fait de glisserdéposer l’un des objets de la catégorie JSF Core dans la page web à créer
entraîne la génération automatique de la balise JSF correspondante, dans le code source de la page. Il s’agit
obligatoirement d’une balise issue de la bibliothèque Core.
Catégorie JSP
Elle regroupe des objets dont l’exploitation permet une intégration plus aisée des balises spécifiques à la
technologie Java Server Pages, comme les balises correspondant à des directives, à des redirections, à l’usage de
JavaBeans ou à l’intégration de scriptlets.
b. Édition du fichier de configuration des ressources des applications web
Outre la conception des pages JSP, la zone d’édition est également conçue pour faciliter la mise à jour du fichier de
configuration des ressources des applications web. En double cliquant sur le nom de ce fichier (en général faces
config.xml) depuis l’explorateur de projets, différents formulaires de saisie sont proposés pour permettre la
définition des règles de navigation, la déclaration des beans managés et de leurs propriétés, ainsi que la
déclaration de divers autres composants, tels que les convertisseurs, les validateurs ou les écouteurs. Bien sûr, il
est également possible de visualiser d’un seul coup d’œ il l’ensemble du code source de ce fichier de configuration
des ressources.
Définition des règles de navigation
Celleci se fait directement après la sélection de l’onglet Navigation Rule et se réalise exclusivement de manière
graphique.
Un clic sur l’onglet Source de la zone d’édition permet de visualiser le code source du fichier de configuration. Les
cas de navigation présentés cidessus correspondent au code suivant :
<faces-config
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-facesconfig_1_2.xsd"
version="1.2">
<navigation-rule>
<display-name>
premierePage</display-name>
<from-view-id>
/premierePage.jsp</from-view-id>
<navigation-case>
<from-outcome>
UnVersDeux</from-outcome>
<to-view-id>
/secondePage.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<display-name>
premierePage</display-name>
<from-view-id>
/premierePage.jsp</from-view-id>
<navigation-case>
<from-outcome>
UnVersTrois</from-outcome>
<to-view-id>
/troisiemePage.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<display-name>
troisiemePage</display-name>
<from-view-id>
/troisiemePage.jsp</from-view-id>
<navigation-case>
<from-outcome>
TroisVersDeux</from-outcome>
<to-view-id>
/secondePage.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
Chaque bean managé intervenant dans le cadre d’une application web doit être déclaré dans le fichier de
configuration des ressources. La sélection de l’onglet ManagedBean de la zone d’édition permet de faciliter cette
démarche, par la présentation de formulaires de saisie spécifiques.
L’arborescence située sur la gauche de la zone d’édition propose une répartition des beans managés suivant leur
portée au sein de l’application (session, request, application ou none).
La déclaration d’un nouveau bean managé se fait également très simplement par le biais de cette interface, en
précisant le nom du bean, sa classe et sa portée. Il est en général préférable d’avoir préalablement créé la classe
correspondant au nouveau bean managé, mais cela n’est cependant pas indispensable : la création de cette classe
peut en effet être faite à la volée, au moment même de la déclaration du bean managé.
Naturellement, toute modification apportée dans la déclaration des beans managés est immédiatement répercutée
dans le code source de l’application, visible par la sélection de l’onglet Source de la zone d’édition.
Déclaration de composants personnalisés
La démarche à suivre est ici identique à celle présentée pour la déclaration des beans managés. La sélection de
l’onglet Component de la zone d’édition permet d’afficher différents formulaires chargés de faciliter la déclaration
des objets personnalisés suivants : composants graphiques, convertisseurs, validateurs et kits de rendus.
Après avoir sélectionné le type de composant à créer/modifier depuis l’arborescence située à gauche de la zone
d’édition, il est possible de choisir l’un des composants déjà déclarés pour en modifier les caractéristiques, ou d’en
déclarer un nouveau. Il est important de préciser ici que les classes correspondant aux nouveaux composants
doivent impérativement exister préalablement pour que la déclaration puisse être réalisée.
Parmi les caractéristiques qui peuvent ou doivent être mentionnées, on trouve le nom du composant personnalisé,
sa description, son identifiant, la classe qui le caractérise, et enfin les attributs et propriétés qui lui sont propres.
Déclaration des autres types de composants
Cette action peut être entreprise par la sélection de l’onglet Others de la zone d’édition. Elle permet d’assurer la
déclaration des ressources qui n’ont pas encore été évoquées, à savoir, notamment : les écouteurs et les fichiers
de messages personnalisés.
Le mode de déclaration de ces ressources se fait sur le même principe que ce qui a été vu précédemment : sélection
du type de ressource à déclarer, puis précision/modification des propriétés qui le caractérisent (par exemple : nom
de classe pour les écouteurs ; nom de fichier pour les messages personnalisés).
Aperçu général des ressources déclarées
La répartition de l’affichage du contenu du fichier de configuration des ressources dans différents onglets peut
potentiellement rendre sa lecture difficile. Il peut en effet être intéressant de visualiser de manière globale
l’ensemble des ressources, en vue d’une impression par exemple. La zone d’édition propose de répondre à ce
besoin par la sélection de l’onglet Overview, qui offre une vue récapitulative des ressources de l’application.
Il s’agit d’une vue habituellement rencontrée dans les différents types de projets supportés par l’environnement de
développement Eclipse. Elle permet de naviguer au sein des différents projets et d’accéder ainsi facilement aux
multiples pages JSP et classes Java utilisées par les applications web en cours de création.
À noter la présence d’un nœ ud d’arborescence correspondant aux serveurs déclarés et utilisables par
l’environnement Eclipse. Son utilisation, qui permet d’accéder rapidement aux différents fichiers de configuration de
ces serveurs, se fait conjointement à l’affichage de la fenêtre de propriétés, ainsi qu’avec celui de la vue Servers elle
même.
3. La vue Outline
4. La vue Servers
L’utilisation de cette vue permet de déclarer différents serveurs et moteurs de servlets, dans le but de les rendre
directement exploitables par Eclipse sans qu’il soit nécessaire de passer par des utilitaires annexes.
a. Adaptateurs de serveurs
Outre le classique serveur HTTP de Apache, Eclipse propose la gestion de serveurs spécifiques à J2EE disponibles
gratuitement, tels que Tomcat, GlassFish et Sun Application Server. L’exploitation de produits payants est
également proposée, notamment celle de IBM WebSphere et Oracle OC4J Server. Il est important de noter que la
liste de serveurs gérables par Eclipse n’est pas fermée : elle peut très facilement être complétée par l’installation
d’adaptateurs spécifiques recherchés sur le web. L’illustration suivante montre l’utilitaire d’Eclipse chargé de trouver
les adaptateurs disponibles. Cet utilitaire s’active depuis la vue Servers.
Naturellement, l’installation d’un adaptateur spécifique ne dispense pas de l’installation du serveur luimême dans le
système d’exploitation. Cette étape obligatoire doit être entreprise indépendamment de l’IDE Eclipse.
b. Configuration des serveurs
La vue Servers est également conçue pour faciliter la configuration des différents serveurs : une fois l’un des
serveurs sélectionné, la zone d’édition est mise à jour pour en faire apparaître les multiples paramètres de
configuration. Il est notamment possible de mentionner/modifier les ports TCP/IP utilisés par le service de
publication et de référencer les différentes applications web prises en charge par le serveur sélectionné.
À titre d’illustration, l’image cidessous présente l’apparence de la zone d’édition pour la configuration d’un serveur
5. La vue Properties
Cette vue est classiquement chargée de présenter la ou les propriétés de l’un des éléments sélectionné dans
l’environnement de développement. Par exemple, elle affiche les diverses informations concernant les fichiers ou
dossiers exposés dans la vue d’exploration de projets (chemin d’accès complet, date de la dernière modification,
taille, etc.).
Dans le cadre de la création d’applications web exploitant des composants JSF, cette vue est d’une importance
certaine, dans la mesure où elle facilite grandement l’affichage et la mise à jour des propriétés des divers composants
positionnés sur les pages.
a. Affichage des propriétés de composants de type HTML ou JSF
Pour ce type de composants, la vue Properties présente une unique grille de saisie, dénommée Attributes, à partir
de laquelle le concepteur de l’application web a la possibilité de préciser rapidement les valeurs qui doivent être
attribuées aux différentes propriétés du composant sélectionné.
Par exemple, pour un simple bouton représenté par une balise HTML <input type=’button’>, la vue Properties
expose l’intégralité des attributs de balise définis par la norme : le développeur peut donc facilement préciser les
valeurs de l’attribut name, mentionner le code JavaScript à exécuter lors d’un clic sur le bouton, ou encore définir une
image à associer au même bouton. L’image cidessous montre le contenu de la vue Properties pour ce cas de figure
spécifique.
Bien sûr, l’utilisation de cette grille de saisie dispense le concepteur de modifier directement le code source de la
page web pour préciser la valeur des attributs.
b. Affichage des propriétés de composants issus des catégories JSF Core et JSF HTML
Concernant le traitement des composants JSF issus des catégories JSF Core et JSF HTML de la palette d’édition, la
6. La vue DataSource Explorer
La dernière vue qui peut potentiellement intéresser le concepteur d’applications web basées sur JSF est la vue Data
Source Explorer. Comme certaines des autres vues qui ont été évoquées précédemment, celleci n’est pas spécifique
à ce type de projets : elle peut tout à fait être exploitée dans des contextes complètement différents. Néanmoins,
compte tenu de l’importance de l’utilisation des bases de données dans les projets web actuels, il paraît nécessaire
d’évoquer l’existence de cette vue dans le cadre de cet ouvrage.
a. Accès aux bases de données
Le rôle de la vue Data Source Explorer est de fournir au développeur un moyen d’accéder rapidement aux
différentes bases de données utilisables par l’application web. Cet outil dispense de passer par des outils annexes,
tels que les logiciels clients édités par les fournisseurs de systèmes de gestion de bases de données, et permet
l’exploitation d’Eclipse dans toute sa dimension d’environnement de développement intégré.
Les principales actions qui peuvent être entreprises à partir de cette vue sont des opérations de gestion, tels que
l’ajout ou la suppression de tables, l’import ou l’export de données. Bien sûr, les données ellesmêmes peuvent être
visualisées en sélectionnant la base, puis la table dont on veut connaître le contenu : les données sont alors
présentées dans la zone d’édition. Il est également possible de mettre à jour les informations, et même d’ajouter
de nouveaux enregistrements.
b. Accès à d’autres types de sources de données
Outre l’exploitation des bases de données, la vue Data Source Explorer permet également de faire appel à
d’autres sources de données. En l’occurrence, les fichiers plats (au format CSV, par exemple) peuvent être pris en
charge, de même que les fichiers XML et les sources de données accessibles par Web Services.
Au moment de l’intégration d’un composant dans une page, le code source de celleci est mis à jour pour faire
apparaître une balise spécifique au type de composant choisi : c’est ce que l’on appelle une balise de restitution. Il
s’agit, selon le cas, d’une balise appartenant à la bibliothèque HTML ou d’une balise référencée dans la bibliothèque
Core. À titre d’illustration, l’intégration d’un composant de type UICommand peut provoquer l’ajout de la balise suivante
dans le code source de la page web :
Dans ce cas particulier, le composant UICommand a été restitué par une balise <h:commandButton> de la bibliothèque
HTML, dont l’apparence graphique correspond à celle d’un classique bouton de soumission HTML. Cette balise présente
plusieurs attributs qui, en général, servent à préciser l’apparence graphique du composant (couleurs, styles...) ou à
indiquer les actions qui peuvent être engagées lors de l’utilisation de ce composant (par exemple, appel d’une fonction
JavaScript au moment du survol par la souris ; utilisation d’un cas de navigation particulier au moment du clic).
D’une manière plus générale, il est important de noter que la plupart des balises correspondant aux composants
graphiques JSF partagent un jeu d’attributs communs. C’est le cas notamment de l’attribut id, qui est disponible pour
la totalité des composants JSF. Sa présence est d’ailleurs mentionnée dans l’exemple cidessus, concernant le bouton
de soumission. Mais ces balises proposent également un jeu d’attributs spécifiques, qui diffère suivant le type de
composant graphique représenté. Par exemple, la balise correspondant à un bouton de soumission expose un attribut
action qui lui est propre : cet attribut ne peut pas être utilisé pour d’autres composants (champ de saisie, par
exemple).
Ce paragraphe a pour objectif de présenter les différentes balises de restitution de composants JSF, en précisant
notamment le rôle de leurs principaux attributs communs, et de montrer comment se réalise l’intégration de ces balises
dans les pages web.
Seuls sont traités ici les composants JSF restitués dans la page par des balises issues de la bibliothèque HTML.
Il s’agit donc uniquement des objets se trouvant dans la catégorie JSF HTML de la palette. Des informations
concernant les autres types de composants (convertisseurs, écouteurs et validateurs) sont fournies dans les
paragraphes suivants de ce chapitre.
1. Classes et balises de restitution
Ce point fait écho à certaines informations déjà données dans le chapitre Composants graphiques personnalisés de
cet ouvrage. Il rappelle la liste des classes correspondant à des composants graphiques JSF, indique pour chacun
d’eux la balise de restitution à utiliser en vue d’une présentation dans une page web, et rappelle l’apparence visuelle
du composant.
Le tableau cidessous présente l’ensemble de ces informations, et mentionne, pour chaque composant, le nom de
l’objet correspondant tel qu’il est présenté dans la palette Eclipse. Les composants sont classés ici en catégories,
compte tenu de leur rôle respectif.
Catégorie : Composants de type "Texte"
Catégorie : composants de type "Commande"
Catégorie : composants de type "Tableau de données"
Catégorie : composants de
type "Présentation"
Catégorie : composants de type "Messages"
Catégorie : composant de type "Images"
Catégorie : composant de type
"Formulaire"
2. Principaux attributs de balises communs
La connaissance du rôle de chaque attribut est indispensable pour que le concepteur d’une l’application web puisse
utiliser efficacement les composants JSF dont il dispose.
Il est possible de distinguer deux groupes d’attributs communs : le premier concerne l’ensemble des attributs
utilisables par la totalité des balises de restitution. Le second se limite aux attributs exclusivement applicables aux
balises correspondant à des composants destinés à la saisie d’information (zones de texte, cases à cocher, etc.).
a. Attributs communs à l’ensemble des balises de restitution
Les attributs communs les plus couramment utilisés sont binding, id, immediate, rendered, style et styleClass.
L’attribut binding
Il permet de lier l’instance du composant représenté par la balise à une propriété de bean managé. Cela permet
notamment de modifier par programmation les attributs du composant en question.
Le code source cidessous correspond à celui d’un JavaBean extrêmement simple : il ne possède qu’une seule
propriété de type UIInput, dénommée champEntree, qui lui permet de stocker la référence d’un objet de ce type.
package premierProjetJSF;
import javax.faces.component.UIInput;
public class Liaison {
UIInput champEntree;
Un tel JavaBean peut être exploité en tant que bean managé dans une application web JSF, à condition de le
déclarer dans le fichier de configuration des ressources de l’application. Les lignes suivantes correspondent à une
<managed-bean>
<managed-bean-name>liaison</managed-bean-name>
<managed-bean-class>premierProjetJSF.Liaison</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
Toutes les conditions sont donc réunies pour réaliser une liaison entre une instance d’un composant graphique de
l’application et la propriété champEntree du bean liaison. Naturellement, le type du composant à lier ne peut pas
être choisi librement : la propriété champEntree étant de type UIInput, seuls les composants de ce type (restitués
par une balise <h:inputText>) sont éligibles. Voici un exemple de contenu de page JSP dans lequel un composant
UIInput est lié à la propriété champEntree du bean liaison.
<f:view><h:form>
<h:inputText binding="#{liaison.champEntree}"></h:inputText>
</h:form></f:view>
Par ce mécanisme, le JavaBean dispose de la référence au champ de saisie : il peut donc en modifier les attributs si
nécessaire.
L’attribut id
Cet attribut permet de référencer le composant qui l’utilise au sein de l’application web. Il ne s’agit pas d’un
caractère obligatoire, mais son absence empêche la manipulation du composant concerné par les autres
composants de la page, ou par d’autres classes.
L’exemple suivant correspond à la présence d’un composant de type UIMessage sur une page JSP. Ce composant est
restitué sous la forme d’une balise <h:message>, dont l’attribut id prend ici la valeur messageMotPasse :
L’attribut rendered
Cet attribut de balise permet de préciser si le composant doit être présenté à l’internaute ou s’il doit être caché. La
valeur de l’attribut rendered est bien entendu un booléen, dont la valeur peut être mentionnée directement ou par
l’intermédiaire d’une expression booléenne. Il est également possible de préciser cette valeur grâce à l’emploi du
langage d’expression spécifique à JSF, dont l’évaluation renvoie un booléen.
<h:outputText rendered="#{beanInscription.nom!=’test’}"
value="texte affiché">
</h:outputText>
Dans l’exemple cidessus, l’affichage d’un champ de sortie de type UIOutput est contrôlé grâce à l’attribut rendered,
dont la valeur correspond à l’évaluation d’une expression JSF. Le test assuré par cette expression consiste à vérifier
si la propriété nom d’un bean managé dénommé beanInscription possède une valeur différente de la chaîne test.
Les attributs style et styleClass
Ces deux attributs de balise permettent de spécifier le style à appliquer au composant graphique. L’attribut style
accepte une valeur correspondant à la définition complète du style à utiliser (précision d’une couleur, d’un fond,
d’une police, etc.).
<h:outputText
binding="#{liaison.champLabel}"
id="txtLabel1"
value="Saisissez la quantité souhaitée (entre 1 et 10):"
rendered="true"
style=’color: #0000FF; font-style: italic; font-size: 12px;
font-family: "Comic Sans MS", Sans-Serif; font-weight: bold’
>
</h:outputText>
Dans cet exemple, le champ de type UIOutput dénommé txtLabel1 permet d’afficher un texte italique de couleur
bleue, de taille égale à douze pixels. La police utilisée pour ce texte est Comic Sans MS.
Dans la spécification Java Server Faces, les composants graphiques destinés à la saisie sont instanciés à partir de la
classe UIInput, ou de ses classes dérivées. Il existe actuellement onze classes dérivées de UIInput, auxquelles
sont associées des balises de restitution HTML. Outre les attributs communs à tous les types de balises de
restitution, les balises restituant des composants de saisie dans les pages web partagent spécifiquement un
ensemble d’attributs communs dont voici une description :
Attribut converter
Cet attribut permet de spécifier le convertisseur associé au champ de saisie. Pour rappel, un convertisseur est un
objet chargé de s’assurer que la donnée saisie dans le composant graphique est compatible avec la valeur
attendue pour la propriété du bean à laquelle est lié le composant.
Supposons par exemple que le fichier de configuration des ressources d’une application web dispose de la
référence à un convertisseur personnalisé, par l’intermédiaire des lignes de code suivantes :
<converter>
<display-name>
convertisseurPerso</display-name>
<converter-id>
convertisseurPersoID</converter-id>
<converter-class>
premierProjetJSF.MonConvertisseur</converter-class>
</converter>
Le convertisseur en question se nomme convertisseurPerso. Il est issu d’une classe
premierProjetJSF.MonConvertisseur implémentant l’interface Converter et peut être utilisé par l’ensemble des
pages web de l’application JSF grâce à son identifiant convertisseurPersoID.
Ainsi, ce convertisseur peut, par exemple, être associé à un champ de saisie de type HtmlInputText. Pour cela,
l’identifiant du convertisseur est utilisé comme valeur de l’attribut converter de la balise <h:inputText>
représentant le composant.
Attribut converterMessage
Il indique le contenu du message à présenter à l’internaute lorsque la conversion de la donnée saisie échoue.
Dans l’exemple suivant, un champ de type HtmlInputText dispose d’un convertisseur standard issu de la classe
DateTimeConverter. Ce convertisseur est utilisé pour vérifier que la date mentionnée dans le champ de saisie
respecte bien un format particulier (par exemple : dd/MM/yyyy). Ce format est indiqué par l’attribut pattern de la
balise <f:convertDateTime> représentant le convertisseur. En cas de nonrespect du format de date attendu, le
message mentionné par l’attribut converterMessage de la balise correspondant au champ de saisie est généré :
celuici peut éventuellement être présenté à l’internaute, si la page prévoit une association entre le champ de saisie
et un objet de type UIMessage. Ce qui est le cas ici.
<h:inputText id="itxtDateNaissance"
converterMessage="La date indiquée doit être au format
JJ/MM/AAAA"
<f:convertDateTime pattern="dd/MM/yyyy" />
</h:inputText>
<h:message id="msgDateNaissance" for="itxtDateNaissance"
style="color: #FF0000; background-color: #FFFF00">
</h:message>
Attribut dir
Cet attribut sert à préciser le sens dans lequel doit être affiché le composant de saisie. Il peut s’agir d’un défilement
de la droite vers la gauche (la valeur de l’attribut dir est alors égale à rtl, pour righttoleft), ou d’un défilement de
la gauche vers la droite (la valeur de l’attribut sera alors égale à ltr, pour lefttoright).
Dans l’exemple suivant, la saisie réalisée dans le champ txtCommentaire se fait de droite à gauche.
Cet attribut permet d’attribuer une étiquette au champ de saisie. Cette étiquette n’est pas visible en tant que telle
dans le formulaire, mais elle est utilisée lorsque des messages d’erreur concernant le champ de saisie sont générés.
Cela permet, en particulier lorsqu’une page web présente un formulaire comportant de nombreux champs de saisie,
d’identifier rapidement et précisément les champs à l’origine d’une erreur.
Dans le code source suivant, une zone de texte txtQuantite permet à l’utilisateur de saisir une valeur numérique.
Cette zone est associée à un validateur, chargé de vérifier systématiquement que la valeur mentionnée est bien
comprise entre 1 et 10. En cas d’erreur, un message adapté est présenté à l’utilisateur par l’intermédiaire de l’objet
UIMessage associé à la zone de saisie. Ce message fait spécifiquement mention de l’étiquette correspondant au
champ à l’origine du problème, car la balise <h:inputText> qui le représente comporte un attribut label renseigné.
<f:view><h:form>
<h:outputText binding="#{liaison.champLabel}" id="txtLabel1"
value="Saisissez la quantité souhaitée (entre 1 et 10):"
rendered="true" ></h:outputText>
<br>
<h:inputText label="Quantité souhaitée" id="txtQuantite"
immediate="false">
<f:validateDoubleRange minimum="1" maximum="10">
</f:validateDoubleRange>
</h:inputText>
<h:message for="txtQuantite" style="color: #FF0000">
</h:message>
<br>
<h:commandButton id="btnValidation" value="Enregistrer la
quantité" immediate="true">
</h:commandButton>
</h:form></f:view>
Attribut required
Cet attribut permet de spécifier que la saisie est obligatoire dans un champ de saisie particulier. La valeur de cet
attribut est bien entendu un booléen.
L’exemple suivant correspond à l’utilisation d’un champ de saisie txtCommentaire, dans lequel l’utilisateur est forcé
de fournir une information : l’attribut required de la balise <h:inputText> est en effet positionné sur la valeur true.
En cas de nonrespect de cette contrainte, un message adapté est renvoyé à l’internaute par le biais de l’objet
UIMessage associé au champ de saisie.
<f:view>
<h:form>
<h:outputText id="txtIntitule" value="Saisissez
impérativement un commentaire:"></h:outputText>
<br>
<h:inputText id="txtCommentaire"
label="Commentaire impératif"
required="true">
</h:inputText>
<h:message id="messageCommentaire"
for="txtCommentaire"
Attribut requiredMessage
Lorsque la saisie dans un champ est rendue obligatoire par la présence de l’attribut de balise required, un message
par défaut est renvoyé à l’utilisateur en cas de non respect de la contrainte. Il est probable que ce message par
défaut ne convienne pas dans certaines situations, pour une raison quelconque (par exemple : l’information délivrée
est trop précise (ou au contraire, pas assez) ; la langue utilisée pour le message n’est pas la même que celle
utilisée dans le reste de la page web).
Il est alors possible d’empêcher l’affichage du message proposé par défaut, grâce à l’utilisation de l’attribut de
balise requiredMessage. La valeur fournie pour cet attribut sert alors de message d’erreur affiché lorsque
l’internaute oublie de fournir une information dans un champ requis.
L’exemple proposé précédemment pour l’attribut required peut être adapté en rajoutant un attribut
requiredMessage à la balise <h:inputText> correspondant au champ de saisie :
<h:inputText
id="txtCommentaire"
label="Commentaire impératif"
required="true"
requiredMessage="Vous devez obligatoirement saisir une
information dans ce champ!">
Attribut validator
Cet attribut sert à identifier une méthode spécifique d’un JavaBean, chargée de faire toutes les vérifications
requises par rapport à la valeur saisie dans un champ particulier.
La méthode en question doit impérativement être de type void et accepter les trois arguments suivants :
● Un argument de type FacesContext permettant au JavaBean de détenir une référence au contexte de
l’application web.
● Un argument de type UIComponent, correspondant au composant JSF à l’origine de la demande de validation.
● Un argument de type Object, représentant la valeur du composant JSF à l’origine de la demande de
validation.
À titre d’exemple, considérons une page web dans laquelle se trouve un champ de saisie de type HtmlInputText. On
peut imaginer la mise en place d’une validation triviale, destinée à s’assurer que le texte saisi dans le champ
contienne exactement deux occurrences de la lettre A. Pour répondre à cette attente, il est possible d’entreprendre
successivement les étapes suivantes :
● Création d’un JavaBean contenant une méthode spécifiquement chargée de la validation.
● Déclaration du JavaBean dans le fichier de configuration des ressources.
● Association entre le composant graphique dont on veut tester la valeur, et la méthode de validation.
Conformément aux contraintes évoquées plus haut concernant la signature que doit respecter la méthode de
validation, voici le code source d’un JavaBean capable de déterminer le nombre d’occurrences de la lettre A dans la
chaîne représentant la valeur d’un composant graphique (quel que soit son type).
package premierProjetJSF;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
return nbOccurences;
}
String valeur=arg2.toString().toUpperCase();
int nombreDeA_requis=2;
int nombreDeA=nombreOccurences(’A’, valeur);
Le code de ce JavaBean montre que la méthode pouvant faire office de méthode de validation se nomme
checkName : elle présente effectivement les trois arguments requis pour assurer une validation. Le contenu de cette
méthode indique que si le nombre d’occurrences de la lettre A est incorrect, alors une exception de type
ValidatorException est générée. La création de cette exception se fait obligatoirement en fournissant un message
décrivant la cause de l’erreur : ce message est un objet de type FacesMessage.
Pour que ce JavaBean puisse être exploité dans les pages de l’application web, son existence doit être déclarée au
sein du fichier de configuration des ressources de l’application. Les lignes suivantes peuvent correspondre à une
telle déclaration :
<managed-bean>
<managed-bean-name>
beanAttributValidator
</managed-bean-name>
<managed-bean-class>
premierProjetJSF.BeanAttributValidator
</managed-bean-class>
<managed-bean-scope>
session
</managed-bean-scope>
</managed-bean>
Par ces modifications dans le fichier facesconfig.xml, toutes les pages web l’application peuvent exploiter le bean
de session nommé beanAttributValidator, instance de la classe BeanAttributValidator, et exploiter sa méthode
checkName pour réaliser une validation.
Voici pour finir le contenu d’une page JSP contenant un champ de saisie de type HtmlInputText. Ce champ,
représenté par la balise <h:inputText>, est associé à la méthode checkName de beanAttributValidator, grâce à
l’utilisation de l’attribut validator.
</h:inputText>
<h:message id="messageCommentaire"
for="txtCommentaire"
style="color: #FF0000; font-weight: bold">
</h:message>
<br>
<h:commandButton id="btnValidation"
value="Validation du formulaire">
</h:commandButton>
</h:form>
</f:view>
</html>
L’exécution de cette page JSP montre bien la prise en charge correcte de la validation attendue :
De plus, conformément au contenu de la méthode checkName de la classe BeanAttributValidator, l’identifiant et la
valeur du composant pour lequel la validation est demandée sont présentés dans la vue Console d’Eclipse :
Attribut validatorMessage
Cet attribut joue un rôle similaire à celui de l’attribut requiredMessage, mais il concerne le processus de validation. Il
permet au concepteur de pages web de préciser le message qui doit être renvoyé à l’internaute lors de l’échec
d’une validation. Ce message vient en remplacement de celui qui est généré par le composant ou la méthode
chargé d’assurer la validation.
Dans l’exemple qui vient d’être évoqué à propos de l’attribut validator, le message renvoyé par la méthode
checkName peut être ignoré par l’affectation d’un attribut validatorMessage à la balise représentant le champ de
saisie dans la page JSP :
<h:inputText
Attribut valueChangeListener
Cet attribut permet de mentionner le nom d’une méthode de JavaBean qui doit être exécutée dès qu’un
changement intervient au niveau de la valeur d’un composant.
De façon similaire à ce qui a été vu concernant l’attribut validator, une méthode capable de prendre en charge ce
type d’événement doit respecter une signature particulière. En l’occurrence, la méthode en question doit :
● Être de type void.
● Présenter un argument de type ValueChangeEvent.
Le concepteur de l’application web doit développer le JavaBean contenant la méthode évoquée, déclarer ce
JavaBean dans le fichier de configuration des ressources de l’application et faire appel à la méthode depuis un
composant graphique positionné dans une page JSP. Cet appel de méthode se fait par le biais de l’attribut
valueChangeListener de la balise qui représente le composant.
À titre d’illustration, voici le code source d’un JavaBean comportant une méthode modificationContenu pouvant faire
office d’écouteur pour les événements de type ValueChangeEvent. Lorsqu’un tel événement survient, la méthode en
question récupère la référence du composant qui en est la source, puis incrémente un compteur permettant de
connaître le nombre de fois que l’événement est survenu. La valeur de ce compteur est enfin affichée dans la
console.
package premierProjetJSF;
import javax.faces.component.UIComponent;
import javax.faces.event.ValueChangeEvent;
public BeanAttributValueChangeListener()
{
compteur=0;
}
public void modificationContenu(ValueChangeEvent evenement)
{
UIComponent composant=evenement.getComponent();
compteur++;
System.out.println("Déjà "+compteur+" modification(s)
de la valeur du composant "+composant.getId());
}
}
Ce JavaBean doit ensuite être déclaré dans le fichier de configuration des ressources pour pouvoir être exploité par
le reste de l’application web. Les lignes suivantes montrent la déclaration d’un bean de session dénommé
beanAttributValueChangeListener basé sur la classe BeanAttributValueChangeListener.
<managed-bean>
<managed-bean-name>
beanAttributValueChangeListener</managed-bean-name>
<managed-bean-class>
premierProjetJSF.BeanAttributValueChangeListener
</managed-bean-class>
<managed-bean-scope>
session</managed-bean-scope>
</managed-bean>
La capture des événements de type ValueChangeEvent par la méthode modificationContenu peut désormais être
assurée. Un composant graphique situé sur une page JSF peut donc faire l’objet de cette capture : la balise qui le
<h:inputText id="txtCommentaire"
valueChangeListener = "#{beanAttributValueChangeListener.
modificationContenu}"
label="Commentaire"
required="true"
requiredMessage="Vous devez obligatoirement saisir une information
dans ce champ!" >
3. Intégration des composants graphiques dans les pages JSP
Après avoir abordé les différents attributs partagés par l’ensemble des balises de restitution, et ceux partagés
uniquement entre les balises de restitution des composants de saisie, voyons maintenant comment intégrer
concrètement les principaux composants graphiques dans les pages JSP.
Pour cela, nous pouvons nous appuyer sur la mise en place d’un formulaire web comprenant les composants
graphiques les plus couramment utilisés, et détailler pas à pas les étapes de réalisation. La figure suivante illustre le
résultat à obtenir :
a. Intégration du composant correspondant au formulaire de saisie
Après avoir créé la page JSP dans laquelle les différents composants seront positionnés, il faut immédiatement
placer la balise de restitution correspondant au formulaire de saisie. Les balises des autres composants graphiques
seront par la suite obligatoirement encadrées par la balise du formulaire.
Par un simple glissédéposé depuis la palette, l’objet Form est positionné dans la zone d’édition. On constate que
l’environnement a automatiquement inséré le formulaire au sein d’un couple de balises <f:view> </f:view>. Au
besoin, depuis la vue Properties, il est possible de préciser certains attributs du formulaire.
b. Intégration d’une grille de présentation
Pour que la présentation du formulaire de saisie soit assez esthétique, il est nécessaire de répartir les différents
composants graphiques dans un conteneur tabulaire. En l’occurrence, compte tenu de l’apparence qui doit être
donnée à ce formulaire, ce conteneur pourra être constitué par l’utilisation de l’objet Panel Grid de la palette. Au
moment où celuici est déposé sur la zone d’édition, il se présente sous la forme d’un tableau de deux lignes et
deux colonnes. Si d’autres colonnes doivent être rajoutées, il faut modifier la valeur de la propriété columns de la
balise <h:panelGrid>.
Par défaut, chaque cellule du tableau contient un objet de type HtmlOutputText : ceuxci peuvent être bien entendu
supprimés.
Pour constituer le reste du formulaire de saisie, chacun des composants graphiques devra être déposé dans la
cellule adaptée de la grille de présentation.
Les cellules de l’objet HtmlPanelGrid ne peuvent contenir qu’un seul composant graphique : il n’est donc
pas possible, de prime abord, de disposer dans la même cellule une zone de texte et l’étiquette qui lui est
associée (par exemple). Pour réaliser une telle opération, il est indispensable de faire usage d’un conteneur de
type HtmlPanelGroup dans lequel les composants en question seront placés.
c. Intégration d’un texte simple et d’une zone de texte à ligne unique
On sélectionne successivement les objets Output Text et Text Input depuis la palette, pour les positionner
correctement dans la zone d’édition. L’utilisation de la vue Properties permet de préciser certains attributs, tels que
id, value et style.
d. Intégration d’une zone de mot de passe et d’un message
Il faut ici positionner les deux composants et associer le message à la zone de mot de passe. Cela permettra par la
suite d’entreprendre un test de validation concernant le mot de passe, et d’afficher un message d’erreur adapté en
cas d’échec de la validation (pour cause de mot de passe trop court, par exemple).
La réalisation d’un tel test de validation requiert également l’association de la zone de mot de passe avec
un validateur standard, ou avec un validateur personnalisé. Ce point n’est pas traité ici, dans la mesure où
l’on se limite à l’ajout des composants à la page web. Pour obtenir des détails sur l’association entre un
composant et un validateur, voyez le titre Exploitation des validateurs standards de ce chapitre.
L’insertion des composants se fait par l’utilisation des objets Secret Input et Message de la palette. Cependant,
Il est impératif de donner une valeur à l’attribut id de la balise correspondant au champ de mot de passe, de façon
à permettre son association avec le message. La balise de restitution du message doit, quant à elle, comporter un
attribut for dont la valeur est identique à celle de l’attribut id de la zone de mot de passe.
Pour imposer à l’internaute de saisir un mot de passe, il faut donner la valeur true à l’attribut required de la balise
<h:inputSecret>. Si l’on souhaite qu’un message d’erreur adapté soit présenté lorsque cette situation survient, il
est possible de renseigner l’attribut requiredMessage de la même balise.
Un message d’erreur à afficher en cas d’échec de validation peut également être spécifié grâce à l’attribut
validatorMessage du champ de mot de passe. Attention, dans ce cas, le message d’erreur éventuellement généré
dynamiquement par un autre biais ne pourra jamais être affiché. Voir le titre Ajout de composants graphiques à une
page Principaux attributs de balises communs cidessus, concernant l’attribut validatorMessage, pour plus
d’explications.
e. Intégration de boutons radios
L’insertion de boutons radios dans une page web se fait par le biais de l’objet Select On Radio de la palette
Eclipse.
Un groupe de boutons radios permet à l’utilisateur de manifester un choix unique parmi un ensemble de
propositions. Pour constituer un tel groupe, il suffit de réaliser un unique glissédéposé de l’objet Select One Radio
sur la page web. La définition des différentes propositions se fait très simplement depuis la vue Properties, qui
présente une rubrique Choices permettant de rajouter les items. Ces items sont restitués sous la forme de balises
<f:selectItem>.
Une fois que chacun des items a été déclaré, il faut impérativement en afficher les propriétés de manière à préciser
le label (attribut itemLabel) et la valeur (attribut itemValue) qui leur correspondent. Il est également fortement
recommandé de fixer une valeur pour leur propre attribut id.
La disposition des différentes propositions, en ligne ou en colonne, peut être précisée au moyen de l’attribut layout
de la balise de restitution de l’objet de type HtmlSelectOneRadio. Les différentes valeurs autorisées sont
f. Intégration d’une zone de liste déroulante à choix unique
La démarche à suivre ici est identique à celle qui vient d’être vue pour l’insertion de boutons radios. On dépose
l’objet Select One Menu sur la zone d’édition, après l’avoir sélectionné dans la palette. La vue Properties spécifique
à cet objet présente une rubrique Choices qu’il convient remplir avec les différents choix proposables à l’utilisateur.
À chaque choix correspond une balise <f:selectItem>, pour laquelle il faut préciser les attributs id, itemLabel et
itemValue.
<h:selectOneMenu id="selectEnfants">
<f:selectItem id="itemEnfant0" itemLabel="0" itemValue="0"/>
<f:selectItem id="itemEnfant1" itemLabel="1" itemValue="1"/>
<f:selectItem id="itemEnfant2" itemLabel="2" itemValue="2" />
<f:selectItem id="itemEnfant3" itemLabel="3" itemValue="3"/>
</h:selectOneMenu>
Malgré les facilités qu’offre la vue Properties pour saisir les différents items, son utilisation ne peut être
envisagée que si le nombre d’éléments à insérer dans la zone de liste déroulante est réduit. Lorsque ce
n’est pas le cas (par exemple pour constituer une liste contenant tous les nombres compris entre 1 et 100000), il
convient de générer les items dynamiquement : cela peut être fait par l’exploitation d’un bean managé de type
ArrayList. Ce cas de figure est décrit dans le paragraphe Liaison de composants à des sources de données
externes de ce chapitre.
g. Intégration d’une zone de texte multilignes
Cette étape ne pose pas de difficulté particulière. Il peut être intéressant de fixer un nombre de lignes et de
colonnes pour la zone de texte : il faut pour cela utiliser respectivement les attributs rows et cols de la balise de
restitution <h:inputTextArea>.
h. Intégration d’un bouton de soumission
Le traitement des données saisies se fait après la validation du formulaire : celleci est initiée par l’utilisation d’un
bouton de soumission, que l’on positionne sur la page web grâce à un objet Command Button. En général, la balise
<h:commandButton> représentant ce bouton doit disposer d’un attribut action, dont la valeur est utilisée par
l’implémentation JSF pour identifier la ressource (autre page JSP, JavaBean…) chargée de traiter les informations
saisies par l’internaute. En d’autres termes, la valeur de l’attribut action doit correspondre à l’un des cas de
navigation prévus dans le fichier de configuration des ressources de l’application.
Si l’attribut action n’est pas renseigné, les données sont traitées par la page ellemême.
Lorsque la valeur de l’attribut action est mentionnée, mais qu’elle ne correspond à aucun des cas de
navigation prévu, l’environnement Eclipse le signale par un avertissement qui précise que les données du
formulaire ne pourront pas être prises en charge.
1. Les différents types de validateurs et leur mode d’utilisation
a. Description des validateurs
La spécification JSF propose en standard quatre validateurs distincts : ils correspondent à des classes implémentant
l’interface javax.faces.validator.Validator.
Cependant, l’implémentation JSF choisie dans le cadre de cet ouvrage (Sun JSF 1.2 RI) ne permet l’exploitation que
de trois d’entre eux. Ils sont visibles dans la catégorie JSF Core de la palette, et leur utilisation directe au cours du
développement d’une application web est rendu possible par l’exploitation de balises de restitution issues de la
bibliothèque Core.
Le tableau suivant récapitule les informations concernant chaque validateur standard utilisable pour la création
d’applications web : il précise la classe dont le validateur est issu, la balise Core qui le représente, et l’objet de la
palette qui lui correspond. Le rôle du validateur est également mentionné.
Le quatrième validateur, non disponible dans l’interface Eclipse pour la conception de pages web, est issu
de la classe javax.faces.validator.MethodExpressionValidator. Il est chargé de vérifier la conformité
d’une méthode d’expression (c’estàdire qu’il s’assure qu’une expression correspond effectivement à l’appel
d’une méthode sur un objet).
b. Composants supportant les validateurs
Dans le cadre du développement d’applications web, ces validateurs ne présentent d’intérêt que lorsqu’ils sont
associés à un champ de saisie particulier. Un LengthValidator sera utilisé pour vérifier qu’un nom ou un mot de
passe a bien été saisi, alors qu’un LongRangeValidator pourra vérifier que la quantité demandée pour un article de
boutique en ligne est bien comprise entre deux valeurs données.
Les composants JSF capables de supporter les validateurs sont ceux qui sont directement issus de la classe
UIInput : celleci présente en effet une méthode addValidator(…) permettant d’associer un validateur au
composant, ainsi qu’une méthode getValidators() utilisable pour obtenir la liste de tous les validateurs associés au
composant.
c. Mode d’utilisation des validateurs
Avec l’environnement Eclipse, l’association entre un composant graphique et un validateur particulier se définit à
partir de la vue Properties, lorsque le composant de saisie en question est sélectionné. L’onglet Quick Edit de
cette vue comporte une rubrique Validators, à partir de laquelle il est possible d’associer un ou plusieurs
validateurs au composant, et de préciser leurs attributs.
Dans l’illustration cidessous, deux validateurs distincts sont associés à un champ de type HtmlInputText. Le
premier d’entre eux est un LongRangeValidator vérifiant que la chaîne saisie dans le champ est un entier compris
entre 2323 et 10671. Le second est un LengthValidator s’assurant que la longueur de la chaîne contient au
minimum 5 caractères et au maximum 6. Naturellement, les deux contraintes imposées par les validateurs devront
être vérifiées simultanément au moment de la saisie dans le champ.
2. Contrôler la longueur d’une chaîne de caractères
Il est courant, dans les formulaires de saisie, de devoir s’assurer que la chaîne saisie dans un champ a une certaine
taille. Ce type de situation se rencontre par exemple pour vérifier qu’un mot de passe contient un nombre suffisant
de caractères. La mise en œ uvre d’un tel contrôle avec JSF se fait facilement par l’utilisation d’un validateur standard
de type LengthValidator.
Ce validateur dispose de deux propriétés de type int, nommées minimum et maximum, qui permettent de réaliser le
traitement attendu.
● Lorsqu’une valeur est attribuée à minimum, le validateur s’assure que la chaîne saisie dans le champ de
formulaire contient au moins minimum caractères. Si ne n’est pas le cas, une exception de type
ValidatorException est générée : la prise en charge de celleci par l’application web peut permettre
l’affichage d’un message d’erreur adapté par l’intermédiaire d’un objet de type HtmlMessage.
● Lorsqu’une valeur est attribuée à maximum, le validateur s’assure que la chaîne saisie dans le champ de
formulaire contient au plus maximum caractères. Si ne n’est pas le cas, une exception de type
ValidatorException est générée : elle peut être prise en charge par l’intermédiaire d’un objet de type
HtmlMessage.
● Si les deux propriétés sont définies, la chaîne saisie doit répondre simultanément aux deux contraintes
précédemment citées.
Le code source suivant illustre l’exploitation d’un LengthValidator chargé de s’assurer que la chaîne saisie dans un
champ HtmlInputText dispose d’une longueur comprise entre 5 et 10 caractères. En cas du nonrespect de cette
contrainte, un message d’erreur spécifique est présenté à l’internaute grâce à un objet HtmlMessage associé au
champ de saisie.
<f:view>
<h:form>
<h:outputText id="txtIntitule"
value="Saisissez impérativement un commentaire
(entre 5 et 10 caractères):">
</h:outputText>
<br>
<h:inputText id="txtCommentaire"
label="Commentaire impératif"
required="true">
<f:validateLengthminimum="5"
maximum="10">
</f:validateLength>
</h:inputText>
<h:message id="messageCommentaire"
for="txtCommentaire"
style="color: #FF0000; font-weight: bold">
</h:message>
<br>
<h:commandButton id="btnValidation"
value="Validation du formulaire">
</h:commandButton>
Notez que la balise <h:inputText>, représentant le champ de saisie, dispose d’un attribut required positionné à true.
En effet, bien que le LengthValidator soit configuré pour vérifier que la chaîne saisie contient entre 5 et 10
caractères, celuici n’est pas en mesure de faire un quelconque traitement lors de l’absence de saisie. En l’occurrence,
aucune ValidatorException ne sera générée dans ce cas de figure et la soumission du formulaire se fera avec
succès, malgré la contrainte exprimée par le validateur. Il est donc indispensable d’imposer une saisie dans ce champ
texte, par l’usage de l’attribut de balise required.
La génération d’une ValidatorException par un validateur, quel que soit son type, lors du nonrespect d’une
contrainte, provoque systématiquement dans les applications web l’échec de validation du formulaire de
saisie. Cela oblige l’internaute à fournir des informations cohérentes et limite les risques de mise en échec de
l’application ellemême pour cause de fourniture de données inadaptées, par exemple.
3. S’assurer qu’une valeur numérique est comprise entre deux bornes
Deux validateurs permettent de répondre à ce besoin : LongRangeValidator et DoubleRangeValidator. Bien qu’ils
soient tous deux en mesure de contrôler des valeurs numériques, leur différence réside dans le fait que le premier ne
peut prendre en charge que des valeurs entières, alors que le second traite à la fois les valeurs entières et les
valeurs décimales. Cette différence est clairement visible au regard des constructeurs respectifs des deux classes :
Les modes de fonctionnement de ces deux validateurs sont identiques : ils effectuent une comparaison entre la
valeur saisie par l’internaute dans un champ de formulaire et deux valeurs, minimum et maximum.
● Si aucune valeur n’est saisie, aucun traitement n’est réalisé. Le validateur ne bloque pas la soumission du
formulaire.
● Si les propriétés minimum et maximum sont précisées, le validateur s’assure que la valeur saisie se situe bien
entre les deux. Lorsque ce n’est pas le cas, une exception de type ValidatorException est générée. Ce qui a
pour effet d’empêcher la soumission du formulaire.
● Si seule la propriété minimum est indiquée, alors le validateur vérifie que l’utilisateur a mentionné une valeur
supérieure ou égale à celleci. Dans le cas contraire, une ValidatorException est générée.
● Si seule la propriété maximum est indiquée, alors le validateur vérifie que l’utilisateur a mentionné une valeur
inférieure ou égale à celleci. Dans le cas contraire, une ValidatorException est générée.
a. Exemple d’utilisation d’un LongRangeValidator
Après avoir déposé un champ de saisie dans la zone d’édition d’Eclipse, il est possible de lui associer un
LongRangeValidator depuis la vue Properties. Les propriétés minimum et maximum peuvent également être précisées
depuis cette vue. L’aperçu du code source de la page web montre que la balise <f:validateLongRange>
correspondant au validateur est une balise enfant de celle représentant le champ de saisie (par exemple
<h:inputText>).
<f:view>
<h:form>
<h:inputText id="txtDuree">
<f:validateLongRangeminimum="2323"
maximum="10671">
</f:validateLongRange>
</h:inputText>
<h:message for="txtDuree">
</h:message>
<br>
<h:commandButton value="Tester le validateLongRange">
</h:commandButton>
</h:form>
L’association d’un objet HtmlMessage avec le champ de saisie est utile pour présenter à l’utilisateur les raisons d’un
éventuel échec de la validation. Dans le code cidessus, cette association est assurée par la déclaration de l’attribut
for de la balise <h:message>, dont la valeur correspond à celle de l’attribut id du champ à contrôler.
Outre les cas précédemment cités pour lesquels le LongRangeValidator déclenche une ValidatorException,
un échec de la validation peut également survenir lorsque la chaîne de caractères saisie par l’utilisateur
n’est pas convertible en type long. Cela se produit dès qu’un caractère non numérique est trouvé dans la chaîne,
et a fortiori le caractère point ("."). C’est la raison pour laquelle la validation d’un nombre décimal ne peut pas
être assurée par un LongRangeValidator : il faut pour cela exploiter un DoubleRangeValidator.
b. Exemple d’utilisation d’un DoubleRangeValidator
La mise en œ uvre de ce validateur ne diffère en aucun point de ce qui vient d’être dit concernant le
LongRangeValidator : l’association du validateur à un champ de saisie peut se faire depuis la vue Properties
d’Eclipse, en même temps que la précision des valeurs des deux propriétés minimum et maximum.
À l’exécution, on constate qu’effectivement la saisie d’un nombre décimal ne pose aucun problème, contrairement à
ce qui est observé avec l’usage d’un LongRangeValidator.
<f:view>
<h:form>
<h:inputText id="txtDuree">
<f:validateDoubleRange minimum="10" maximum="100">
</f:validateDoubleRange>
</h:inputText>
<h:message for="txtDuree"></h:message>
<br>
<h:commandButton value="Tester le validateDoubleRange">
</h:commandButton>
</h:form>
</f:view>
1. Les différents types de convertisseurs et leur mode d’utilisation
a. Description des convertisseurs
Un convertisseur est un objet issu d’une classe implémentant l’interface Converter, dont le rôle consiste à tenter la
conversion d’une valeur donnée pour la rendre compatible avec une propriété particulière d’un JavaBean.
La spécification JSF définit en standard treize classes de convertisseurs, permettant d’assurer des conversions vers
divers types numériques, ainsi que vers le type Date. Dans le cadre du développement d’applications web basées
sur JSF, seuls deux convertisseurs sont proposés en standard :
● Le premier traite de la conversion des nombres, en facilitant notamment la prise en charge de plusieurs
formats de données (pourcentages, monnaies, etc.) : il est disponible dans la catégorie JSF Core de la
palette d’Eclipse sous le nom convertNumber. La balise de restitution qui lui correspond est
<f:convertNumber>.
● Le second prend en charge les conversions de chaîne vers un format spécifique de date (et
réciproquement). Il se situe dans la même catégorie de la palette et se nomme dateTimeConverter. Sa balise
de restitution est <f:dateTimeConverter>.
b. Composants supportant les convertisseurs
L’analyse du diagramme des classes montre que seuls les composants graphiques JSF issus de classes basées sur
UIOutput peuvent se voir associer un convertisseur.
Il est donc possible d’attribuer un convertisseur à un champ de saisie particulier, tel qu’une zone de texte ou une
zone de liste déroulante à choix unique. Dans ce cas, le convertisseur est utilisé pour convertir la donnée saisie, de
manière à la rendre compatible avec la suite du traitement (il s’agit le plus souvent du stockage de la valeur saisie
dans une propriété d’un JavaBean).
Mais il est également possible d’utiliser un convertisseur pour l’associer à un label ou un texte présenté en lecture
seule. Dans cette situation, le convertisseur effectue un traitement réciproque de celui qui vient d’être décrit : il se
charge de convertir, si cela est possible, la valeur d’une propriété de JavaBean en vue d’un affichage au niveau de
l’interface web. Il s’agit donc d’une tentative de conversion d’un type quelconque vers le type String.
Il n’est pas possible d’associer plusieurs convertisseurs à un composant graphique particulier.
c. Mode d’utilisation des convertisseurs
De la même manière que ce qui a été vu concernant les validateurs, l’association entre un composant graphique et
un convertisseur se fait facilement depuis la vue Properties d’Eclipse, lorsque le composant en question est
sélectionné. Une fois le convertisseur déclaré, ses différents attributs peuvent rapidement être précisés depuis la
même vue.
L’illustration proposée montre les propriétés d’un objet de type HtmlOutputText. La rubrique Converter contient la
déclaration d’un convertisseur de type DateTimeConverter, alors que l’attribut value indique que ce champ texte est
associé à la propriété dateCourante du bean managé beanDateCourante.
2. Conversion des valeurs numériques
a. Propriétés utilisées dans ce type de conversion
Ce type de conversion se fait à l’aide d’un NumberConverter. Lors de la déclaration de ce type de convertisseur, la
vue Properties montre l’existence de quatre propriétés :
● type : sert à préciser si le convertisseur est utilisé pour convertir des devises monétaires, des pourcentages
ou des nombres quelconques. Elle permet aussi d’indiquer que le convertisseur ne correspond à aucun de
ces types prédéfinis : le type est alors personnalisé.
● Currency Code : cette propriété est utilisée pour des conversions de devises. Elle permet de préciser une
chaîne de caractères correspondant à la devise en question (par exemple, EUR pour les euros). Les
différentes valeurs possibles sont proposées dans une zone de liste déroulante et sont issues de la norme
ISO 4217.
● Currency symbol : utilisée également pour la conversion de devises, elle sert à mentionner le symbole
correspondant à la monnaie (par exemple, € pour les euros).
● Pattern : définit le format que doit respecter la chaîne ou la valeur de la propriété du JavaBean.
Suivant les choix réalisés au moment de la définition des propriétés du convertisseur, toutes les propriétés ne
peuvent pas être précisées : en l’occurrence, l’usage d’un convertisseur de devises exclut la mention d’une valeur
pour la propriété Pattern, alors que la déclaration d’un convertisseur de pourcentages rend inutile la précision d’une
valeur pour les propriétés Currency Code et Currency Symbol.
b. Mode de fonctionnement de la conversion
Le fonctionnement de ce type de convertisseur diffère selon que la conversion se réalise en vue du stockage d’une
valeur saisie dans une propriété de JavaBean, ou que, à l’inverse, elle est utilisée dans le but d’afficher le contenu
d’une propriété de JavaBean sur l’interface web. La première situation correspond à la conversion d’une chaîne en
Object ; la seconde est la conversion d’un Object en chaîne de caractères.
Lors de la conversion d’une chaîne en Object
La chaîne source est analysée dans le but de la convertir en objet de type Long ou Double.
● Si la propriété Pattern est renseignée, sa valeur doit respecter un certain format, selon les règles précisées
dans la classe java.text.DecimalFormat. La précision d’une valeur pour Pattern provoque l’absence de
prise en compte de la valeur de la propriété type.
Lors de la conversion d’un Object en chaîne de caractères
La constitution de la chaîne de caractères s’effectue selon la démarche suivante :
● Si l’Object source correspond à la valeur null, une chaîne de longueur nulle est restituée.
● Si l’Object source est une chaîne de caractères, celleci est restituée telle quelle.
● Si la propriété Pattern possède une valeur, celleci doit respecter le formatage prévu dans la classe
java.text.DecimalFormat. Elle rend inutile la précision d’une valeur pour la propriété type du convertisseur.
● Si la propriété Pattern n’est pas mentionnée, l’Object source est converti sous la forme d’une chaîne dont le
format correspond, selon la valeur de l’attribut type, à une devise, à un pourcentage ou à un nombre
quelconque. Le format en question correspond à celui mentionné dans les méthodes getCurrencyInstance
(), getNumberInstance() et getPercentInstance() de la classe java.text.NumberFormat.
Échec d’une conversion
Si la conversion demandée, dans un sens ou dans l’autre, ne peut pas être assurée, une exception de type
ConverterException est générée : cela empêche la soumission du formulaire dans lequel se trouve le composant JSF
auquel est associé le convertisseur. Le cas échéant, le motif de l’échec de la conversion peut être précisé à
l’internaute par le biais d’un objet de type HtmlMessage ou HtmlMessages.
c. Exemple d’utilisation d’un NumberConverter
Le code source cidessous illustre l’emploi d’un NumberConverter associé à un champ de type HtmlInputText. Ce
convertisseur est représenté par une balise <f:convertNumber> possédant un attribut pattern renseigné : la validité
de la conversion est donc déterminée en comparant le format de la chaîne saisie par l’internaute dans le champ
<h:inputText> avec la valeur du pattern.
La présence d’un objet HtmlMessage associé au champ de saisie permet de présenter à l’utilisateur le motif d’un
éventuel échec de conversion. En l’occurrence, la teneur du message en question correspondra systématiquement à
la valeur de l’attribut converterMessage de la balise <h:inputText>.
<f:view>
<h:form id="formulaireInscription">
<br>
<h:panelGrid border="1" columns="2">
<h:outputText id="otxtValeurNumerique"
value="Saisissez une valeur numérique">
</h:outputText>
<h:panelGroup>
<h:inputText id="itxtValeurNumerique"converterMessage="Format non respecté (0,00%)"
requiredMessage="Vous devez renseigner ce champ!"
required="true">
<f:convertNumber pattern="0.00%"/>
</h:inputText>
<h:message id="msgValeurNumerique"
for="itxtValeurNumerique"
style="color: #FF0000; background-color:
#FFFF00">
</h:message>
</h:panelGroup>
3. Conversion de la date et de l’heure
a. Propriétés utilisées dans ce type de conversion
Cette conversion s’obtient par l’utilisation d’un convertisseur de type DateTimeConverter. Quatre propriétés peuvent
être définies depuis la vue Properties d’Eclipse pour ce convertisseur :
● Type : sert à indiquer si la conversion concerne la date uniquement, l’heure uniquement, ou les deux
simultanément.
● Date Style : dans le cas d’une conversion de date, cette propriété est utilisée pour spécifier le style
d’affichage/de stockage de la date. Il peut s’agir d’une forme courte, complète ou intermédiaire.
● Time Style : dans le cas d’une conversion d’heure, cette propriété est utilisée pour spécifier le style
d’affichage/de stockage de l’heure. Il peut s’agir d’une forme courte, complète ou intermédiaire.
● Pattern : l’utilisation de cette propriété exclut l’emploi des trois autres propriétés précédemment évoquées.
Elle permet de mentionner un format particulier d’affichage/de stockage de la date ou de l’heure.
L’ensemble des formats autorisés est indiqué au sein d’une zone de liste déroulante.
b. Mode de fonctionnement de la conversion
De la même manière que pour un convertisseur NumberConverter, un convertisseur de type DateTimeConverter
présente un mode de fonctionnement qui diffère, selon qu’il s’occupe de la conversion d’une chaîne en vue du
stockage dans une propriété de JavaBean, ou qu’à l’inverse, il s’attache à la conversion du contenu d’une propriété
de JavaBean pour en réaliser un affichage dans l’interface utilisateur.
Lors de la conversion d’une chaîne en Object
La chaîne source est analysée afin de tenter sa conversion en objet de type Date.
● Si l’objet String initial vaut null, ou si le nombre de caractères de cette chaîne est nul, la conversion n’est
pas en échec, mais l’objet Date qui en résulte est null.
● Lorsque la propriété pattern est spécifiée, sa valeur doit être conforme aux règles mentionnées dans la
classe java.text.SimpleDateFormat.
Lors de la conversion d’un Object en chaîne de caractères
Dans ce cas de figure, le convertisseur tente la conversion d’une propriété d’un JavaBean en chaîne de caractères.
La propriété en question peut être d’un type quelconque compatible avec le type Date ou être de type String. La
démarche suivante est réalisée pour mettre en œ uvre la conversion :
● Si la valeur de propriété du JavaBean est égale à null, le résultat de la conversion est une chaîne de
caractères de longueur nulle.
● Si la propriété du JavaBean est de type String, sa valeur est restituée telle quelle par le convertisseur.
● Si la propriété pattern est spécifiée, sa valeur doit respecter la syntaxe précisée dans la classe
java.text.SimpleDateFormat. En cas d’utilisation de cette propriété, toutes les autres propriétés du
convertisseur sont ignorées.
Lorsque cette situation survient, une exception de type ConverterException est générée. La soumission du
formulaire dans lequel se trouve le composant associé au convertisseur est interrompue. Un message explicitant le
motif de l’échec de la conversion peut être présenté à l’utilisateur si un objet HtmlMessage est rattaché au
composant en question ou si un objet HtmlMessages est présent sur la page web.
c. Exemple d’utilisation d’un DateTimeConverter
À titre d’illustration, on peut imaginer la mise en place d’un formulaire de saisie à partir duquel un internaute
mentionne une date quelconque au format jj/MM/aaaa. La validation du formulaire doit entraîner l’affichage du nom
du jour correspondant à la date fournie (par exemple, samedi).
Afin de garantir la saisie de la date selon le format choisi, il est nécessaire d’associer un convertisseur de type
DateTimeConverter au champ de saisie. Ce convertisseur doit disposer d’une propriété pattern correspondant au
format à respecter.
Par ailleurs, pour rendre aisé l’affichage du nom du jour de la date saisie, il est très intéressant d’exploiter un
JavaBean dont l’une des propriétés correspond précisément à cette date, et de lier cette propriété avec un label
disposé sur la page web. L’affichage du nom du jour seul, sans précision de la date ellemême, se fait alors
extrêmement simplement par l’emploi d’un DateTimeConverter associé au label. Ce convertisseur doit comporter une
propriété pattern dont la valeur correspond au seul affichage du jour de la semaine, telle qu’elle est précisée dans
la classe SimpleDateFormat.
Pour récapituler, la page à web exploite un bean managé (à déclarer dans le fichier de description des ressources
de l’application web) comportant une propriété de type Date qui pourra servir à stocker la date saisie par
l’internaute. De plus, la page web doit comporter :
● un champ de saisie HtmlInputText lié à la propriété de type Date du bean managé, et associé à un premier
convertisseur DateTimeConverter dont la propriété pattern est égale à dd/MM/yyyy.
● Un label de type HtmlOutputText, également lié à la propriété de type Date du bean managé (mais en
lecture seule cette fois), associé à un second DateTimeConverter dont la propriété pattern est fixée à EEEE.
Voici le code source d’un JavaBean répondant au besoin exprimé. La création d’une instance de ce JavaBean
initialise la propriété de type Date avec la date du jour.
package premierProjetJSF;
import java.util.Calendar;
import java.util.Date;
public BeanDateCourante()
{
setDateCourante(Calendar.getInstance().getTime());
La déclaration d’un bean managé s’appuyant sur cette classe peut se faire dans le fichier de description des
ressources de l’application par les lignes suivantes :
<managed-bean>
<managed-bean-name>
beanDateCourante
</managed-bean-name>
<f:view>
<h:form id="formulaireInscription">
<br>
<h:panelGrid border="1" columns="2">
<h:outputText id="otxtDateDuJour"
value="Saisissez une date valide:">
</h:outputText>
<h:panelGroup>
<h:inputText id="itxtDateDuJour"value="#{beanDateCourante.dateCourante}"
converterMessage="La date indiquée doit être au
format JJ/MM/AAAA"
requiredMessage="Vous devez renseigner ce champ!"
required="true">
<f:convertDateTimepattern="dd/MM/yyyy" />
</h:inputText>
<h:message id="msgDateDuJour"
for="itxtDateDuJour"
style="color: #FF0000; background-color: #FFFF00">
</h:message>
</h:panelGroup>
</h:panelGrid>
<h:outputText id="otxtDateCourante"
value="#{beanDateCourante.dateCourante}">
<f:convertDateTime
type="date" dateStyle="full"
pattern="EEEE" />
</h:outputText><br>
<h:commandButton id="btnTester"
value="Afficher le nom du jour">
</h:commandButton>
</h:form>
</f:view>
● Les ActionEvent, qui peuvent être générés par des composants implémentant l’interface ActionSource
(notamment, les composants de type HtmlCommandButton ou HtmlCommandLink).
● Les ValueChangeEvent, qui concernent tous les composants JSF basés sur la classe UIInput (champs de saisie).
Ces événements peuvent être traités indifféremment par des écouteurs spécifiques, ou par des méthodes de
JavaBeans.
1. Prise en charge des événements par un écouteur
Un écouteur est l’instance d’une classe implémentant l’interface FacesListener, ou l’une de ses interfaces dérivées.
En l’occurrence, pour qu’une classe puisse traiter un ActionEvent, elle doit implémenter l’interface ActionListener. De
même, une classe implémentant ValueChangeListener peut réceptionner des ValueChangeEvent.
a. Utiliser un écouteur prenant en charge les ActionEvent
L’exemple suivant montre le code source d’une classe BeanActionListener implémentant ActionListener : elle
présente une méthode processAction dont l’argument correspond à un événement de type ActionEvent. Les
instructions contenues dans cette méthode se contentent d’exploiter cet événement pour en connaître l’origine (la
méthode getComponent() de la classe ActionEvent renvoie en effet la référence du composant ayant provoqué
l’événement). L’identifiant de ce composant est ensuite affiché dans la console.
package premierProjetJSF.listeners;
import javax.faces.component.UIComponent;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
Compte tenu du fait que cette classe implémente ActionListener, celleci peut être utilisée au sein d’une application
web afin de prendre en charge les ActionEvent générés lors de l’exploitation de certains composants graphiques
JSF (bouton de commande ou hyperlien).
Réaliser une association entre un composant JSF et un écouteur se fait facilement depuis la vue Properties
d’Eclipse, lorsque le composant en question est sélectionné. Si ce composant est capable de générer l’un des deux
types d’événements prévus par la spécification, une rubrique Listeners est en effet disponible. Son utilisation
permet d’associer un ou plusieurs écouteurs au composant. Bien sûr, seuls les écouteurs compatibles avec le
composant sont proposés en vue d’une association.
Dans le code source suivant, un composant de type HtmlCommandButton est présent dans la page web. La balise
<h:commandButton> qui le représente dispose d’une balise enfant, <f:actionListener>. Celleci identifie un écouteur
de type ActionListener associé au bouton ; elle possède un attribut obligatoire type permettant de mentionner la
classe implémentant l’ActionListener. Il s’agit bien sûr ici du nom complet de la classe décrite précédemment :
BeanActionListener.
<f:view>
<h:form>
L’utilisation de cette page web montre bien que la réalisation d’un clic sur le bouton de commande associé à
l’ActionListener provoque l’affichage de l’identifiant du bouton dans la console Eclipse.
b. Utiliser un écouteur prenant en charge les ValueChangeEvent
La même démarche peut être utilisée pour illustrer la mise en œ uvre d’un écouteur de type ValueChangeListener :
une classe implémentant cette interface présente une méthode processValueChange prenant en charge un objet de
type ValueChangeEvent. Cet objet correspond à un événement généré, et l’appel de sa méthode getComponent()
permet d’obtenir la référence du composant qui en est la source.
package premierProjetJSF.listeners;
import javax.faces.component.UIInput;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ValueChangeEvent;
import javax.faces.event.ValueChangeListener;
UIInput composantSaisie=
(UIInput)arg0.getComponent();
System.out.println("La valeur du composant
"+composantSaisie.getId()+ " a été modifiée
("+composantSaisie.getValue()+")");
}
}
Un composant JSF s’appuyant sur la classe UIInput peut être à l’origine d’un événement de type ValueChangeEvent.
Pour assurer un traitement spécifique lorsque survient ce type d’événement, il faut associer le composant en
question à un écouteur de type ValueChangeListener.
Dans l’exemple cidessous, un champ de type HtmlInputTextarea est positionné sur une page web, côte à côte avec
un composant HtmlCommandButton. La balise qui le représente comporte une balise enfant <f:valueChangeListener>,
indiquant qu’il est associé à un écouteur de type ValueChangeListener. Cette balise enfant dispose d’un attribut
type dont la valeur correspond au nom d’une classe capable de prendre en charge les ValueChangeEvent. En
l’occurrence ici : BeanValueChangeListener.
<f:view>
<h:form>
<h:inputTextarea id="itaCommentaires">
<f:ValueChangeListener
type="premierProjetJSF.listeners.BeanValueChangeListener"/>
</h:inputTextarea>
<h:commandButton id="btnValider" value="Valider">
</h:commandButton>
</h:form>
</f:view>
Lors de l’exécution de cette page, on constate qu’un message est indiqué dans la console Eclipse à chaque fois que
2. Associer plusieurs écouteurs à un unique composant
La spécification JSF prévoit la possibilité d’associer plusieurs écouteurs à un unique composant. Il est par exemple
réalisable de déclarer N gestionnaires pour l’événement ActionEvent pour un bouton de commande particulier. Dans
cette situation, l’événement généré est transmis successivement à l’ensemble des gestionnaires.
Le code source cidessous illustre ce cas de figure : un bouton de commande dispose de deux écouteurs capables de
prendre en charge des ActionEvent. À chaque balise <f:actionListener> représentant les écouteurs correspond une
classe spécifique implémentant l’interface ActionListener.
<f:view>
<h:form>
<h:commandButton id="btnTester"
value="Tester plusieurs écouteurs">
<f:actionListener
type="premierProjetJSF.listeners.BeanActionListener"/>
<f:actionListener
type="premierProjetJSF.listeners.EvenementClicListener"/>
</h:commandButton>
</h:form>
</f:view>
3. Gestion des événements par l’exploitation d’une méthode de JavaBean
Outre la prise en charge des événements par des écouteurs spécifiques de type ValueChangeListener ou
ActionListener, il est également possible de déléguer la gestion événementielle à de simples méthodes de classes.
Dans ce cas, les composants JSF susceptibles d’être la source des événements sont représentés sur les pages web
par des balises comportant, selon le cas, soit un attribut actionListener, soit un attribut valueChangeListener. La
valeur de ces attributs fait appel au langage d’expressions spécifique à JSF, et permet d’identifier une méthode de
bean managé chargée de traiter l’événement. Si le nom d’une telle méthode peut être choisi librement, le reste de sa
signature doit respecter les contraintes suivantes : la méthode doit être publique, de type void et accepter un unique
paramètre de type ActionEvent ou ValueChangeEvent (selon le type d’événement à prendre en charge). Les deux
lignes de code suivantes correspondent à des signatures de méthodes capables de traiter des événements générés
par des composants JSF :
Exemple de prise en charge d’un ActionEvent
Pour illustrer ce concept, imaginons que l’on souhaite mettre en place une page web contenant un bouton de
commande dont le label change chaque fois que l’internaute l’utilise (par exemple, le texte affiché sur le bouton passe
de la valeur "OUVRIR" à la valeur "FERMER", et réciproquement).
Il faut, dans un premier temps, utiliser un JavaBean comportant une méthode capable de traiter un événement de
type ActionEvent. Le code source suivant correspond à un tel JavaBean : il comporte en effet une méthode publique
de type void, dénommée traitementClic, acceptant un unique paramètre de type ActionEvent. Les instructions
contenues dans la méthode en question assurent l’obtention de la référence du composant UICommand à l’origine de
l’événement, et effectuent une permutation de sa valeur par l’appel des méthodes getValue et setValue de la classe
UICommand.
package premierProjetJSF.listeners;
import javax.faces.component.UICommand;
import javax.faces.event.ActionEvent;
Dans un second temps, il est indispensable de déclarer ce JavaBean en tant que nouvelle ressource de l’application
web : il sera alors considéré comme un bean managé et pourra donc être exploité par les pages JSP de l’application
grâce au langage d’expressions. Une telle déclaration peut prendre la forme suivante dans le fichier de configuration
des ressources de l’application :
<managed-bean>
<description>
Ce JavaBean comporte une méthode capable
de traiter les ActionEvent.
</description>
<managed-bean-name>
beanActionListener2</managed-bean-name>
<managed-bean-class>
premierProjetJSF.listeners.BeanActionListener2
</managed-bean-class>
<managed-bean-scope>
session
</managed-bean-scope>
</managed-bean>
Il ne reste plus enfin qu’à concevoir la page web ellemême. Celleci peut, par exemple, comporter une balise
<h:commandButton> dont l’attribut ActionListener identifie la méthode traitementClic du bean managé
beanActionListener2 comme gestionnaire des événements ActionEvent qui surviennent sur le bouton.
<f:view>
<h:form>
<h:commandButton
id="btnValidation"
value="OUVRIR"
actionListener="#{beanActionListener2.traitementClic}">
</h:commandButton>
</h:form>
</f:view>
À l’exécution, on constate qu’effectivement le bouton change de label à chaque fois que l’utilisateur clique dessus.
Un exemple de prise en charge d’un ValueChangeEvent par une méthode de JavaBean est présenté à la
section Ajout de composants graphiques à une page Principaux attributs de balises communs de ce
chapitre.
1. Lier un composant à l’une des propriétés d’un bean managé
Le mécanisme de liaison de composants graphiques JSF avec des propriétés de beans managés est très largement
mis en œ uvre dans la conception d’applications web basées sur cette technologie. En effet, ce type de liaison est
utilisé pour sauvegarder les informations saisies dans un formulaire par l’internaute. Il est aussi exploité pour
présenter à l’internaute les valeurs des propriétés de beans managés, en respectant parfois un formatage particulier
(exemple : une date dont on ne veut afficher que le numéro du jour).
Concrètement, la plupart des composants graphiques JSF s’appuient sur des classes disposant de deux méthodes
particulières : getValue et setValue. C’est le cas notamment de tous les composants basés sur les classes UIOutput
et UICommand. Comme leurs noms l’indiquent, ces deux méthodes servent respectivement à lire et modifier la valeur du
composant.
Bien sûr, le designer des pages web peut aisément faire appel à ces méthodes par l’exploitation de l’attribut value
des balises représentant les composants. L’usage de cet attribut est particulièrement intéressant lorsqu’il s’agit
d’afficher dans l’interface web une information stockée dans un fichier de messages. À ce sujet, de plus amples
détails sont fournis dans le chapitre Internationalisation d’une application web de cet ouvrage, concernant
l’internationalisation des applications. L’attribut value est aussi utilisé pour donner une valeur par défaut au
composant (texte d’un label, par exemple). Mais il est aussi très souvent utilisé pour lier la valeur locale d’un
composant graphique JSF avec la valeur d’une propriété de bean managé. Dans ce cas, la valeur de cet attribut fait
appel au langage d’expression JSF, grâce auquel il est possible de mentionner le nom du bean et celui de la propriété
à lier au composant.
a. Liaison en écriture (sauvegarde des données de formulaires)
La mise en place d’une telle liaison consiste à copier la valeur locale du composant graphique dans une propriété de
JavaBean. L’application la plus courante de cet artifice technologique concerne la sauvegarde des informations
saisies dans un formulaire.
Imaginons par exemple le classique cas du formulaire d’authentification qu’un internaute visualise lors de la
consultation de la première page d’une application web protégée : l’internaute y est invité à saisir un login et un
mot de passe. Afin de ne pas alourdir la visite du site, ces informations d’authentification doivent être stockées côté
serveur. Dans le cadre d’une application basée sur la technologie JSF, ce stockage côté serveur peut être assuré
par l’exploitation d’un bean managé de portée session, dont les propriétés sont compatibles avec les informations à
sauvegarder. Le code source suivant correspond à un tel JavaBean : ses propriétés name et password, toutes deux
de type String, peuvent servir à archiver côté serveur un login et un mot de passe.
package premierProjetJSF;
public LoginBean()
{
super();
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("Modification du login: "+name);
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
System.out.println("Modification du mot de passe:
"+password);
Ce JavaBean doit être rendu disponible à l’ensemble de l’application web. Pour cela, il doit être déclaré dans le
fichier de configuration des ressources en tant que bean managé. Ce bean devra nécessairement avoir une portée
session, de manière à ce qu’il subsiste en mémoire le temps de la visite du site web par l’internaute, et qu’il ne soit
pas partagé avec d’autres utilisateurs. Voici les lignes à ajouter au fichier facesconfig.xml pour assurer cette
déclaration :
<managed-bean>
<managed-bean-name>
loginBean
</managed-bean-name>
<managed-bean-class>
premierProjetJSF.LoginBean
</managed-bean-class>
<managed-bean-scope>
Session
</managed-bean-scope>
</managed-bean>
Ce bean managé peut ensuite être utilisé par les autres ressources de l’application, en utilisant l’identifiant qui lui
correspond : loginBean. La page web contenant le formulaire d’authentification contient différents composants,
dont un champ texte de type HtmlInputText et un champ de mot de passe de type HtmlInputSecret. Les balises
représentant ces composants doivent être liées aux propriétés name et password de loginBean. Pour cela, l’attribut
de balise value est exploité : sa valeur indique le nom du bean managé et la propriété liée au composant.
Notez également la présence de l’attribut action de la balise <h:commandButton> représentant le bouton de
soumission du formulaire. La valeur de cet attribut correspond à un cas de navigation prévu dans le fichier de
configuration des ressources : l’emploi du bouton de soumission entraîne donc l’utilisation de ce cas de navigation,
et donc la poursuite de la navigation vers une autre page JSP (dont le rôle peut consister à réafficher les
paramètres d’authentification saisis).
<f:view>
<h:form>
<h:panelGrid border="1" columns="3">
<h:outputText value="Login:"></h:outputText>
<h:inputText value="#{loginBean.name}"
id="champCodeClient">
</h:inputText>
<h:message for="champCodeClient"
id="messageCodeClient">
</h:message>
<h:outputText value="Mot de passe:">
</h:outputText>
<h:inputSecret value="#{loginBean.password}"
id="champMotPasse">
</h:inputSecret>
<h:message for="champMotPasse"
id="messageMotPasse">
</h:message>
</h:panelGrid>
<h:commandButton value="Valider"
id="btnLogin" action="authentificationValide">
<f:actionListener
type="premierProjetJSF.listeners.EvenementClicListener"
/>
</h:commandButton>
</h:form>
</f:view>
b. Liaison en lecture
Dans ce type de liaison, la valeur d’une propriété de bean managé est lue en vue de son affichage dans une page
web. Le plus souvent, la valeur en question est présentée à l’internaute au travers de composants de type
HtmlOutputText ou HtmlInputText. Mais d’une manière générale, elle peut être affichée dans tous les composants
Pour faire suite à l’exemple proposé précédemment pour la liaison en écriture, il est possible de mettre en place la
page JSP qui doit être dévoilée à l’internaute après la validation du formulaire d’authentification. Cette page peut
par exemple se contenter de réafficher les paramètres fournis par l’utilisateur. Pour cela, la page en question peut
comporter deux labels de type HtmlOutputText dont les balises qui les représentent disposent d’un attribut value.
Par utilisation du langage d’expression propre à JSF, la valeur de cet attribut doit référencer le bean managé
loginBean, ainsi que la propriété adaptée (name ou password). Voici un exemple de code source correspondant à
cette attente :
<f:view>
<h:form>
<h:outputText id="otxtTitre"
value="Rappel des paramètres d’authentification saisis:"
style="text-decoration: underline; font-weight: bold">
</h:outputText>
<br>
<h:outputText id="otxtLabelLogin"
value="Login: ">
</h:outputText>
<h:outputText id="otxtLogin"
style="color: #FF0000"
value="#{loginBean.name}">
</h:outputText>
<br>
<h:outputText id="otxtLabelMotPasse"
value="Mot de passe: ">
</h:outputText>
<h:outputText id="otxtMotPasse"
style="color: #FF0000"
value="#{loginBean.password}">
</h:outputText>
<br>
</h:form>
</f:view>
2. Liaison à des méthodes de beans managés
Le formulaire d’authentification précédemment évoqué contient une illustration de la navigation statique entre pages
web : la balise représentant le bouton de commande destiné à valider le formulaire dispose en effet d’un attribut
action dont la valeur est fixée. Cette valeur correspond à l’un des cas de navigation prévus dans le fichier de
configuration des ressources de l’application web. Cela signifie que, dans toutes les situations, la validation du
formulaire d’authentification implique systématiquement une navigation vers la même page web.
Mais typiquement, il serait souhaitable d’éliminer une telle rigidité en rendant possible une navigation dynamique. En
cas d’échec de l’authentification, notamment, il serait intéressant de ne pas autoriser la navigation vers la page
suivante. Pour obtenir ce résultat, il est possible de déléguer le test de validité de l’authentification au bean managé
loginBean contenant les paramètres saisis par l’internaute. Ce test de validité est alors assuré par une méthode
spécifique du JavaBean, dont le résultat peut potentiellement servir à orienter dynamiquement la navigation web. Le
code source suivant montre une méthode du bean loginBean dont le contenu permet de contrôler trivialement les
paramètres d’authentification :
Il reste à associer le résultat de l’exécution de cette méthode avec le bouton de soumission du formulaire, pour
rendre la navigation dynamique. Cela se fait simplement par le biais de l’attribut de balise action, dont la valeur fait
référence au bean managé et à la méthode verificationAuthentification grâce au langage d’expression.
<h:commandButton
action="#{loginBean.verificationAuthentification}"
value="Valider"
id="btnLogin">
</h:commandButton>
En effet, en suivant une démarche visant à séparer clairement les vues d’une application web de la couche d’accès aux
données, les pages web ne doivent jamais disposer d’un accès direct aux sources de données. Elles doivent, dans le
cas des applications Java, exploiter des classes qui, elles seules, peuvent atteindre ces sources. En conséquence, lier
un composant graphique JSF à une source de données équivaut à lier ce composant à un JavaBean qui, lui seul,
exploite les données directement.
Considérons le cas d’une page web chargée de présenter à l’internaute la liste des clients d’une boutique en ligne,
dans une zone de liste déroulante. Les informations concernant les clients sont stockées dans une table de base de
données. Conformément au modèle physique présenté cidessous, chaque client est représenté par son nom, son
prénom et son adresse email.
Au niveau de l’interface web, une zone de liste déroulante peut correspondre à un composant JSF de type
HtmlSelectManyListBox. Un élément particulier de cette zone de liste est, quant à lui, une instance de la classe
javax.faces.model.SelectItem qui peut être restituée dans les pages web par une balise <f:selectItem>. Lorsque la
zone de liste contient de nombreux éléments, il est très préférable de regrouper la totalité des items dans une classe
de type ArrayList dont la restitution dans les pages web se fait par l’intermédiaire d’une unique balise
<f:selectItems>.
En imaginant que le nombre de clients de la boutique virtuelle est important, le JavaBean chargé d’accéder directement
à la base de données peut donc être un représentant d’une classe issue de ArrayList. Par l’exploitation d’une requête
SQL adaptée, cette classe récupère l’ensemble des informations concernant les clients, puis crée un objet de type
SelectItem spécifique pour chaque client trouvé. Notez que l’un des constructeurs de la classe SelectItem permet de
mentionner la valeur et le label de l’élément de liste. Le code source suivant est celui d’une classe répondant à
l’ensemble de ces critères.
package premierProjetJSF;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import javax.faces.model.SelectItem;
Personne personne;
Ce JavaBean doit être déclaré dans le fichier de configuration des ressources, en tant que bean managé de portée
session. Cela le rendra accessible à toutes les autres ressources de l’application.
<managed-bean>
<managed-bean-name>
listePersonnes</managed-bean-name>
<managed-bean-class>
premierProjetJSF.ArrayPersonnes</managed-bean-class>
<managed-bean-scope>
session</managed-bean-scope>
</managed-bean>
Le bean managé est identifié par le nom listePersonnes. La page web chargée de présenter l’ensemble des clients à
l’internaute doit comporter une balise <h:selectManyListBox> disposant d’une unique balise enfant <f:selectItems>.
Cette dernière permet de restituer la totalité des éléments de la zone de liste déroulante : la valeur de son attribut
value doit faire référence au bean managé listePersonnes par l’intermédiaire du langage d’expression JSF.
De fait, on constate à l’exécution que la zone de liste dévoile effectivement les informations attendues concernant les
clients de la boutique virtuelle. Chaque élément de cette liste est traduit en langage HTML par une balise <option>
comportant le label et la valeur du SelectItem généré dans le bean managé.
<f:view>
<h:form>
<h:outputText
value="Liste des clients de la boutique virtuelle"
style="font-size: 24px; font-weight: bold">
</h:outputText><br>
<h:selectManyListbox size="10">
<f:selectItems value="#{listePersonnes}"/>
</h:selectManyListbox>
<br>
<h:commandButton action="voirLesSelections"
value="Valider">
</h:commandButton>
</h:form>
</f:view>
● Le premier est issu de la classe NumberConverter : son rôle consiste à tenter la conversion de la valeur saisie
dans un champ de formulaire pour la rendre compatible avec la propriété de bean managé auquel est associé
ce champ de saisie. Ce convertisseur standard réalise également un traitement réciproque, dans lequel la
valeur d’une propriété numérique d’un bean managé est convertie en chaîne de caractères afin de pouvoir être
présentée dans une page web.
Vous trouverez de plus amples informations sur les convertisseurs standards à la section Exploitation des
convertisseurs standards du chapitre Exploitation des composants standards JSF.
Malgré la souplesse proposée lors de l’exploitation de ces convertisseurs standards et le large champ d’application
qu’ils couvrent, ceuxci peuvent ne pas convenir dans certains contextes. Les traitements qu’ils réalisent peuvent par
exemple s’avérer trop succincts, ou au contraire trop poussés. Il faut alors envisager la conception de convertisseurs
personnalisés, répondant pleinement à certaines contraintes spécifiques. Pour cela, dans le cadre de la mise en place
d’applications web basées sur la technologie JSF, il est nécessaire de développer une classe représentant le nouveau
convertisseur, puis de la déclarer en tant que nouveau composant dans le fichier de configuration des ressources de
l’application. L’ensemble des autres ressources, en particulier les pages web, peut alors exploiter le nouveau
convertisseur.
1. Définition de la classe représentant le convertisseur
Une classe définissant un convertisseur doit impérativement implémenter l’interface javax.faces.convert.Converter.
Celleci prévoit deux méthodes, getAsString et getAsObject. La première doit permettre d’assurer la conversion d’une
chaîne de caractères en une instance de type Object, alors que la seconde effectue la conversion inverse. Voici les
signatures de ces deux méthodes :
En dehors du type et du nom de ces méthodes, la signature de cellesci ne diffèrent que par leur troisième argument
qui représente l’objet qui doit être converti. Le premier argument correspond au contexte JSF, c’estàdire celui de
l’application web ellemême, alors que le second argument est une référence au composant JSF pour lequel la
conversion est demandée.
Les instructions contenues dans le corps de ces méthodes peuvent être quelconques. La seule contrainte existante,
mis à part le fait que la méthode doit au final renvoyer un objet du type adapté, concerne la situation où la
conversion ne peut pas être assurée : il faut dans ce cas introduire une instruction provoquant la génération d’une
exception de type ConverterException.
Le code source qui suit correspond à la définition d’une classe répondant à tous les critères requis pour constituer un
nouveau type de convertisseur. Le rôle de ce nouveau convertisseur est de tenter la conversion d’une chaîne de
caractères en valeur numérique entière positive paire. Les situations provoquant un échec de la conversion sont les
suivantes :
● La chaîne saisie ne correspond pas à une valeur numérique.
● La chaîne saisie est une valeur numérique négative.
Lorsque l’une de ces situations est rencontrée, une ConverterException est générée : celleci est constituée d’un
message d’erreur explicite utilisé pour instancier un FacesMessage qui peut potentiellement être récupéré au niveau
de l’interface web afin d’être présenté à l’internaute.
package premierProjetJSF;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
int laValeurNumerique;
NombrePairPositif nombrePair;
try
{
//Tentative de conversion de l’argument arg2
//en valeur de type int.
//Cela peut bien sûr provoquer
//une NumberFormatException.
laValeurNumerique=Integer.parseInt(arg2);
}
catch (Exception exc)
{
String msg=exc.getMessage();
Le code source de cette classe est présenté cidessous. Il s’agit d’un simple JavaBean réalisant un test trivial au
moment de la mise à jour d’une propriété valeurEntierePositive et générant une exception le cas échéant.
package premierProjetJSF;
int valeurEntierePositive;
public NombrePairPositif()
{valeurEntierePositive=0;}
2. Déclaration du nouveau composant
Pour qu’une application web puisse exploiter une classe représentant un nouveau type de convertisseur, cette
dernière doit être déclarée explicitement dans le fichier de configuration des ressources. La déclaration se fait par
l’intermédiaire de la balise <converter> et de deux balises enfants obligatoires <converter-id> et <converter-class>.
Il est possible d’adjoindre d’autres balises enfants pour compléter cette déclaration, mais elles ne sont pas
indispensables : cellesci peuvent notamment à servir à donner un descriptif du convertisseur (balise <display-
name>), ou à indiquer la valeur par défaut de certains de ses attributs (balises <attribute>, <attribute-class>,
<attribute-class> et <default-value>).
Le code XML suivant correspond à la déclaration de la classe NombrePairConverterConverter en tant que nouveau
type de convertisseur d’une application web. Cette déclaration se limite à la précision du nom de la classe
(converter-class), de l’identifiant utilisable par les autres ressources pour tirer profit de ce convertisseur (converter-
id) et de sa description (display-name).
<faces-config
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-facesconfig_1_2.xsd"
version="1.2">
...
<converter>
<display-name>
convertisseurNombrePairPositif</display-name>
<converter-id>
monConvertisseurNombrePairPositif</converter-id>
<converter-class>
premierProjetJSF.NombrePairPositifConverter</converter-class>
</converter>
...
</faces-config>
3. Faire appel au nouveau convertisseur dans les pages web
Une fois que la classe correspondant au nouveau type de convertisseur est développée et déclarée dans le fichier de
configuration des ressources de l’application web, il est possible de faire usage du nouveau composant depuis toutes
les autres ressources.
Concernant les pages JSP de l’application, la démarche d’utilisation du nouveau convertisseur est identique à celle
suivie pour l’exploitation des convertisseurs standards : là où sont utilisées les balises de restitution
<f:convertNumber> ou <f:convertDateTime>, on fait appel à la balise de restitution <f:converter> pour associer un
convertisseur personnalisé à un composant graphique JSF. Cette balise doit obligatoirement faire mention d’un
attribut converterId dont la valeur doit correspondre à celle de la balise <converter-id>, indiquée dans le fichier de
configuration des ressources.
Voici un exemple de page JSP exploitant le convertisseur personnalisé d’identifiant
monConvertisseurNombrePairPositif. Celuici est associé à un champ de saisie de type HtmlInputText. Au moment de
la validation du formulaire contenant ces deux composants, le convertisseur tentera de réaliser la conversion
demandée en s’assurant que la chaîne saisie par l’internaute peut effectivement être utilisée pour constituer une
instance de la classe NombrePairPositif. Lorsque cette conversion n’est pas possible, une exception est générée par
le convertisseur et le motif de l’échec de la conversion est présenté à l’internaute par le bais d’un composant de type
HtmlMessage.
<f:view>
<h:form>
<H1><u>
Test d’un convertisseur JSF personnalisé
</u></H1>
<h:outputText
value="Tentative de conversion en objet de type NombrePairPositif"
style="color: #0000FF">
</h:outputText>
<br><br>
<h:message for="txtSaisie"
style="color: #FF0000; background-color: #FFFF00">
</h:message>
<br>
<h:outputText value="Si vous tapez ici une lettre, un
nombre négatif, ou un nombre impair, une erreur de
conversion se produira.">
</h:outputText>
<br>
<h:inputText id="txtSaisie">
<br>
<h:commandButton
value="Tester la valeur saisie"
action="succesConversion">
</h:commandButton>
</h:form>
</f:view>
● Le validateur de type DoubleRangeValidator, qui permet de comparer la valeur d’un composant graphique JSF
avec deux valeurs minimum et maximum. Il prend en charge les nombres entiers, ainsi que les nombres décimaux.
● Le validateur de type LongRangeValidator, qui effectue un traitement similaire à celui entrepris par le
DoubleRangeValidator, en dehors du fait qu’il ne prenne pas en compte les nombres décimaux.
● Le validateur de type LengthValidator : il teste la longueur de la chaîne de caractères correspondant à la
valeur d’un composant JSF spécifique, en la comparant avec deux limites maximum et minimum.
● Le validateur de type MethodExpressionValidator : son rôle consiste à vérifier le format d’un objet de type
MethodExpression, en s’assurant qu’il correspond bien à l’appel d’une méthode sur un objet. Ce validateur n’est
pas disponible lors de la mise en place d’applications web.
Bien que ces validateurs standards permettent de répondre à un grand nombre de besoins, ils peuvent ne pas être
adaptés à certaines situations particulières. Il revient alors aux concepteurs d’une application web d’envisager
l’élaboration de validateurs personnalisés, en général chargés de réaliser des vérifications nettement plus poussées
sur les valeurs des différents composants JSF disposés sur les pages web. La démarche de création et d’utilisation de
validateurs personnalisés est similaire à celle qui a été évoquée à propos des convertisseurs personnalisés : il convient
tout d’abord de concevoir la classe Java qui permettra d’instancier le nouveau validateur, puis de la déclarer dans le
fichier de configuration des ressources de l’application web. Il reste ensuite à faire appel au validateur personnalisé
dans les différentes pages web, par l’exploitation d’une balise de restitution adaptée.
1. Définition de la classe représentant le validateur personnalisé
Un validateur est toujours un objet issu d’une classe implémentant l’interface javax.faces.validator.Validator. La
constitution d’une classe correspondant à un nouveau type de validateur amène donc nécessairement le développeur
à respecter cette contrainte, en l’obligeant à déclarer et implémenter une méthode validate dont la signature est la
suivante :
Les arguments de cette méthode indiquent que la validation porte sur la valeur value d’un composant JSF component,
et qu’elle concerne une application web spécifique, identifiée par le contexte context. Par ailleurs, la signature de la
méthode validate précise également que celleci est susceptible de déclencher une exception de type
ValidatorException. Cela doit effectivement être le cas dans toutes les situations où la validation de la valeur du
composant est en échec. À ce sujet, les raisons qui déterminent le succès ou l’échec d’une validation dépendent
entièrement du contexte dans lequel vient s’insérer l’application web à mettre en place. Ces raisons sont bien sûr
traduites dans l’implémentation de la méthode validate.
La classe Java, dont le code source est présenté cidessous, correspond à un validateur personnalisé permettant de
s’assurer que la valeur d’un composant JSF est une chaîne caractérisée par les éléments suivants :
● Sa longueur est au moins égale à la valeur de la propriété minimumLength.
● Elle contient au moins l’un des caractères spéciaux définis dans la propriété caracteresSpeciaux.
● Elle contient un nombre de caractères chiffrés au moins égal à la valeur de la propriété nombreChiffres.
Typiquement, un tel validateur peut être utilisé pour forcer un internaute à saisir un mot de passe disposant de
critères précis. La méthode validate de cette classe indique les trois vérifications sont réalisées successivement, et
que chacune d’elles peut donner lieu à la génération d’une exception de type ValidatorException lorsque le critère
testé n’est pas respecté. Dans ce cas, une chaîne de caractères décrivant le motif de l’échec de la validation est
utilisé pour instancier un objet de type FacesMessage. Cet objet peut potentiellement être récupéré au niveau de la
package premierProjetJSF;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
int minimumLength;
char[] caracteresSpeciaux;
int nombreChiffres;
String message_minimumLength;
String message_caracteresSpeciaux;
String message_nombreChiffres;
chaineCarac+=tableau[i]+", ";
}
chaineCarac+="ou "+tableau[tableau.length-1];
public ValidatorPassword() {
//Définition des caractères spéciaux par défaut.
char[] spec={’#’,’%’,’&’,’$’,’=’};
setCaracteresSpeciaux(spec);
String pwd=arg2.toString();
if (!checkMinimumLength(pwd)) throw new
ValidatorException(new FacesMessage(getMessageMinimumLength()));
if (!checkCaracteresSpeciaux(pwd)) throw new
ValidatorException(new FacesMessage(getMessageCaracteresSpeciaux()));
if (!checkNombreChiffres(pwd)) throw new
ValidatorException(new FacesMessage(getMessageNombreChiffres()));
}
2. Déclaration du nouveau composant
Afin de rendre un nouveau validateur disponible à l’ensemble d’une application web, celuici doit être déclaré comme
tel dans le fichier de configuration des ressources. Cela se fait par l’intermédiaire d’une balise <validator> disposant
de plusieurs balises enfants permettant de préciser les caractéristiques du validateur :
● <validator-class> : permet de spécifier le nom complet de la classe à partir de laquelle le validateur pourra
être instancié. Cette balise est bien sûr obligatoire.
● <display-name> : permet de préciser un texte descriptif du validateur.
● <attribute>, <attribut-name>, <attribute-class> et <default-value> : sert à définir le nom, la classe et la
valeur par défaut d’un attribut spécifique de la balise <f:validator> représentant le validateur personnalisé
dans la page web.
Compte tenu de ces informations, la déclaration de la classe ValidatorPassword comme validateur personnalisé peut
être réalisée dans le fichier de configuration des ressources par le code XML suivant :
<validator>
<display-name>
Validation du mot de passe</display-name>
<validator-id>
monValidateurDeMotDePasse</validator-id>
<validator-class>
premierProjetJSF.ValidatorPassword</validator-class>
<attribute>
<attribute-name>param1</attribute-name>
<attribute-class>java.lang.Integer</attribute-class>
<default-value>4</default-value>
</attribute>
<attribute>
<attribute-name>param2</attribute-name>
<attribute-class>java.lang.Integer</attribute-class>
<default-value>3</default-value>
</attribute>
</validator>
Depuis l’environnement Eclipse, une telle déclaration se fait simplement lorsque le fichier de configuration des
ressources est présenté dans la zone d’édition : il faut sélectionner l’onglet Component, puis la rubrique Validators,
pour visualiser un formulaire de saisie spécifique aux validateurs personnalisés. Par l’utilisation de celuici, le
concepteur de l’application peut indiquer l’ensemble des caractéristiques du nouveau validateur.
3. Faire appel au nouveau validateur dans les pages web
Lorsque la classe caractérisant le nouveau validateur est développée, et que celleci est déclarée dans le fichier de
configuration des ressources, le composant personnalisé peut être utilisé dans les différentes pages web d’une
application.
Un validateur personnalisé est associé à un composant JSF spécifique par utilisation d’une balise <f:validator>
disposant d’un attribut validatorId. Cet attribut permet de préciser l’identifiant du validateur, tel qu’il est donné dans
le fichier de configuration des ressources. D’autres attributs peuvent éventuellement être précisés pour la balise
<f:validator>, à condition que ceuxci aient été prévus.
Le code source suivant illustre l’exploitation du validateur personnalisé d’identifiant monValidateurDeMotDePasse, issu
de la classe ValidatorPassword. Ce validateur est ici utilisé pour contrôler la saisie réalisée dans un champ de type
HtmlInputSecret. Au moment de la soumission du formulaire, le validateur vérifie que tous les critères requis sont
respectés (longueur minimale, nombre de caractères spéciaux, nombre de caractères chiffrés). Si la validation échoue,
la soumission du formulaire est interrompue et un message correspondant à la ValidatorException est présenté à
l’internaute par le biais d’un objet HtmlMessage.
<f:view>
<h:form>
<h:panelGrid border="1" columns="3">
<h:outputText value="Login:">
</h:outputText>
<h:inputText value="#{loginBean.name}"
id="champCodeClient">
</h:inputText>
<h:message for="champCodeClient" id="messageCodeClient">
● Conception de la classe régissant le comportement du nouveau composant.
● Déclaration du composant dans le fichier de configuration des ressources.
● Mise en place d’un fichier TLD comprenant les caractéristiques de la balise chargée de représenter le nouveau
composant dans les pages JSP de l’application web.
● Définition d’une classe faisant office de TagHandler associé à la balise représentant le nouveau composant.
● Si nécessaire, conception d’une (ou de plusieurs) classe(s) chargée(s) d’assurer la restitution graphique du
composant au niveau de l’interface web. Lorsque cette possibilité est exploitée, il est indispensable de modifier
le fichier de configuration des ressources pour que cette classe de restitution soit exploitable par l’application
web.
● Association éventuelle de gestionnaires d’événements, de validateurs et de convertisseurs au nouveau
composant.
● Développement des pages JSP exploitant le composant graphique personnalisé.
Cependant, dans toutes les situations, la classe représentant un nouveau composant graphique personnalisé doit
impérativement dériver de la classe UIComponentBase. Le nom de la classe à créer peut être choisi librement, en
sachant toutefois que les composants destinés à être affichés dans les pages web doivent conventionnellement être
définis par des classes dont le nom commence par Html.
1. Création d’un composant destiné à l’affichage simple (lecture seule)
Considérons un exemple simple dans lequel un composant graphique personnalisé est chargé de présenter l’heure
courante à l’internaute.
a. Si le composant gère luimême sa restitution graphique
Pour que le composant puisse assurer sa propre restitution graphique, la classe qui le représente doit implémenter
l’une des méthodes encodeBegin et encodeEnd, définies dans la classe parente UIComponentBase. Il est également
possible de définir ces deux méthodes simultanément, comme le montre le code source présenté cidessous.
La méthode encodeBegin est invoquée lors de l’interprétation de la balise ouvrante représentant le
composant, alors que la méthode encodeEnd est exploitée au moment de l’interprétation de la balise
fermante correspondante.
package premierProjetJSF.composantsPersonnalises;
import java.io.IOException;
import java.util.Calendar;
import javax.faces.component.html.HtmlOutputText;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
@Override
public void encodeBegin(FacesContext context)
throws IOException {
//Récupération de l’heure courante.
Calendar calendrier=Calendar.getInstance();
String heureCourante=
calendrier.get(Calendar.HOUR)+":"
+calendrier.get(Calendar.MINUTE)+":"
@Override
public void encodeEnd(FacesContext context)
throws IOException {
//Récupération d’un référence au flux de sortie.
ResponseWriter out=context.getResponseWriter();
String reponse="</b>";
out.write(reponse);
}
}
Ces deux méthodes acceptent en paramètre une référence au contexte de l’application web. Grâce à celuici, une
référence au flux de sortie peut être obtenue, puis utilisée pour présenter le message attendu au niveau de
l’interface graphique.
b. Si le composant délègue sa restitution graphique à un Renderer spécifique
Dans certaines situations, il peut être intéressant de ne pas fixer définitivement la restitution graphique d’un
composant personnalisé : dans ce cas, la charge de la restitution doit être confiée à un Renderer particulier. Le
designer de l’application web dispose alors de la possibilité de choisir l’apparence du composant, compte tenu de
l’évolution des contraintes graphiques à respecter, en sélectionnant un Renderer adapté. Le composant précédent
peut par exemple présenter le résultat attendu, sous la forme d’un texte encadré écrit en rouge sur fond jaune :
Un composant personnalisé peut déléguer la restitution graphique à un Renderer au moment de l’interprétation de
la balise ouvrante correspondant au composant, ou au moment de l’interprétation de la balise fermante, ou dans
les deux cas. Suivant le choix effectué, les méthodes encodeBegin et/ou encodeEnd ne doivent pas être
implémentées dans la classe représentant le composant : elles doivent l’être dans la classe correspondant au
Renderer. Par contre, la classe du nouveau composant doit obligatoirement définir une méthode getFamily, dont le
rôle consiste à renvoyer une chaîne de caractères identifiant le nom de la famille du composant. Ce nom peut être
choisi librement, mais doit permettre de sélectionner un Renderer particulier : il doit donc correspondre aux
informations spécifiées dans le fichier de configuration des ressources, au moment de la déclaration d’un Renderer
(voir la section Constitution du rendu des composants personnalisés Déclaration du nouveau Renderer dans le
fichier de configuration des ressources de l’application de ce chapitre).
Le code source suivant illustre la création d’un composant HtmlHeureCourante2, réalisant la même action que celui
présenté précédemment. Ce composant conserve la charge de la restitution graphique de la balise fermante qui le
représente (la classe implémente la méthode encodeEnd), mais délègue la restitution de sa balise ouvrante à un
Renderer. Le Renderer en question n’est bien sûr pas précisé ici, puisque l’intérêt de cet artifice technologique est
de permettre au designer web de choisir librement celuici. Par contre, la classe implémente la méthode getFamily,
qui renvoie la chaîne heureCourante2 identifiant la famille du nouveau composant : cette chaîne est utilisée par
l’implémentation JSF pour identifier un Renderer adapté.
package premierProjetJSF.composantsPersonnalises;
import java.io.IOException;
@Override
public String getFamily() {
return "heureCourante2";
}
Si les méthodes encodeBegin et/ou encodeEnd sont définies conjointement avec la méthode getFamily, leur
implémentation sera utilisée prioritairement à celle proposée dans le Renderer associé au composant.
2. Création d’un composant permettant la saisie d’informations
De manière à pouvoir disposer de toutes les caractéristiques liées aux champs de saisies standards de la
spécification JSF, les composants de saisie personnalisés doivent obligatoirement être issus de classes dérivées de
UIInput.
Ces classes doivent implémenter la méthode encodeEnd, de manière à assurer la restitution graphique du composant,
tout en permettant la prise en charge de convertisseurs éventuellement associés à celuici.
Par ailleurs, il convient également de permettre un accès aux paramètres passés dans la chaîne de requête au
moment de la soumission du formulaire dans lequel sont insérés les champs de saisie personnalisés. Cet accès est
assuré par l’implémentation de la méthode decode dans les classes correspondant aux composants.
Imaginons à présent la conception d’un composant graphique plus complexe que celui traité précédemment, composé
d’un label, d’une zone de texte et d’un bouton. Ce type de composant peut par exemple servir à la saisie d’une
adresse email dans un formulaire web, comme le montre l’illustration suivante :
Le code source qui suit est une implémentation possible pour un tel composant :
package premierProjetJSF.composantsPersonnalises;
import java.io.IOException;
import java.util.Map;
import javax.faces.component.UIInput;
import javax.faces.context.ExternalContext;
@Override
public void encodeEnd(FacesContext context) throws IOException {
//Récupération d’un référence au flux de sortie.
ResponseWriter out=context.getResponseWriter();
@Override
public void decode(FacesContext context) {
ExternalContext externalContext
=context.getExternalContext();
Map<String, String> parametresRequete
=externalContext.getRequestParameterMap();
String idChampSaisie=getIdChampNom(context);
La méthode encodeEnd assure la restitution graphique du composant, en renvoyant vers le flux de sortie une chaîne
de caractères correspondant à l’ensemble des balises HTML nécessaires. Cette chaîne se compose donc d’un label
associé au champ de saisie, d’une balise <input type=’text’> représentant le champ de saisie luimême, et du
bouton de soumission correspondant à la balise <input type=’submit’>.
Ces deux balises doivent impérativement disposer d’un attribut name afin de pouvoir être prises en charge au moment
de la soumission du formulaire. La valeur de ces attributs devant nécessairement être unique au sein du formulaire,
celleci peut s’obtenir dynamiquement par appel de la méthode getClientId.
3. Permettre la prise en charge des attributs de balise
Que ce soit pour la conception de composants personnalisés en lecture seule, ou pour celle relative aux composants
permettant la saisie, il peut être intéressant de permettre l’utilisation d’attributs de balises pour faciliter la
personnalisation des composants graphiques.
L’exemple précédent gagnerait effectivement en souplesse s’il était possible, notamment, de personnaliser le label du
champ de saisie ainsi que celui du bouton de soumission, grâce aux attributs de la balise correspondant au
composant personnalisé. Pour obtenir un tel résultat, il faut légèrement modifier le code source de la méthode
encodeEnd, chargée de restituer graphiquement la balise de fermeture du composant. Les modifications doivent porter
sur l’attribution de valeurs, initialement fixes, aux variables locales labelChamp et labelBouton :
String labelChamp=
(String)getAttributes().get("labelChampSaisie");
String labelBouton=
(String)getAttributes().get("labelBoutonSoumission");
L’appel de la méthode getAttributes permet de récupérer une collection contenant toutes les propriétés du
composant personnalisé. L’obtention d’une propriété particulière est réalisée par appel de la méthode get sur la
collection, à laquelle le nom de la propriété à trouver est passé en paramètre. Dans l’exemple proposé, les propriétés
labelChampSaisie et labelBoutonSoumission sont recherchées : cellesci correspondent aux attributs de balise que
l’on souhaite utiliser pour définir respectivement le label du champ de saisie, et celui du bouton de soumission.
L’instruction suivante est un exemple de balise représentant le composant personnalisé : celleci se nomme
composantInputButton et dispose des deux attributs évoqués.
Malgré ces modifications dans le code source de la classe définissant le composant, la prise en charge des
attributs de balise ne peut être effective que si le TagHandler associé à la balise du composant assure
également les opérations nécessaires à leur traitement. La section Définition de balises de composants
personnalisés Définition d’un TagHandler associé à la balise représentant un composant de ce chapitre montre
comment réaliser cette action.
4. Déclaration des nouveaux composants dans le fichier de configuration des
ressources de l’application
Une fois que la classe correspondant à un nouveau composant graphique est intégralement constituée, celleci doit
être déclarée au sein du fichier de configuration des ressources, de manière à permettre son utilisation en tant que
composant personnalisé dans l’application web.
Cette déclaration se fait à l’aide d’une balise <component> directement issue de la balise <faces-config>. Elle
comporte deux éléments essentiels : <component-type>, dont la valeur est utilisée par les TagHandler souhaitant
s’associer au composant en question, et <component-class>, permettant de préciser le nom complet de la classe
définissant le composant.
Le code source suivant est un extrait de fichier de configuration des ressources d’une application exploitant les trois
composants personnalisés évoqués précédemment dans ce chapitre. Ces composants sont identifiés par les types
HtmlHeureCourante, monHtmlHeureCourante2, et monHtmlInputButton. Ils correspondent respectivement aux classes
HtmlHeureCourante, HtmlHeureCourante2 et HtmlInputButton dont le code source a déjà été donné.
<component>
<description>
Description du composant personnalisé
</description>
1. Mise en place d’un fichier TLD (Tag Library Descriptor)
Un fichier TLD doit être positionné, de préférence, dans le sousrépertoire WEBINF/tlds de l’application web : son
contenu présente la totalité des balises rattachées à la librairie.
Chaque balise comporte diverses informations permettant notamment :
● d’indiquer le nom de la balise, tel qu’il devra être utilisé dans les pages JSP pour instancier un composant
particulier. Cette information, obligatoire, est donnée par l’intermédiaire de la balise <name>.
● de mentionner le nom complet de la classe correspondant au composant à instancier (balise <tag-class>). La
précision de cette information est impérative.
● de préciser si la balise peut ou non disposer d’un corps (balise <body-content>). L’absence de cette
information indique que la balise supporte effectivement la précision d’un contenu, alors que l’attribution de la
valeur empty à la balise <body-content> empêche cette situation.
● de mentionner la liste de tous les attributs, obligatoires et optionnels, supportés par la balise personnalisée.
Chaque attribut de balise se définit à l’aide d’une balise <attribute>, capable de prendre en charge les balises
enfant <name> et <required>. La première de ces balises permet de préciser le nom de l’attribut, tel qu’il devra être
mentionné dans les pages JSP de l’application. Quant à la balise <required>, elle sert à indiquer si l’attribut en
question est obligatoirement requis.
Le code source suivant correspond au contenu d’un fichier TLD nommé mesPremiersTagsPersonnalises.tld. Il définit
trois balises personnalisées destinées à être associées aux trois composants personnalisés précédemment évoqués.
Parmi elles, on retrouve la balise composantInputButton et la précision de ces deux attributs obligatoires
labelChampSaisie et labelBoutonSoumission.
<attribute>
<name>id</name>
</attribute>
<attribute>
<name>label</name>
<required>true</required>
</attribute>
</tag>
<tag>
<description>
Composant affichant l’heure courante avec
un renderer spécifique
</description>
<name>heureCouranteAvecRenderer</name>
<tag>
<description>
Composant constitué d’un champ de saisie
et d’un bouton de soumission
</description>
<name>composantInputButton</name>
<tag-class>
premierProjetJSF.composantsPersonnalises.HtmlInputButtonTag
</tag-class>
<body-content>empty</body-content>
<attribute>
<name>id</name>
</attribute>
<attribute>
<name>labelChampSaisie</name>
<required>true</required>
</attribute>
<attribute>
<name>labelBoutonSoumission</name>
<required>true</required>
</attribute>
</tag>
</taglib>
2. Définition d’un TagHandler associé à la balise représentant un composant
a. Méthodes assurant la liaison avec un composant graphique et un Renderer
La méthode getComponentType sert à renvoyer une chaîne identifiant la classe correspondant au composant
graphique associé à la balise. La valeur de cette chaîne doit impérativement correspondre avec celle de la balise
<component-type> définissant un composant personnalisé dans le fichier de description des ressources de
l’application.
La méthode getRendererType permet de renvoyer une chaîne de caractères identifiant le Renderer à associer
éventuellement avec la balise. Si aucun Renderer ne doit être associé, alors cette méthode doit renvoyer la valeur
null. Dans le cas contraire, la valeur retournée doit correspondre avec celle de la balise <renderer-type>
définissant un Renderer personnalisé dans le fichier de configuration des ressources.
b. Méthodes permettant la prise en charge des attributs de balise
Comme cela a déjà été précisé, la prise en charge des attributs de balise ne peut être assurée uniquement depuis
la classe définissant un composant personnalisé. En effet, à chaque attribut de balise doit correspondre une
propriété privée de même nom au sein de la classe définissant le TagHandler. Ces propriétés privées doivent
impérativement être rendues accessibles en écriture au moyen d’un accesseur setNomAttribut. Ainsi, à un attribut
de balise labelChampSaisie correspond une propriété privée de même nom et un accesseur en écriture nommé
setLabelChampSaisie.
Par ailleurs, la transmission de la valeur des attributs de balises entre un TagHandler et le composant personnalisé
Le code source suivant correspond à la classe définissant un TagHandler pour la balise composantInputButton,
représentant le composant personnalisé de type HtmlInputButton. On constate que la transmission de la valeur des
attributs labelChampSaisie et labelBoutonSoumission au composant se fait par appel de la méthode getAttributes
sur l’objet correspondant à ce composant. Cette méthode renvoie la liste des attributs, qu’il est possible de mettre
à jour grâce à l’invocation d’une méthode put, en mentionnant le nom et la valeur des nouveaux attributs.
package premierProjetJSF.composantsPersonnalises;
import javax.faces.component.UIComponent;
import javax.faces.webapp.UIComponentELTag;
@Override
public String getComponentType() {
//Renvoie le nom du type de composant à associer
//à cette balise.
//Ce nom doit être déclaré dans le faces-config.xml.
return ("monHtmlInputButton");
}
@Override
public String getRendererType() {
//Aucun Renderer n’est associé
return null;
}
composant.getAttributes().put("labelChampSaisie",
labelChampSaisie);
composant.getAttributes().put("labelBoutonSoumission",
labelBoutonSoumission);
}
}
Dans un souci d’exhaustivité, voici le code source d’un TagHandler associé à la balise correspondant au composant
personnalisé monHtmlHeureCourante2. Pour rappel, ce composant utilise un Renderer spécifique dont la description
est donnée dans le paragraphe suivant. La chaîne identifiant ce Renderer est renvoyée par la méthode
getRendererType de la classe.
package premierProjetJSF.composantsPersonnalises;
import javax.faces.component.UIComponent;
@Override
public String getRendererType() {
//Renvoie le nom du type de Renderer à utiliser avec
//le composant associé.
//Renvoie null si le composant associé doit gérer
//lui-même le Rendering.
return "heureAvecRenderer";
}
@Override
protected void setProperties(UIComponent composant) {
super.setProperties(composant);
composant.getAttributes().put("label", leLabel);
}
}
L’intérêt de définir des classes spécifiquement chargées de la restitution graphique est de permettre à un composant
d’être représenté graphiquement de différentes manières. En outre, un Renderer particulier n’est pas spécifiquement
lié à un type de composant donné : une fois défini, il peut être associé à n’importe quel type de composant graphique
rattaché à une famille particulière.
1. Définition d’une classe représentant un Renderer personnalisé
Un Renderer personnalisé est simplement une classe dérivée de la classe javax.faces.render.Renderer. Les actions
assurées pour restituer graphiquement la balise d’ouverture correspondant à un composant sont décrites dans une
méthode encodeBegin, acceptant en paramètres la référence du contexte de l’application web, ainsi que celle du
composant pour lequel la restitution est demandée. Une méthode encodeEnd, comportant les mêmes paramètres, est
chargée de préciser ce qui doit être fait pour restituer graphiquement la balise de fermeture associée au composant.
Ces méthodes peuvent être implémentées conjointement, mais un Renderer peut également ne comporter que l’une
d’elles. De plus, si le composant graphique définit luimême l’une ou l’autre des méthodes encodeBegin et encodeEnd,
l’implémentation précisée dans le Renderer est totalement ignorée.
package premierProjetJSF.composantsPersonnalises;
import java.io.IOException;
import java.util.Calendar;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;
@Override
public void encodeBegin(FacesContext context,
UIComponent component)
throws IOException {
//Méthode utilisée en début d’encodage,
//à moins que le composant
//dispose lui-même d’une méthode encodeBegin.
super.encodeBegin(context, component);
System.out.println("encodeBegin du Renderer pour
le composant de classe "+component.getClass().toString());
Calendar calendrier=Calendar.getInstance();
String intitule=
(String)component.getAttributes().get("label");
String heureCourante=
calendrier.get(Calendar.HOUR)+":"
+calendrier.get(Calendar.MINUTE)+":"
+calendrier.get(Calendar.SECOND);
ResponseWriter out=context.getResponseWriter();
out.write("
<table border=’1’>
<tr bgcolor=’yellow’><td>
<font color=’red’>
"+intitule+":"+heureCourante+"
</font></td></tr></table>");
}
@Override
public void encodeEnd(FacesContext context,
UIComponent component)
throws IOException {
//Méthode utilisée en fin d’encodage,
Ce code source correspond à celui d’un Renderer nommé HeureCouranteRenderer. Sa méthode encodeBegin permet
d’afficher l’heure courante dans le navigateur web. Cette information est mentionnée à l’aide d’une police rouge sur
fond jaune, et se trouve positionnée au sein d’une cellule de tableau HTML.
2. Déclaration du nouveau Renderer dans le fichier de configuration des ressources
de l’application
De même que pour les composants personnalisés euxmêmes, la création d’une classe dérivée de Renderer ne suffit
pas à rendre un Renderer utilisable par une application web. Celuici doit en effet être déclaré comme tel au sein du
fichier de configuration des ressources.
Cette déclaration doit comporter les informations suivantes :
● Nom complet de la classe implémentant le Renderer (balise <renderer-class>).
● Nom de la famille de composants à laquelle s’adresse le Renderer (balise <component-family>). Ce nom
correspond à la chaîne de caractères renvoyée par la méthode getFamily des composants en question.
● Identifiant du Renderer (balise <renderer-type>). Celuici est utilisé pour associer un TagHandler à un
Renderer donné.
Voici un extrait de fichier de configuration des ressources permettant de déclarer un Renderer nommé
heureAvecRenderer, basé sur la classe HeureCouranteRenderer. Ce Renderer peut être utilisé avec les composants de
la famille heureCourante2, ce qui est le cas des composants basés sur la classe HtmlHeureCourante2 présentée
précédemment.
<render-kit>
<renderer>
<display-name>
Heure courante avec Renderer</display-name>
<component-family>
heureCourante2</component-family>
<renderer-type>
heureAvecRenderer</renderer-type>
<renderer-class>
premierProjetJSF.composantsPersonnalises.HeureCouranteRenderer
</renderer-class>
</renderer>
</render-kit>
Une prise en charge correcte des différents événements par des composants personnalisés suppose que le concepteur
d’une application web réalise les opérations suivantes :
● Développer la/les classe(s) chargée(s) de gérer les événements.
● Déclarer dans la TLD les attributs de balises qui seront utilisés dans les pages JSP pour identifier les
gestionnaires d’événements.
● Modifier le code source du TagHandler associé à la balise correspondant au nouveau composant, de manière à
permettre la prise en charge de ces attributs de balise.
Pour illustrer ce propos, voyons comment rendre le composant de type HtmlInputButton capable de générer des
événements.
1. Développement du gestionnaire d’événements
Compte tenu du fait que la classe HtmlInputButton dérive directement de UIInput, les composants personnalisés qui
en sont issus sont en mesure d’être à l’origine d’événements de type ValueChangeEvent. La constitution d’une classe
capable de gérer ces événements peut simplement se limiter à l’implémentation d’une méthode acceptant un
ValueChangeEvent en argument. Dans le code source cidessous, la méthode changementValeur répond à cette
caractéristique : son rôle consiste à afficher dans la console le nom du composant, ainsi que sa nouvelle valeur, à
chaque fois que survient un ValueChangeEvent.
package premierProjetJSF.composantsPersonnalises;
import javax.faces.component.UIInput;
import javax.faces.event.ValueChangeEvent;
Bien sûr, pour que ce gestionnaire d’événements soit exploitable depuis les pages JSP d’une application web, le
fichier de configuration des ressources doit être mis à jour par la déclaration d’un bean managé correspondant à la
classe GestionnaireEvenements :
2. Modification de la TLD
Pour permettre au designer web de mentionner la référence du gestionnaire d’événements au travers de la balise
représentant le composant personnalisé, il est nécessaire de définir un attribut spécifique. Cette déclaration
comporte nécessairement le nom de cet attribut, qui, compte tenu de son rôle, peut conventionnellement être
valueChangeListener. D’autres informations importantes concernant cet attribut doivent également être précisées :
son caractère obligatoire (balise <required>) et la signature de la méthode chargée de gérer l’événement (balise
<method-signature>).
<attribute>
<description>
Permet de spécifier un gestionnaire pour les évènements
de type ValueChangeEvent.
</description>
<name>valueChangeListener</name>
<required>false</required>
<deferred-method>
<method-signature>
nomDeMethodeQuelconque(javax.faces.event.ValueChangeEvent)
</method-signature>
</deferred-method>
<type>String</type>
</attribute>
Notez la particularité de la signature de méthode indiquée par la balise <method-signature> : elle ne doit
comporter aucun type, et le nom de la méthode peut être tout à fait quelconque. La seule contrainte
concerne le type de l’argument de méthode, qui lui, doit obligatoirement correspondre à celui de la méthode
chargée de gérer l’événement (ValueChangeEvent).
3. Modification du TagHandler
Cette action consiste à déclarer une propriété supplémentaire dans la classe HtmlInputButtonTag : son nom doit être
identique à celui de l’attribut de balise. Il est également indispensable de créer l’accesseur en écriture correspondant,
et d’ajouter quelques lignes à la méthode setProperties pour que la valeur de la nouvelle propriété puisse être
transmise au composant associé au TagHandler.
Étant donné que l’attribut de balise valueChangeListener est susceptible de disposer d’une valeur correspondant à
une expression de méthode (par exemple #{ gestionnaireEvenements.changementValeur}), la nouvelle propriété du
TagHandler doit être de type javax.el.MethodExpression. Naturellement, l’accesseur en écriture correspondant doit
disposer d’un argument de même type :
La méthode setProperties doit, quant à elle, récupérer cet objet de type MethodExpression pour le convertir en une
instance de la classe MethodExpressionValueChangeListener. Cette classe, directement dérivée de
ValueChangeListener, permet en effet de créer des objets qui peuvent ensuite être ajoutés à la liste des
ValueChangeListener associés à un composant donné, par appel de la méthode addValueChangeListener de la classe
Voici le contenu d’une page JSP faisant usage des deux composants personnalisés de type HtmlInputButton et
HtmlHeureCourante2.
<f:view>
<h:form>
<composantPerso:composantInputButton
labelChampSaisie="Saisissez votre email: "
labelBoutonSoumission="Cliquez pour valider"
valueChangeListener="#{gestionnaireEvenements.changementValeur}"
/>
<br>
<composantPerso:heureCouranteAvecRenderer
id="nouveau"
label="Il est actuellement: " />
</h:form>
</f:view></body>
</html>
1. La classe Locale
a. Description
● L’argument language sert à indiquer le code ISO639 de la langue utilisée dans la région que l’on souhaite
représenter. Ce code est obligatoirement constitué de deux caractères alphabétiques écrits en minuscules.
Par exemple, le français est identifié par le code fr, alors que l’anglais l’est par la chaîne de caractères en.
Pour information, la totalité des codes correspondant aux langues peut être consultée sur le web à l’adresse
http://www.loc.gov/standards/iso6392/langhome.html
● L’argument variant, indissociable des deux autres, est introduit pour permettre aux éditeurs de logiciels de
préciser un code qui leur est spécifique (WIN pour Windows, MAC pour Macintosh, POSIX pour Posix).
Précisons enfin que la classe Locale fournit en standard un ensemble de propriétés statiques facilitant l’instanciation
d’objets Locale particuliers. Ainsi, la variable Locale.FRANCE permet d’obtenir simplement un objet Locale
représentant le français parlé en France.
b. Utilisation dans le cadre de la création d’applications web
La classe Locale est systématiquement exploitée dans le cadre des applications web basées sur le langage Java
(avec ou sans composants JSF). Dès qu’une session est ouverte sur un contexte d’application particulier, le langage
défini par défaut dans le navigateur web est recherché, puis utilisé pour instancier un objet Locale correspondant
aux habitudes linguistiques de l’internaute. Cet objet est stocké par la suite dans la session ellemême, afin de
pouvoir être exploité durant toute la visite du site.
Pour rappel, le langage par défaut utilisé par le navigateur se définit simplement par le biais des préférences.
Avec Internet Explorer, cette opération est réalisée depuis le menu Outils Options Internet et le bouton
Langues. La fenêtre qui se présente (voir illustration cidessous) indique le nom des langues définies, le pays où
Audelà de la simple application du langage prévu par défaut par le navigateur web, l’objet Locale placé dans la
session peut être manipulé par programmation. Cela permet au développeur, notamment, de proposer à l’internaute
de basculer d’une langue à une autre par l’utilisation de menus constitués précisément dans ce but. Ce cas de figure
particulier est étudié dans le détail, en guise d’illustration, dans la suite de ce chapitre.
2. La classe ResourceBundle et ses dérivées
a. Description
La classe ResourceBundle est une classe abstraite, rattachée au package java.util, dont les instances servent à
représenter un ensemble de ressources utilisées spécifiquement pour une langue et une région particulières. Les
ressources en question peuvent être de type quelconque, mais la plupart du temps, un ResourceBundle est exploité
pour regrouper des chaînes de caractères utilisées par la suite dans diverses interfaces graphiques. Globalement, on
peut dire que la notion de ResourceBundle se trouve au cœ ur des problématiques liées à la mise en œ uvre des
processus d’internationalisation. C’est elle en effet qui rend une application particulièrement adaptable à de
nombreux langages.
Création d’un ensemble de ressources
Un ResourceBundle se définit le plus souvent à l’aide d’un identifiant particulier, appelé nom de famille, et d’un objet
de type Locale représentant une langue utilisée dans une région particulière. Lorsque l’objet Locale n’est pas
précisé par le développeur de l’application, les paramètres locaux définis sur le poste de travail de l’utilisateur sont
pris en compte.
La classe ResourceBundle étant abstraite, son utilisation peut nécessiter la création de classes qui en dérivent et qui
précisent son comportement. Cependant, la classe fournit un jeu de trois méthodes statiques nommées getBundle,
dont l’utilisation permet d’instancier plus simplement un ResourceBundle particulier.
Déclaration des ressources d’un ResourceBundle
Comme indiqué précédemment, un ResourceBundle est défini par un identifiant, qui caractérise la famille à laquelle il
est rattaché. Pour être plus précis, une famille regroupe plusieurs ResourceBundle, qui diffèrent tous par la valeur de
l’objet Locale qu’ils portent. Par exemple, une famille nommée MesLabels peut rassembler deux ResourceBundle,
intitulés MesLabels_fr_FR et MesLabels_en_GB : le premier contient des éléments propres au français parlé en France,
alors que le second est composé d’éléments linguistiques propres à l’anglais utilisé au Royaume Uni.
Tous les ResourceBundle d’une même famille doivent impérativement posséder les mêmes éléments, mais la
traduction de ces éléments varie suivant la langue définie par l’objet Locale du ResourceBundle. Chaque élément est
caractérisé par une paire d’informations de type Clé/Valeur. Ainsi, la clé bouton1 d’un élément peut posséder la
valeur "Se connecter" pour dans un ResourceBundle correspondant au français. Le même élément se retrouve
obligatoirement dans un ResourceBundle propre à l’anglais : il est caractérisé par la même clé (bouton1), mais dont la
valeur correspond à la traduction anglaise du verbe "Se Connecter" (login).
Les deux principales techniques à mettre en œ uvre pour déclarer des ressources consistent à utiliser les deux
classes directement dérivées de ResourceBundle. Il s’agit des classes PropertyResourceBundle et
ListResourceBundle.
■ Faire une déclaration à l’aide d’un PropertyResourceBundle.
Un PropertyResourceBundle est un objet prenant en charge un fichier de type texte dans lequel sont déclarés les
différents éléments d’un ResourceBundle. L’exemple qui suit illustre le contenu d’un tel fichier, valable pour la langue
française : chaque ligne représente un élément particulier, composé de sa clé et de sa valeur.
Il va de soi que les valeurs de chacune des clés est obligatoirement de type String.
Il existe une convention de nommage à respecter pour que des fichiers texte puissent être exploités par un objet de
type PropertyResourceBundle : le nom du fichier doit comporter le nom de la famille de ressources, le code ISO de la
langue utilisée, auquel est éventuellement joint le code ISO de la région. Ces trois informations sont séparées les
unes des autres par le caractère underscore. Enfin, le nom d’un fichier texte exploité par un PropertyResourceBundle
doit posséder l’extension .properties. Ainsi, les éléments de ResourceBundle présentés cidessus peuvent être stockés
dans un fichier texte nommé MesLabels_fr_FR.properties. Un tel nom montre que les éléments sont membres de la
famille MesLabels, et concernent des expressions françaises utilisées en France. Les éléments de la même famille,
valables pour l’anglais parlé au Royaume Uni, doivent être déclarés dans un fichier texte nommé
MesLabels_en_GB.properties, dont le contenu peut être le suivant :
■ Faire une déclaration à l’aide d’un ListResourceBundle.
L’usage d’un PropertyResourceBundle peut s’avérer être intéressant, du simple fait de sa simplicité d’utilisation.
Cependant, les valeurs des différents éléments d’un ResourceBundle de ce type sont obligatoirement des chaînes de
caractères. Pour éliminer cette contrainte, en offrant la possibilité de définir des valeurs d’un type quelconque, il
convient de faire usage de la classe ListResourceBundle.
S’agissant d’une classe abstraite, il est nécessaire d’en constituer une classe dérivée dont le nom respecte la
convention de nommage expliquée précédemment pour les PropertyResourceBundle, et d’implémenter la méthode
getContents dont voici la signature :
Cette méthode doit renvoyer un tableau bidimensionnel, dont chaque élément est une paire d’instances issues de la
classe Object. En réalité, les éléments du tableau renvoyé doivent correspondre aux éléments du ResourceBundle : la
première dimension du tableau identifie la clé de l’élément du ResourceBundle et doit donc être de type String. La
seconde dimension représente la valeur de l’élément du ResourceBundle, qui peut effectivement être d’un type
quelconque.
Si l’on souhaite constituer le ResourceBundle nommé MesLabels_fr_FR grâce à un ListResourceBundle, il faut donc
package premierProjetJSF;
import java.awt.Button;
import java.util.ListResourceBundle;
L’implémentation de la méthode getContents réalise la déclaration de l’ensemble des éléments évoqués
précédemment pour ce ResourceBundle. Un nouvel élément a cependant été ajouté : il dispose de la clé nommée
bouton2 et possède une valeur de type java.awt.Button représentant un bouton d’interface basée sur la couche
graphique AWT.
b. Utilisation dans le cadre de la création d’applications web
De même que les applications web basées sur le langage Java exploitent toutes une instance particulière de la classe
Locale, cellesci peuvent rechercher si un ResourceBundle est disponible par défaut pour le Locale utilisé. Lorsque
celuici existe, il peut être stocké dans la session, de manière à rester disponible durant toute la visite du site par
l’internaute. La librairie standard de balises JSP prévoit par ailleurs la balise <fmt:setBundle> permettant de
surcharger le ResourceBundle par défaut, pour en proposer un autre, plus adapté aux attentes.
Dans le cadre des applications web exploitant des composants JSF, un ResourceBundle peut être instancié par l’usage
de la balise <f:loadBundle>, issue de la bibliothèque Core. Il est également possible de déclarer des ResourceBundle
au sein du fichier de configuration des ressources de l’application. Ce point particulier est abordé à la section
Déclaration de ResourceBundle associés aux fichiers de libellés de ce chapitre.
3. La classe NumberFormat
a. Description
La classe abstraite NumberFormat est fournie dans le package standard java.text. Elle permet d’obtenir un formatage
des nombres adapté à une langue et une région géographique particulière. Plusieurs méthodes statiques peuvent
être utilisées pour instancier des objets issus de cette classe abstraite. Parmi ces méthodes, les plus importantes
sont définies par les signatures suivantes :
Ces méthodes disposent d’un rôle spécifique suivant le type de données à formater : getCurrencyInstance fournit un
objet NumberFormat capable de s’occuper du formatage des nombres correspondant à des devises et monnaies ;
getPercentInstance en instancie un autre en mesure d’assurer le formatage des nombres exprimant des
pourcentages. Enfin, la méthode getInstance renvoie un objet NumberFormat prenant en charge les autres types de
données.
L’argument inLocale de type Locale, présent dans certaines des signatures de méthodes précédentes, sert à
indiquer la langue et la région par rapport auxquelles le formatage est demandé. Lorsque cet argument n’est pas
b. Utilisation dans le cadre des applications web
Le formatage des valeurs numériques selon les usages locaux est bien évidemment d’une importance capitale dans
les applications web, en particulier pour toutes celles concernées par le ecommerce.
Les deux balises <fmt:formatNumber> et <fmt:parseNumber>, issues de la bibliothèque standard JSTL fmt, peuvent
respectivement être utilisées dans les pages JSP pour formater et réaliser une analyse syntaxique de valeurs
numériques qui leur sont fournies en argument sous la forme d’une chaîne de caractères.
Avec la technologie Java Server Faces, le formatage des valeurs numériques se fait au travers de l’usage de
convertisseurs associés à des composants graphiques. Ces convertisseurs sont restitués par des balises
<f:convertNumber> dont l’attribut type permet de préciser si le formatage concerne des devises, des pourcentages ou
des nombres d’autres types.
4. La classe DateFormat
a. Description
La classe abstraite DateFormat, définie dans le package java.text, permet d’instancier des objets capables de
formater des informations liées à la date et aux horaires, conformément aux habitudes spécifiques d’une région
particulière. Ces objets peuvent s’obtenir en constituant des classes dérivées de DateFormat (la spécification en
définit une, nommée SimpleDateFormat). Il est également possible d’en instancier par invocation de méthodes
statiques disponibles dans la classe DateFormat. Voici les principales signatures de ces méthodes :
La méthode getDateInstance sert à obtenir objet DateFormat spécialisé dans le formatage de la date. Elle requiert
potentiellement la précision d’un paramètre style indiquant sous quelle forme la date en question doit être présentée
(courte, longue, ou intermédiaire). Il est également possible de mentionner le pays et la langue pour lesquels le
formatage est demandé, par l’utilisation d’un paramètre aLocale de type Locale. Si ce dernier paramètre n’est pas
fourni, les informations de localisation définies par défaut sur le poste de travail de l’utilisateur sont exploitées.
La méthode getDateTimeInstance permet de créer un objet DateFormat capable de formater simultanément la date et
l’heure. Elle nécessite la précision éventuelle de deux arguments, dateStyle et timeStyle, dont la valeur permet
d’indiquer sous quelle forme la date et l’heure doivent être présentées (courte, longue, ou intermédiaire). L’indication
de localisation peut se faire par l’intermédiaire de l’argument aLocale.
Enfin, la méthode getTimeInstance présente des arguments dont les noms et les rôles sont identiques à ceux décrits
pour la méthode getDateInstance. La seule spécificité de getTimeInstance réside dans le fait qu’elle assure le
formatage de l’heure uniquement.
b. Utilisation dans le cadre des applications web
Comme pour les objets de type ResourceBundle et NumberFormat, il est possible d’exploiter des instances de la classe
DateFormat depuis les pages JSP d’une application web. Cela peut se faire en utilisant certaines balises définies dans
la bibliothèque JSTL fmt : il s’agit des balises <fmt:formatDate> et <fmt:parseDate>. La première permet de réaliser le
formatage d’une date fournie en paramètre, alors que la seconde assure l’analyse syntaxique d’une chaîne de
caractères représentant une date.
La spécification JSF s’appuie, quant à elle, sur l’usage des convertisseurs pour réaliser le formatage des dates et des
Reportezvous au chapitre Exploitation des composants standards JSF de cet ouvrage pour obtenir de plus
amples renseignements concernant l’usage du convertisseur de type DateTimeConverter.
Cette section montre comment il est possible, sur un plan pratique, d’exploiter le mécanisme d’internationalisation : il
précise la méthode de déclaration de nouveaux ResourceBundle associés à des fichiers de libellés, et propose une
illustration de sélection dynamique du langage, selon les souhaits de l’internaute.
1. Définir plusieurs fichiers de libellés
La première étape du travail consiste à élaborer autant de fichiers de libellés que de langues à proposer aux
internautes. Ces fichiers doivent être placés préférentiellement dans le sousrépertoire src de l’application web. Chaque
ligne de ces fichiers contient une paire d’informations représentant la clé et la valeur d’un libellé ou d’un message
particulier. Les fichiers d’une même famille de ResourceBundle présentent tous les mêmes clés, mais les valeurs de
cellesci diffèrent bien sûr selon la langue. Il est naturellement possible de mettre en place plusieurs familles de
ResourceBundle dans une même application web.
Tous les fichiers de libellés ou de messages doivent respecter la convention de nommage requise. À défaut, ils ne
pourront pas être pris en charge par l’application web. Leur nom doit donc être composé de l’identifiant de la famille, de
celui de la langue, et éventuellement de celui de la région. Ils doivent en outre disposer de l’extension .properties.
Des exemples de contenu de fichiers de libellés sont présentés dans les sections précédentes de ce chapitre.
2. Utilisation de la langue définie par défaut dans le navigateur
L’image suivante montre le contenu de la vue d’exploration de projets d’Eclipse, pour une application web spécifique :
Plusieurs familles de ResourceBundle y sont définies. L’une d’elles, nommée portail, permet la prise en charge de l’anglais
parlé au Royaume Uni et du français parlé en France. De fait, tous les navigateurs pour lesquels le langage par défaut
correspond à l’une de ces langues seront en mesure de proposer à l’internaute des libellés qui lui sont adaptés.
Qu’en estil pour les autres situations, dans lesquelles le navigateur n’est pas configuré pour exploiter les langues
proposées par l’application web ? Il s’agit en effet d’une situation courante, dans la mesure où le concepteur du site est
dans l’impossibilité de définir autant de fichiers de libellés qu’il n’y a de dialectes dans le monde. La réponse à cette
problématique consiste à créer un fichier de libellés par défaut pour chaque famille de ResourceBundle. Le nom de ce
fichier par défaut est uniquement composé du nom de la famille et de l’extension .properties. L’illustration précédente
montre que le fichier de libellés par défaut de la famille portail est effectivement prévu : son nom est portail.properties.
3. Permettre l’exploitation de ces fichiers dans l’application web
a. Les dialectes supportés
Après avoir affiché le fichier de configuration des ressources dans la zone d’édition de l’environnement Eclipse, la
Les changements sont naturellement visibles dans l’onglet Source présentant le code source du fichier de
configuration des ressources. Les dialectes sont définis par le biais d’une balise <locale-config>, sousélément de la
balise <application>. Le dialecte par défaut est mentionné par la valeur d’un élément <default-locale>, alors que
chaque dialecte supplémentaire est défini par une balise <supported-locale>.
<faces-config>
<application>
<locale-config><default-locale>fr_FR</default-locale>
<supported-locale>en_GB</supported-locale>
<supported-locale>de_DE</supported-locale>
</locale-config>
</application>
...
</faces-config>
b. Déclaration de ResourceBundle associés aux fichiers de libellés
Deux moyens sont proposés pour déclarer et utiliser de nouveaux ResourceBundle associés à des fichiers de libellés :
la déclaration au sein des pages web, et la déclaration en tant que nouvelles ressources de l’application web.
Déclaration au sein des pages web
Dans cette situation, les ResourceBundle sont instanciés directement dans les pages web par le bais d’une balise
<f:loadBundle> : ils disposent alors d’une portée de type request. Si un tel mode d’utilisation peut convenir dans le
cadre d’applications web limitées, il présente une contrainte importante pour les applications plus lourdes, dans la
mesure où la balise <f:loadBundle> doit être systématiquement répétée dans l’ensemble des pages web qui exploite
un ResourceBundle particulier.
Le code source suivant illustre la déclaration et l’utilisation d’un ResourceBundle au sein d’une page JSP représentant
un formulaire d’authentification :
<f:view>
<f:loadBundle
basename="premierProjetJSF.messages"
var="mesMessagesPerso"/>
<h:form>
<h:panelGrid border="1" columns="3">
La balise <f:loadBundle> présente un attribut basename permettant de préciser le nom de famille du ResourceBundle à
instancier. Quant à l’attribut var de la même balise, il sert à attribuer un identifiant à ce ResourceBundle, pour le rendre
disponible dans le reste de la page web.
Les étiquettes associées aux deux champs de saisie et au bouton de soumission sont récupérées dans le fichier de
libellés correspondant au ResourceBundle nommé mesMessagesPerso, pour la langue et la région définies par défaut
dans le navigateur web. Le fichier en question possède au moins trois éléments dont les clés sont nommées
clientcode, password et login. Voici un contenu possible pour ce fichier, ainsi qu’une illustration du résultat obtenu
lors de l’exécution de la page :
name=Nom
password=Mot de passe
clientcode=Code client
welcome=Bienvenue!
submit=Validez
login=Se connecter
Déclaration en tant que nouvelle ressource de l’application
Par ce second moyen, les ResourceBundle associés aux fichiers de libellés disposent d’une portée plus importante
(session, application) : ils peuvent alors être utilisés dans la totalité des pages web de l’application par l’intermédiaire
d’un identifiant unique, sans qu’il soit nécessaire d’avoir recours à la balise <f:loadBundle>.
Lorsque le fichier de configuration des ressources est présenté dans la zone d’édition, on constate qu’il n’existe pas
de formulaire permettant de déclarer spécifiquement de nouveaux ResourceBundle : il est donc nécessaire de modifier
directement le code source du fichier facesconfig.xml pour y ajouter les balises indispensables à ce type de
déclaration. Un ResourceBundle se caractérise par deux informations : son nom de famille et son identifiant unique.
<faces-config>
<application>
<resource-bundle><base-name>premierProjetJSF.portail</base-name>
<var>portail_web</var>
</resource-bundle>
...
</application>
...
Comme présenté dans le code cidessus, un ResourceBundle se déclare à l’aide d’une balise <resource-bundle>
présentant deux souséléments <base-name> et <var> : le premier permet de mentionner le nom de famille du
ResourceBundle, alors que le second sert à indiquer l’identifiant unique de cet objet. Dans l’exemple proposé, le nom
de famille est portail : il correspond à des fichiers de libellés situés dans le sousrépertoire src/premierProjetJSF de
l’application web. L’identifiant portail_web pourra être utilisé dans les pages web de l’application pour faire référence à
ce ResourceBundle particulier.
4. Permettre à l’utilisateur de sélectionner dynamiquement un langage
Une application intéressante de l’internationalisation consiste à permettre à l’internaute de sélectionner
dynamiquement la langue dans la laquelle il souhaite visualiser les informations proposées par l’application web. Voyons
comment obtenir un tel résultat, au travers d’un exemple simple.
La démarche à suivre peut être la suivante :
● Écrire le contenu des fichiers de libellés pour chacune des langues supportées par l’application.
● Construire une page JSP chargée d’afficher les informations et présentant un ou plusieurs composants JSF
permettant de choisir la langue à utiliser.
● Développer un bean managé dont l’une des méthodes est chargée de modifier dynamiquement la langue à
utiliser dans le contexte de l’application web.
a. Contenu des fichiers de libellés
Cet aspect du travail ne pose aucun problème. La section Mécanismes mis en œ uvre dans le cadre du multilinguisme
La classe ResourceBundle et ses dérivées de ce chapitre présente les contenus de deux fichiers nommés
MesLabels_fr_FR.properties et MesLabels_en_GB.properties : ceuxci sont parfaitement adaptés au cas de figure à
développer ici.
b. Construire la page JSP
Voici un exemple de page web contenant des composants JSF faisant référence à un RessourceBundle nommé
portailWeb, déclaré dans le fichier de configuration des ressources de l’application.
<f:view>
<h:form>
<h:outputText value="#{portailWeb.titre1}">
</h:outputText><br>
<h:commandButton
value="#{portailWeb.francais1}"
id="fr_FR"
actionListener="#{beanInternationalisation.choixLangue}">
</h:commandButton>
<h:commandButton
value="#{portailWeb.anglais1}"id="en_GB"actionListener="#{beanInternationalisation.choixLangue}">
</h:commandButton>
</h:form>
</f:view>
Cette page comporte un champ de type HtmlOutputText dont la valeur correspond à la clé titre1 d’un élément de
Deux points importants sont à noter à propos de ces boutons : tout d’abord, les balises qui les représentent
possèdent un attribut id dont la valeur identifie une langue et une région particulières, selon la codification ISO. De
plus, ces balises présentent également un attribut actionListener, dont la valeur référence la méthode choixLangue
d’un bean managé nommé beanInternationalisation : cette méthode est donc invoquée lors d’un clic sur les boutons.
Celleci a pour but de modifier le langage utilisé pour l’affichage des informations.
c. Définir une classe contenant une méthode chargée de modifier le langage par défaut
La dernière étape de la démarche consiste précisément à développer le bean managé contenant la méthode
choixLangue. Cette méthode doit naturellement accepter un objet de type ActionEvent en argument afin de pouvoir
prendre en charge le clic sur des composants de type HtmlCommandButton.
package premierProjetJSF;
import java.util.Locale;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);
}
}
Ces instructions illustrent la création d’une instance de la classe Locale à partir de l’identifiant du composant JSF à
l’origine du clic. Cette instance est finalement utilisée pour mettre à jour la localisation dans l’application web.
À l’exécution, on constate bien un basculement entre les deux langues (anglais et français) par l’utilisation du bouton
adapté.
Les sections Conversion des valeurs numériques et Conversion de la date et de l’heure du titre Exploitation des
convertisseurs standards du chapitre Exploitation des composants standards JSF de cet ouvrage présentent dans le
détail le mode de fonctionnement de ces convertisseurs, et proposent des exemples pouvant tenir lieu d’illustrations
dans le cadre de l’internationalisation. Le lecteur intéressé par cette thématique peut donc se référer à ces sections
pour obtenir les renseignements qu’il recherche.