JavaServer Faces - techniques avancées
Chapitres traités Cycle de traitement des requêtes JSF
Cette étude fait suite à l'étude précédente qui nous a permis de prendre connaissance de JSF. Cette connaissance est un pré-requis
indispensable aux sujets que nous allons aborder tout au long de cette nouvelle étude. Il est évident que les notions que nous venons
d'apprendre sont insuffisantes pour développer une application de gestion complète. Effectivement, nous devons appréhender un
certains nombre de critères qui vont nous permettre d'aboutir à une démarche de qualité. Nous devons aborder les points suivants :
1. Nous devons maîtriser la structure et le mécanisme interne d'un système élaboré par JSF. Il est en effet important de connaître l'enchaînement des opérations qui
conduisent au résultat final lorsqu'une issue du requête est proposée.
2. Lors de la saisie de données par l'utilisateur, il est souvent indispensable de valider et ou de convertir les valeurs saisies avant de les injecter dans un JavaBean.
Des messages adaptés peuvent alors survenir si les saisies sont incorrectes.
3. Dans certaines situations, il est souhaitable de prendre en compte une gestion fine des événements afin que l'application Web soit suffisamment réactive au
comportement de l'utilisateur.
4. Dans le cas de développements importants, il également utile de créer des composants réutilisables pour augmenter la productivité et faciliter la maintenance.
(Cette partie n'est pas traitée).
Cycle de traitement des requêtes JSF
Toutes les requêtes JSF suivent le même cycle de traitement, constitué de six étapes distinctes. Les lignes pleines décrivent le cycle normal et les lignes en pointillé rouge
le traitement des erreurs.
1. Création de l'arborescence des composants : À la réception de la requête, la hiérarchie des composants (arbre de vue) de la page demandée est créée.
2. Récupération des valeurs de la requête : Les valeurs de la requête sont récupérées et stockées dans les composants de l'arbre de vue. La servlet contrôleur
FacesServlet, non représentée ici, parcourt l'arbre de vue et appelle la méthode decode() de chacun de ses composants. Ensuite, les événements et les validators
sont générés et stockés dans le contexte JSF.
3. Traitement des validations : La méthode validate() est appelée pour tous les validators stockés dans l'arbre de vue créé à l'étape précédente.
4. Modification des valeurs du modèle objet : Les valeurs contenues dans les composants sont ensuite recopiées dans les objets métiers (JavaBeans)
éventuellement associés.
5. Appel de l'événement application : L'événement de type <f:form> ou <h:command...> correspondant à la demande d'une nouvelle page est traitée.
6. Rendu de la réponse : La hiérarchie de composants s'occupe de créer toutes les balises standard nécessaires pour représenter la réponse au format désiré.
Phase 1 - Création de l'arborescence des composants côté serveur (arbre de vue)
Une page HTML est un fichier texte qui contient un assemblage de balises spécialisées pour le formattage de l'information. Par contre JSF utilise, côté serveur, un arbre
d'objets pour représenter la vue équivalente de cette page Web. Il s'agit là d'une structure bien différente d'un fichier texte. Cet arbre d'objets est un mirroir (un
représentant) de l'interface visuelle du client.
Cette phase va donc consister à reconstituer l'arbre de composants qui correspond à la vue HTML de l'utilisateur qui soumet la requête. Cette arbre se nomme :
arbre de vue.
Lorsque le client soumet la requête pour la première fois, JSF doit créer la vue correspondante au travers de cet arbre d'objets. A chaque balise de type <h:...>
correspond un objet Interface Utilisateur équivalent qui va donc être placé sur l'arbre à une branche qui correspond à l'imbrication des balises proposées sur la
page Web. Chaque objet est donc stocké dans cet arbre à l'endroit convenable.
La racine de cet arbre de vue est systématiquement une instance de la classe UIViewRoot qui correspond en réalité à la balise <f:view>. Nous remarquons au
passage que le placement de cette balise dans une page JSP devient prépondérante afin de permettre l'élaboration de cet arbre de vue.
Cet arbre d'objets, qui est une image de la vue té client, se créer automatiquement. Je veux dire que c'est le serveur qui s'en occupe sans aucune intervention de
notre part.
Indépendamment de cet arbre, ces objets sont bien entendus issus d'un ensemble de classes qui respecte la hiérarchie suivante :
Toutes les classes ne sont pas représentées. Nous pouvons, à l'intérieur des Javabeans, travailler directement avec les classes correspondantes aux balises
présentes sur la page Web, celles qui sont représentés en bleu. Toutefois, il est possible de travailler plutôt avec une des classes parentes, représentée en jaune. En
effet, ces classes disposent jà de certaines propriétés correspondantes aux attributs proposés par les balises équivalentes. Ainsi, par exemple, à partir de la balise
suivante :
<h:outputText value="Un texte"/>
Vous pouvez créer un objet de type UIOutput qui dispose de la propriété équivalente à cet attribut value. Ainsi, vous pouvez solliciter les méthodes getValue() et
setValue() qui travaillent donc en tâche de fond sur l'attribut value (de type Object) de la classe UIOutput.
Que se passe-t-il lorsque le client propose la requête la première fois, ou lorsqu'il la propose de nouveau au serveur ?
1. Si la vue est demandée pour la première fois, le serveur d'application crée une instance de UIViewRoot et lui associe un nom, souvent le me nom que la page
JSP. JSF mémorise alors l'arbre de vue.
2. Si la vue existe déjà pour JSF, alors l'arbre de composants correspondant devient la vue courante. Dans ce cas , la méthode restoreState() de la classe ancêtre
UIComponent est appelée récursivement de façon polymorphique sur chacun des composants constituant l'arbre de vue. Ainsi, elle rétablit l'état du composant à
partir de l'état sauvegardé durant la dernière phase appelée Rendu de la ponse (voir plus loin).
Lorsque JSF a déterminé la vue courante, celle-ci est accessible via la classe FacesContext.
.
Phase 2 - Récupération des valeurs de la requête
Lorsque la phase précédente est terminée, nous disposons d'un arbre de composants dont la racine est UIViewRoot. La requête HTTP soumise par le navigateur est
porteuse des actions de l'utilisateur sur la vue. Ceci implique qu'il faut synchroniser la vue côté JSF avec la vue côté client. En effet, si l'utilisateur modifie une valeur dans
un champs de formulaire, il faut que le composant graphique correspondant côté serveur reflète ce changement d'état.
Le but de cette phase est donc de récpercuter les actions de l'utilisateur sur l'arbre de composants courant (arbre de vue courant). Il faut décoder les valeurs
contenues dans l'objet HttpServletRequest (nous connaissons particulièrement bien cet objet depuis que nous manipulons les servlets) et récupérer les
changement d'états de la vue sur les composants concernés.
A cet effet, la classe UIComponent qui est la classe ancêtre de tout composant JSF dispose de la méthode processDecodes(). Cette méthode est appelée
récursivement sur chaque composant de l'arbre. Par polymorphisme, les composants ont la responsabilité de décoder les informations qui les concernent.
Ainsi, chaque information envoyée lors de la requête est associée à l'objet correspondant dans l'arbre de vue. Plus précisément, les attributs de cet objet sont remis
à jour par les nouvelles valeurs envoyées. Ainsi, si nous avons par exemple té client cette ligne là :
<h:inputText value="5"/>
vous retrouver alors cette valeur 5sur l'objet HtmlInputText correspondant qui est mis à jour par la propriété équivalente value, et ceci par l'intermédiaire de la
méthode setValue().
Phase 3 - Traitement des validations
Certaines balises JSF sont parfois liés à des JavaBeans au moyen des expressions EL JSF. Les JavaBeans représentent la logique métier. Il est alors impératif de valider et
ou de convertir les valeurs qui proviennent du client avant de les injecter dans le JavaBean correspondant. En effet, par exemple, si l'utilisateur saisie la chaîne suivante
"345red" en lieu et place d'un nombre entier (valeur attendue), alors cela provoquera une erreur.
Vous allez le découvrir dans les chapitres qui suivent, JSF offre les concepts de validation (Validator) et de conversion (Converter) pour effectuer les traitements sur
les valeurs soumises par l'utilisateur avant leurs injections dans les JavaBeans.
Un composant peut donc éventuellement posséder des Validator et un Converter qui sont invoqués lors de l'appel de la méthode processValidators() de la classe
ancêtre UIComponent. Cette méthode est appelée récursivement sur l'arbre de vue. JSF procède d'abord à la conversion de la valeur extraite de la requête HTTP
(String) puis valide cette valeur en utilisant les Validator.
Si une erreur survient durant cette phase, à cause d'un problème de validation, alors JSF arrête le processus normal et saute directement vers la dernière phase qui
correspond au rendu de la réponse.
Phase 4 - Modification (Mise à jour) des valeurs du modèle objet
Lorsque la requête arrive à cette phase de traitement, les objets sont dans un état qui correspond à la vue du client. Les informations de la requête HTTP qui sont destinées
à mettre à jour les données métiers ont été validées. La méthode processUpdates() de UIComponent est appelée récursivement sur l'arbre des composants. Sa
responsabilité consiste à mettre à jour, cette fois-ci, les Javabeans correspondant à la logique métier.
Egalement durant cette phase, si une erreur survient, alors JSF arrête le processus normal et saute directement à la phase du rendu de la réponse.
.
Vous allez le découvrir dans les chapitres qui suivent, JSF offre un modèle événementiel qui permet de détecter les changements du modèle. A ce niveau, l'appel de
la méthode processUpdates() peut donc éventuellement poster des événements.
Phase 5 - Appel de l'événement application
Lorsque cette phase est atteinte, le modèle métier est mis à jour, des événements sont en attentes dans la queue des événements. Ces événements sont de deux natures.
Soit ils sont issus, de façon classique de l'attribut action des balises <h:commandButton> ou <h:commandLink>. Soit ils sont plutôt issus de l'attribut actionListener qui
met donc en oeuvre un système d'écouteur supplémentaire (ActionListener). -- peut-être à revoir --
La méthode processApplication() de UIComponent est appelée récursivement sur l'arbre de vue. Sa responsabilité consiste à diffuser (Broadcast) certains
événements de la queue vers les écouteurs d'événements associés (listeners).
Phase 6 - Rendu de la réponse
C'est la dernière phase du traitement d'une requête JSF. Sa première responsabilité consiste à encoder l'arbre de vue courant dans un langage compréhensible par le client,
ici le HTML. JSF peut encoder le HTML, le WML, le XML, etc. Ici donc, nous partons de l'arbre de vue et chaque objet s'occupe de créer la balise correspondante dans le
format standard requis.
Pour ce faire, le UIComponent dispose d'un jeu de méthodes dont la signature commence par encodeXXX(). ces méthodes sont particulièrement adaptées à
l'encodage dans des langages à balises. Ces méthodes sont au nombre de trois :
1. encodeBegin(),
2. encodeChildren(),
3. encodeEnd().
Ces méthodes correspondent grossièrement aux étapes d'encodage d'une balise : balise ouvrante, balises filles, balise fermante (sujet traité ultérieurement).
.
Sa deuxième responsabilité consiste à sauvegarder l'état des objets de l'arbre de vue. Pour ce faire une deuxième méthode saveState() est également appelée
récursivement. Cette thode répond à la méthode restoreState() que nous avons découvert durant la première phase Création de l'arbre de vue. Ce comportement
est donné par l'interface StateHolder implémentée par UIComponent.
Classes JSF utiles pour le développement côté JavaBean
Lorsque nous developpions des JavaBeans avec les pages JSP sans tenir compte de la technologie JSF, il était très difficile d'être directement en interaction avec les
éléments constituant la page JSP et tout ce qui concernait l'application Web dans son ensemble. Nous étions souvent obligés de passer par des servlets. Une autre
solution était de faire en sorte que la page JSP passe tous les renseignements requis avec des propriétés supplémentaires dans le JavaBean concerné. ce qui alourdissait
considérablement le code.
Dans le cas de JSF, les JavaBeans peuvent récupérer directement tous les renseignements nécessaires pour mettre en oeuvre les traitements désirés. C'est un des
très gros avantage de cette technologie. Nous allons recenser ici, sans toutefois être pleinement exhaustif, les classes qui peuvent nous aider dans notre démarche.
Le but de ce chapitre est juste de présenter ces classes sans s'attarder sur les détails d'implémentation. Dans les chapitres suivant, nous développerons des sujets
qui interagiront avec ces classes et nous démontrerons l'intérêt de les utiliser.
Hiérarchie des composants Interface Utilisateur
Nous l'avons déjà découvert dans le chapitre précédent, JSF intègre une hiérarchie de composants qui représente l'interface utilisateur côté client. Ces composants sont
issus du paquetage javax.faces.component.
Toutes les classes ne sont pas représentées. Nous pouvons, à l'intérieur des Javabeans, travailler directement avec les classes correspondantes aux balises
présentes sur la page Web, celles qui sont représentés en bleu. Toutefois, il est possible de travailler plutôt avec une des classes parentes, représentée en jaune. En
effet, ces classes disposent jà de certaines propriétés correspondantes aux attributs proposés par les balises équivalentes. Ainsi, par exemple, à partir de la balise
suivante :
<h:outputText value="Un texte"/>
Vous pouvez créer un objet de type UIOutput qui dispose de la propriété équivalente à cet attribut value. Ainsi, vous pouvez solliciter les méthodes getValue() et
setValue() qui travaillent donc en tâche de fond sur l'attribut value (de type Object) de la classe UIOutput.
Présentation de tableaux dynamiques
A titre d'exemple, nous pouvons consulter quelques méthodes intéressantes de la classe UIData qui représente la balise <h:dataTable> par l'intermédiaire de
HtmlTableData, et qui peuvent s'avérer bien utiles dans bien des cas. Effectivement, nous avons souvent besoin de cette balise lors de la mise en valeur d'un
ensemble d'éléments.
javax.faces.component.UIData
Méthodes Retour Explication
getRowCount() int Retourne le nombre de lignes total que comporte l'ensemble du tableau de données ou alors -1 si le tableau est inconnu.
getRows() int Retourne le nombre de lignes qui peut être affiché dans la page, ou 0pour toutes les lignes restantes dans la table. Le nombre de
lignes que nous pouvons afficher est déterminé par la méthode setRows() ci-dessous.
getRowsIndex() int Retourne la valeur de l'index de la ligne courante.
getFirst() int Retourne la valeur de l'index de la première ligne qui peut être affichée.
getRowData() Object Retourne la valeur de la donnée de la ligne courante.
setRowIndex(int index)void Sélectionne la ligne que nous désirons consulter.
setFirst(int index)void Sélectionne la première ligne qui peut être affichée.
setRows(int lignes)void Sélectionne le nombre de lignes à afficher.
Récupérer le contexte de la page courante - FacesContext
C'est certainement la classe la plus importante. Elle est issue du paquetage javax.faces.context. Cette classe nous permet d'être en relation avec la page JSP courante qui
communique avec notre JavaBean. L'objet relatif de cette classe FacesContext représente donc la page JSF, et la plupart du temps, nous passerons par cet objet pour
consulter d'autres objets d'une autre nature qui auront un comportement spécifique sur la page.
Voici la démarche à suivre pour récupérer l'objet représentant la page JSP courante :
FacesContext contexte = FacesContext.getCurrentInstance();
Ici, l'objet contexte représente donc la page Web qui est en communication avec notre JavaBean. Nous pouvons, dès lors l'utiliser pour effectuer un certain
nombre d'opérations intéressantes par l'intermédiaire de méthodes adaptées à la situation. Voici juste quelques unes de ses méthodes.
javax.faces.context.FacesContext
Méthodes Retour Explication
getCourentInstance() FacesContext Retourne le contexte courant, c'est-à-dire, la page JSP qui sert de conteneur.
addMessage(String client,
FacesMessage message)void Permet d'envoyer un message d'alerte ou d'erreur directement sur le composant client qui a provoqué l'erreur.
getApplication() Application Retourne l'objet représentant l'ensemble de l'application Web. Nous connaissons déjà cet objet que nous avons appris à
connaître lors de l'étude sur les pages JSP.
getExternalContext() ExternalContext Retourne un objet relatif à tous les éléments externes à la page courante. Cet objet est d'une grande utilitée. Il permet
de récupérer toutes les informations issues de la requête, donc d'être en relation avec l'objet request que nous avons
déjà utilisé avec les servlets. Nous pouvons également connaître l'objet response, l'objet session, etc.
Il existe bien d'autres méthodes comme getViewRoot() ou getRenderResponse() nous voyons bien à quoi elles correspondent. Mais, elles sont généralement d'un
intérêt plutôt limité.
Ajout de messages sur l'interface utilisateur du client - FacesMessage
Nous pouvons afficher des messages d'alerte sur nos pages JSP par l'intermédiaire de balises adaptées <h:messages> ou <h:message>. Ces alertes apparaissent dans le
cas, par exemple, d'une mauvaise saisie. Nous en avons déjà donné un petit aperçu dans l'étude précédente. L'intérêt de ces messages, c'est qu'ils n'apparaissent qu'en
cas de problème. Ces messages sont implémentés par la classe javax.faces.application.FacesMessage. Dans la suite de cette étude, nous consacrerons tout un chapitre
entier à la gestion de ces messages.
Voici pour l'instant comment nous pouvons créer un message :
FacesContext contexte = FacesContext.getCurrentInstance();
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Attention", "Entier attendu");
contexte.addMessage("saisie", message);
javax.faces.application.FacesMessage
Méthodes Retour Explication
SEVERITY_ERROR FacesMessage.Severity Indique qu'une erreur est survenue.
SEVERITY_FATAL FacesMessage.Severity Indique qu'une erreur fatale est survenue.
SEVERITY_INFO FacesMessage.Severity Juste un message d'information.
SEVERITY_WARN FacesMessage.Severity Message qui réclame une attention particulière.
FacesMessage() Construit un message sans valeurs initiales.
setSeverity(FacesMessage.Severitysévérité)void Précise le type de message.
setSummary(String erreurSommaire)void Donne le message mais de façon sommaire.
setDetail(String détailErreur) void Indique précisément le type d'erreur.
FacesMessage(String erreurSommaire) Construit un message sommaire.
FacesMessage(FacesMessage.Severity
sévérité,String sommaire,String détail) Construit un message complet avec le type d'erreur adapté. Certainement le constructeur le plus
utilisé.
Application Web - Application
La classe javax.faces.application.Application permet de gérer des éléments qui sont placés dans l'application Web. Depuis n'importe quelle page, il est alors possible de
créer de nouveaux éléments. Par la suite, une autre page peut ensuite consulter ces nouvelles informations. Nous pouvons par exemple créer de nouveaux types de
convertisseur, de nouveaux types de validateur, gérer l'internationalisation.
Voici comment obtenir ce type d'info :
FacesContext contexte = FacesContext.getCurrentInstance();
Application externe = contexte.getApplication();
javax.faces.application.Application
Méthodes Retour Explication
getRessourceBundle(FacesContext ctx,
String nom)RessourceBundle Récupère la ressource qui gère l'internationalisation spécifiée en argument.
Contexte de l'application Web - ExternalContext
La classe javax.faces.context.ExternalContext permet d'être en relation avec tous les éléments qui sont en relation avec notre page Web. Ainsi, il est possible de connaître
tout ce qui concerne la requête, la réponse, la session en cours, etc.
Voici comment obtenir ce type d'info :
FacesContext contexte = FacesContext.getCurrentInstance();
ExternalContext externe = contexte.getExternalContext();
javax.faces.context.ExternalContext
Méthodes Retour Explication
getApplicationMap() Map Retourne les objets (les attributs) stockés dans l'application Web.
getInitParameter(String paramètre)String Retourne le paramètre initialisé dans le contexte de l'application Web spécifié par le descripteur de déploiement.
getInitParameterMap() Map Délivre l'ensemble des paramètres d'initialisation de l'application Web.
getRemoteUser() String Procure le nom de loggin de l'utilisateur fabriqué dans la requête courante.
getRequestCookieMap() Map cupère l'ensemble des cookies de la requête.
getRequest() Object Récupère l'objet request que nous connaissons bien.
getRequestContextPath() String Retourne la portion d'URL qui correspond à l'emplacement de l'application Web.
getRequestHeaderMap() Map Retourne l'ensemble de l'en-tête de la requête.
getRequestHeaderValuesMap() Map Retourne l'ensemble de l'en-tête de la requête. Les valeurs sont cette fois-ci sous forme de tableaux de chaînes pour
certains éléments d'en-tête.
getRequestMap() Map Retourne les attributs de l'application courante.
getRequestParameterMap() Map Retourne les paramètres de la requête.
getRequestParameterNames() Iterator Retourne les paramètres de la requête en passant par un itérateur.
getRequestParameterValuesMap() Map Retourne les paramètres de la requête en prenant en compte plutôt les tableaux de chaînes.
getRequestPathInfo() String Retourne uniquement la portion de l'URL qui suit le nom de l'application Web.
getRessource(String chemin)URL Permet de récupérer l'URL d'une ressource.
1 / 58 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !