Cours Framework JSF perfectionnement
EMSI - Université de Nice Sophia Antipolis Richard Grin Version O 2.25 – 4/11/18 | Plan de ce cours ? Présentation de JSF ? Architecture des applications JSF ? Exemple de page JSF ? Backing bean et portée CDI ? Cycle de vie ? Fichiers de configuration ? Navigation ? PRG ? Messages d’erreur ou d’information R. Grin JSF | ? ? ? ? | Événements Ajax JSF et HTML5 Ressources page 2 | |||||
| Présentation de JSF R. Grin JSF page 3 | JSF ? Framework Java pour le développement d’applications Web ? Une page HTML vue par le client Web est représentée sur le serveur par des composants Java ? Ces composants Java sont décrits dans une page JSF (fichier au format XML) R. Grin JSF page 4 | |||||||
| ||||||||
Exemple - page JSF form.xhtml
Espace de noms
<?xml version="1.0" encoding="UTF-8"?>
par défaut
<!DOCTYPE html>
<html xmlns="; Espace de xmlns:h=";> noms JSF
<h:head> <title>Présentation</title> </h:head>
<h:body>
<h3>Présentation</h3>
<h:form>
Nom : <h:inputText value="#{}"/>
<h:commandButton value="Enregistrer" action="#{utilisateur.direHello()}"/>
</h:form>
</h:body>
Vous devinez comment cette page sera utilisée ?
</html>
R. Grin JSF page 7
Exemple - page JSF form.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="; xmlns:h=";>
<h:head> <title>Présentation</title> </h:head>
<h:body> utilisateur : Propriété nom
<h3>Présentation</h3> nom backing bean du backing bean
<h:form>
Nom : <h:inputText value="#{}"/> Formu <h:commandButton value="Enregistrer" laire action="#{utilisateur.direHello()}"/>
</h:form> Bouton soumet formulaire
</h:body> par requête POST envoyée Méthode direHello
</html> au serveur du backing bean
R. Grin JSF page 8
| Principaux services rendus par JSF ? Conversion entre le texte de l’interface utilisateur et les valeurs Java du serveur ? Validation des données saisies par l’utilisateur ? Automatisation de l’affichage des messages d’erreur si problèmes de conversion ou validation ? Internationalisation ? Support d’Ajax sans programmation ? Templates graphiques ? Librairies de composants R. Grin JSF page 13 | Les traitements ? Séparation très nette entre ? les pages JSF ? les traitements à exécuter ? Même les traitements directement liés à l’interface utilisateur sont effectués en dehors de la page JSF, par du code Java (backing bean) R. Grin JSF page 14 |
Code d’un backing bean
? Propriétés pour valeurs à afficher ou saisies par l’utilisateur :
<h:inputText value="#{}"/> setter et getter utilisés en interne
| Architecture des applications JSF R. Grin JSF page 15 | Répartition des tâches ? Pages JSF pour l’interface avec l’utilisateur ; ne contiennent aucun traitement ? Backing beans pour les traitements liés directement à l’interface utilisateur ? Backing beans font appel à des EJB ou POJO pour les autres traitements (traitements métier, accès aux sources de données,…) ? Accès aux bases de données utilisent souvent JPA et donc les classes entités R. Grin JSF page 16 |
? Traitements lancés par l’utilisateur, par un clic bouton par exemple :
<h:commandButton value="Enregistrer" action="#{utilisateur.direHello()}"/>
? Expression qui indique si un composant doit être affiché :
<h:inputText value="#{bean.client.pourcentageRemise}" rendered="#{bean.client.bonClient}" />
page 18
| Servlet « Faces » ? Le servlet JSF gère le cycle de vie JSF, fondamental pour JSF ? Ce servlet est fourni par JSF et caché au développeur ? Un mapping indique les requêtes qui seront traitées par ce servlet ; par défaut celles avec les URLs /faces/*, *.jsf, *.faces , *.xhtml, qui correspondent toujours à un fichier *.xhtml (par exemple correspond à page.xhtml) R. Grin JSF page 19 |
Template
? Les pages d’un site Web respectent souvent une charte graphique
? L’aspect commun aux pages est défini dans un fichier XHTML à part, appelé template
| Convertisseurs et validateurs ? Les convertisseurs peuvent être fournis ? par JSF (convertisseur standard) ? par une classe (balise <f:converter> ou attribut converter) ? par une propriété d’un backing bean (attribut converter) ? par un convertisseur par défaut pour un type ? Les validateurs peuvent être fournis ? par JSF ? par une classe (balise <f:validator>) ? par une méthode (attribut validator) page 23 |
| Template avec 2 parties variables <ui:insert>, titre et contenu R. Grin | Conversion et validation ? Les données saisies dans les formulaires HTML sont des chaînes de caractères ? Il faut les convertir dans le bon type Java (celui de la propriété du backing bean) : <h:inputText id="age" value="#{}" > ? Elles doivent être validées (18 < age < 70 par exemple) avant d’exécuter les traitements qui les utilisent R. Grin JSF page 22 |
? Un template contient des parties « variables » : <ui:insert name="header"/>
? Une page JSF qui utilise ce template (page cliente du template) a l’aspect défini par le template ; elle définit les parties variables :
<ui:define name="header"> </ui:define>
R. Grin JSF page 20
Exemple de convertisseur donné par une propriété du backing bean
@EJB Qui peut expliquer ? private DiscountFacadeEjb ejb;
public Converter<Discount> getDiscountConverter() {
return new Converter<Discount>() {
| Exemple plus complet de page JSF page 29 |
| Validation des beans ? Les champs d’une classe (backing bean ou entité JPA) peuvent être annotés pour définir une contrainte à respecter : @Min(18) @Max(70) private int age; R. Grin JSF | page 27 | Composants des pages JSF ? Nombreux composants standards qui correspondent aux balises HTML : ? saisie des données <h:inputText> ? listes déroulantes <h:selectOneMenu> ? boutons <h:button> ou <h:commandButton> ? tables <h:table> ? … ? Pour améliorer ces composants ou pour en avoir de nouveaux le développeur peut ? utiliser des bibliothèques de composants ? créer ses propres composants R. Grin JSF page 28 |
@Override public DiscountCode getAsObject(
FacesContext ctx, UIComponent cmp, String val) { return ejb.findById(val);
} Utilisé dans TP 1.
@Override Pour faire quoi ?
public String getAsString(
FacesContext ctx, UIComponent cmp, Discount d) { return d.getDiscountCode();
}}; }
R. Grin JSF page 25
| CSS et JSF – fichier des styles ? Utiliser <h:outputStylesheet> à la place de <link rel="stylesheet"> : <h:outputStylesheet name="" /> ? JSF va chercher le fichier dans le répertoire resources placé sous la racine des pages Web ; dans pour l’exemple R. Grin JSF page 35 | CSS et JSF – style d’un composant ? Pour donner du style à un composant JSF, utiliser l’attribut styleClass (ou style pour du CSS intégré) ou un des attributs particuliers à un composant (comme columnClasses de <h:panelGrid>) ? Attention si vous utilisez #id dans le fichier CSS : l’id d’un composant JSF ne correspond pas à l’id du composant HTML envoyé au client R. Grin JSF page 36 |
| Commentaires ? Par défaut les commentaires HTML (<!-- -->) ne fonctionnent pas bien pour JSF, mais on peut configurer pour qu’ils soient pris en compte ? On peut aussi entourer les composants que l’on veut enlever temporairement par la balise <ui:remove> R. Grin JSF page 37 | Backing bean et portée CDI (scope) R. Grin JSF page 38 | ||
| Backing bean ? Backing bean géré par CDI, annoté par @Named ? (Ne pas utiliser les beans gérés par JSF, annotés par @ManagedBean !) ? Initialiser les ressources injectées dans une méthode annotée par @PostConstruct, pas dans un constructeur (il existe aussi @PreDestroy pour « faire le ménage » avant la suppression du bean) Déjà vu pour quel autre composant ? R. Grin JSF page 39 | Exemples ? Ce bean sera désigné par employeBean : @Named @RequestScoped public class EmployeBean { … } ? Celui-ci sera désigné par employe : @Named("employe") @RequestScoped public class EmployeBean { … } R. Grin JSF | page 40 | |
| Bean géré ? Quand une page JSF désigne un bean, par exemple #{} le container CDI regarde s’il existe un bean du même type dans la portée ? Si c’est le cas, le bean existant est utilisé par la page JSF ? Sinon un nouveau bean est créé par le container et utilisé par la page JSF R. Grin JSF page 41 | getter ? Quand une page JSF utilise une propriété d’un backing bean, le getter de la propriété peut être appelé plusieurs fois ? Un getter ne doit donc pas exécuter à chaque appel un code coûteux, tel qu’un accès à une base de données R. Grin JSF page 42 | ||
| ||||||
| Rappel des portées CDI ? Dependent : (portée par défaut) nouvel objet créé à chaque référence ; l’objet est supprimé quand l’objet dans lequel il est injecté est supprimé ? RequestScoped : requête HTTP ? ViewScoped : associé à une vue (page JSF) ? FlowScoped : associé à un ensemble de vues ? ConversationScoped : début et fin par code Java ? SessionScoped : session de travail de l’utilisateur ? ApplicationScoped : durée de vie de l’application ; partagé entre tous les utilisateurs R. Grin JSF page 45 | Serializable ? Les backing beans qui ont une autre portée que RequestScoped et Dependent doivent implémenter Serializable car ils peuvent être retirés temporairement de la mémoire centrale par le container R. Grin JSF page 46 | |||||
| 2 types de portée ? JSF a aussi ses portées qui étaient associées à l’ancienne annotation @ManagedBean (deprecated et remplacée par @Named) mais il faut utiliser les portées CDI ? Attention à importer le bon paquetage ? Ne jamais utiliser les portées du paquetage ! R. Grin JSF page 47 | Le cycle de vie R. Grin JSF page 48 | |||||
| ||||||
| Simple demande d’une page ? Étudions tout d’abord le cas simple d’une requête HTTP GET d’un client qui demande une page JSF, sans passer de paramètres dans la requête R. Grin JSF page 51 | Cycle de vie simplifié ? La phase « Restore View » construit une vue vide (ne contient aucun composant Java) ? La phase « Apply Request Values » s’aperçoit qu’il n’y a pas de paramètres dans la requête ? Le cycle de vie avance donc à la dernière phase « Render Response » dans laquelle la vue de la page JSF demandée est créée, et codée en une page HTML envoyée au client R. Grin JSF | |||||
| Traitement d’un formulaire ? Etudions comment est traitée une requête HTTP POST générée par la soumission d’un formulaire d’une page JSF ? Sur le poste client, l’utilisateur a saisi des valeurs dans ce formulaire ? Ces valeurs sont mises en paramètres de la requête POST envoyée au serveur Web ? Tout le cycle de vie se déroule sur le serveur R. Grin JSF page 53 | ||||||
| Phase de restauration de la vue ? La vue qui correspond à la page qui contient le formulaire est restaurée (phase « Restore View ») R. Grin JSF page 55 | ||
| Phase d’application des paramètres ? Les valeurs des paramètres de la requête HTTP (saisies par l’utilisateur dans le formulaire) sont attribuées aux composants Java de la vue : phase « Apply Request Values » ? Par exemple, si l’utilisateur a saisi un âge dans un composant <h:inputText> du formulaire HTML, le composant Java associé met ce nom dans une variable interne R. Grin JSF page 57 | ||
| Phase de validation ? Les expressions EL sont utilisées pour savoir dans quelles propriétés Java mettre les valeurs récupérées à l’étape précédente : <h:inputText value="#{}" /> ? Les données sont converties dans le type Java et ensuite validées pour voir si elles respectent les contraintes indiquées dans la page JSF et le bean ? Si une conversion ou validation échoue, la phase suivante sera la phase « Rendu de la réponse » qui retourne le formulaire avec tous les messages d’erreur R. Grin JSF page 59 | Validation sur le client HTTP ? Possible de valider avec une fonction JavaScript par une balise JSF personnalisée Intérêt ? ? Pour cela il est plus simple de s’appuyer sur une bibliothèque de composants JSF qui valide par JavaScript, plutôt que d’écrire sa propre validation JavaScript ? Attention, ne remplace pas une validation sur le serveur Pourquoi? R. Grin JSF page 60 |
| Phase de mise à jour du modèle ? Toutes les données ont été validées ; elles peuvent être mises dans les propriétés des backing beans associées (expressions EL) : <h:inputText id="nom" value="#{}" /> | ||||||
| R. Grin JSF page 61 | R. Grin JSF page 62 | |||||
| ||||||
| Phase de rendu de la réponse ? La page déterminée par la valeur retour de la méthode « action » est codée en HTML et envoyée vers le client HTTP R. Grin JSF page 66 | ||||||
| Cycle de vie avec une requête GET ? Si l’URL de la requête contient des paramètres http://serveur/appli/adresse?p1=v1&p2=v2 et si la page JSF demandée contient des paramètres de vue (étudiés plus loin) pour ranger ces valeurs dans un backing bean, le cycle de vie complet est exécuté ? Comme si les valeurs des paramètres de la requête avaient été saisies par un utilisateur dans un formulaire soumis avec une méthode POST R. Grin JSF page 67 | Sauter des phases ? Il est quelquefois indispensable de sauter des phases du cycle de vie ? Il est possible de sauter toutes les phases restantes, par exemple si on a déjà généré une réponse sous le forme d’un fichier PDF ; la méthode FacesContext.responseComplete() est faite pour cela ? L’attribut « immediate="true" » permet aussi de sauter des phases pour certains composants mais son intérêt est faible depuis l’intégration d’Ajax à JSF R. Grin JSF page 68 | ||
| Fichiers de configuration R. Grin JSF page 69 | Exemple de (1/2) <?xml version="1.0" encoding="UTF-8"?> <web-app version="3.1" xmlns="; xmlns:xsi="; xsi:schemaLocation=" "> <context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param> Production pour livrer au client R. Grin JSF page 70 | ||
| Exemple de (2/2) <session-config> <session-timeout>30</session-timeout> </session-config> <welcome-file-list> <welcome-file>faces/index.xhtml</welcome-file> </welcome-file-list> </web-app> R. Grin JSF | page 71 | Phase de projet ? Attention, la phase de projet Development ajoute automatiquement les messages d’erreurs, même s’il n’y a aucun composant pour les messages dans la page (<h:message> ou <h:messages>) ? Ne pas oublier de mettre ces composants dans la page pour que l’utilisateur voie les messages quand l’application sera enproduction R. Grin JSF page 72 | |
| ? Configuration pour CDI (optionnel) ? Sous WEB-INF si fichier WAR ou sous META-INF sinon R. Grin JSF page 73 | faces-config ? : configuration pour JSF ? Par exemple pour indiquer des fichiers de textes pour l’internationalisation (<resource-bundle>) ou pour donner des règles de navigation R. Grin JSF JSF - page 74 | |
| Navigation R. Grin JSF page 75 | Navigation dans JSF ? Navigation = affichage d’une nouvelle page ? Composants JSF standards pour la navigation : <h:commandButton>, <h:button>, <h:commandLink>, <h:link>, <h:outputLink> ? <h:commandButton> et <h:commandLink> doivent être dans une balise <h:form> ; ils soumettent le formulaire ? Les autres composants peuvent ne pas être dans un formulaire et, s’ils le sont, ils ne le soumettent pas R. Grin JSF page 76 | |
| POST ou GET ? <h:commandButton> et <h:commandLink> soumettent le formulaire par une requête POST et affichent la page indiquée par l’attribut action : <h:commandButton value="Voir liste" action="liste.xhtml" /> ? <h:button> et <h:link> lancent une requête GET et affichent la page indiquée par l’attribut outcome : <h:link value="Voir les notes" outcome="/notes/voirNotes" /> ? <h:outputLink> lance une requête GET et affiche la page indiquée par l’attribut value ; la page peut être en dehors de l’application R. Grin JSF page 77 | Recommandation ? Requête GET si on veut juste afficher une page ; par exemple afficher la liste de tous les clients ? Requête POST si l’utilisateur a saisi des données qu’on veut enregistrer sur le serveur ; par exemple si l’utilisateur a modifié le nom d’un client R. Grin JSF page 78 |
| ||
| ||
|
Exemple de règle de navigation
? Règle de navigation dans :
<navigation-rule>
<from-view-id>page1.xhtml</from-view-id>
<navigation-case>
<from-outcome>ok</from-outcome>
<to-view-id>/succes.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>ko</from-outcome>
<to-view-id>/echec.xhtml</to-view-id>
</navigation-case>
</navigation-rule> ? Dans page1.xhtml :
<h:commandButton action="ok" value="Valider" />
Page suivante si clic sur bouton ? /succes.xhtml
R. Grin JSF page 85
| Redirection ? Dans le cas d’une navigation statique, ajouter ?faces-redirect=true à l’URL de la page à afficher : action="page2?faces-redirect=true" ? Dans le cas d’une navigation dynamique, ajouter à la valeur retournée par la méthode : return "page2?faces-redirect=true"; R. Grin JSF page 87 | ? Exercices 1 et 2 du TP 2 (modèle PRG) R. Grin JSF | page 88 | ||
| R. Grin | PRG JSF page 89 | Problèmes avec POST ? Un formulaire est dans une page P1 ; la soumission du formulaire par une requête POST affiche une page P2 en réponse ? 2 problèmes : ? quand P2 est affichée en réponse à la requête POST, le navigateur affiche l’adresse de P1 ? un refresh de P2 après le POST soumet à nouveau le formulaire R. Grin JSF page 90 | ||
| La raison du problème d’URL ? C’est JSF qui dirige vers la nouvelle page (à la fin de la phase « Invoke Application ») ? Le navigateur n’en a pas connaissance ; il continue à afficher l’adresse du formulaire R. Grin JSF page 91 | Refreshou reloadd’une page ? Si l’utilisateur demande un refresh de la page, c’est qu’il veut la dernière version de l’information affichée dans la page ? Le navigateur envoie donc à nouveau la requête qui a permis d’obtenir la page ? Si la page a été affichée en réponse à une requête POST, le navigateur relance donc la requête POST avec les mêmes paramètres, ce qui correspond à une nouvelle soumission du formulaire R. Grin JSF page 92 | ||
| Les conséquences du problème ? Impossible de garder un marque-page pour la page affichée après un POST ? Commande ou paiement involontaire dû à une soumission multiple d’un formulaire Qu’est-ce qui est le plus grave ? R. Grin JSF | page 93 | La solution : Post – Redirect - Get (PRG) ? Le modèle Post – Redirect - Get : ? Ne jamais montrer une page en réponse à un POST ? Charger les pages uniquement avec des GET ? Utiliser la redirection pour passer de POST à GET R. Grin JSF page 94 | |
| Problèmes de PRG ? La redirection peut poser un problème : ? Informations conservées dans la requête du POST ne sont plus disponibles après la redirection ? Messages de succès ou d’information, générés par programmation, sont conservés le temps d’une requête et donc n’apparaissent plus après une redirection R. Grin JSF page 97 | Portée session ? ? Une des solutions est de ranger les informations dans la session plutôt que dans la requête ? Mais cette solution est mauvaise car elle peut conduire à une session trop encombrée ou à d’autres problèmes (en particulier session ne tient pas compte des onglets des navigateurs) R. Grin JSF page 98 | |
| Solutions ? JSF offre des possibilités pour conserver les informations plus longtemps que la requête, sans passer en portée session ? Le plus intéressant est d’utiliser les paramètres de vue (permet de rester en portée « requête ») R. Grin JSF page 99 | Paramètres de vue ? Une requête GET avec 2 paramètres nom et age : ;age=23 ? Avec des paramètres de vue on peut récupérer les valeurs « Bob » et « 23 » dans des propriétés d’un backing bean ? Un paramètre de vue est créé par une balise <f:viewParam> placée à l’intérieur d’une balise <f:metadata> dans la page demandée par GET (page2.xhtml pour l’exemple) R. Grin JSF page 100 |
| Placement de <f:metadata> ? Doit être au « top level », pas dans une autre balise ? Si un template est utilisé, il ne faut pas mettre <f:metadata> dans le template ; il faut le mettre dans le client du template page 102 |
Exemple
Requête GET
? Dans page2.xhtml (juste avant <h:head>) :
<f:metadata>
<f:viewParam name="nom" value="#{bean.p1}" />
</f:metadata>
? Bob sera mis dans la propriété p1 de bean, avant l’affichage de la page
? Dans <f:viewParam>, comme dans
<h:inputText>, on peut ajouter un convertisseur, un validateur ou un attribut required
page 101
| <f:viewAction> ? Balise d’une page demandée par GET ; doit être placée à l’intérieur de <f:metadata> ? Exécute une méthode d’un backing bean ? Exemple : <f:viewAction action="#{bean.m()}"/> ? Cette méthode est exécutée ? après l’enregistrement par <f:viewParam> des valeurs des paramètres de la requête GET dans un backing bean ? avant l’affichage de la page R. Grin JSF page 103 | Exemple d’utilisation ? Soit une requête GET http://…/employe.xhtml?id=12 ? Un paramètre de vue de la page employe.xhtml récupère la valeur de l’id de la requête (12) dans la propriété id d’un backing bean ? L’action de <f:viewAction> récupère dans la base de données l’employé qui a l’id 12 et le met dans une propriété employe (type Employe) du backing bean ? Les informations sur l’employé sont ensuite affichées dans la page employe.xhtml, par exemple par #{} R. Grin JSF page 104 | |||||
| ||||||
| includeViewParams (1/2) ? Cet attribut peut être ajouté à tout lien vers une page qui contient des paramètres de vue : <h:commandButton value=… action="page2?faces-redirect=true& includeViewParams=true" /> ? includeViewParams=true signifie « inclure dans le lien les paramètres qui correspondent aux paramètres de vue de la page de destination, avec les valeurs définies par l’expression EL du paramètre de vue » R. Grin JSF page 107 | includeViewParams (2/2) ? Si l’action désigne une méthode, il faut ajouter « includeViewParams=true » dans la valeur retournée par la méthode : return"page2?faces-redirect=true& includeViewParams=true"; R. Grin JSF page 108 | |||||
| Utilité de includeViewParams ? Si page1 et page 2 utilisent des backing beans de portée requête de la même classe, ça permet de passer des valeurs du backing bean de page1 dans le backing bean de page2, après une redirection ? Le 1er bean ne dure que le temps de la requête POST ; les valeurs des paramètres de vue (donc du 1er bean) sont passés dans la requête GET de redirection ? Le 2ème bean utilisé par la page d’arrivée met ces valeurs dans ses propriétés (grâce aux paramètres de vue) R. Grin JSF page 109 |
Exemple La valeur 5 a été passée
de la 1ère à la 2ème
? page2.xhtml (backing bean bean) :instance de Bean
<f:viewParam name="n1" value="#{bean.p1}" />
? Lien de page1.xhtml (backing bean bean) :
<h:commandButton value=… action="page2?faces-redirect=true
&includeViewParams=true" />
? Supposons que bean.p1 = 5 au départ de la requête, alors la requête GET aura le paramètre
« n1="#{bean.p1}" » donc « n1=5 »
? En arrivant dans page2.xhtml, la valeur 5 sera donc mise dans la propriété bean.p1
R. Grin JSF page 110
| includeViewParams avec GET ? Avec un composant « GET » comme <h:link>, il faut utiliser l’attribut includeViewParams : <h:link outcome="page" includeViewParams="true" > R. Grin JSF page 111 | Donner une valeur à un paramètre (1/2) ? Plusieurs autres façons de donner une valeur à un paramètre de requête GET : ? <h:link outcome="page?p1=4&p2='bibi'" … > <h:link outcome="page?p1=#{ + 2}" … > ?<h:link outcome="page" …> <f:param name="p1" value="4"/> </h:link> R. Grin JSF page 112 | |||||
| ||||||
| ? Finir TP 2 ? TP 3 (templates) ? Étudier la suite de ce support seul R. Grin JSF | page 115 | Messages d’erreur ou d’information / de succès R. Grin JSF page 116 | |
| Cas d’utilisation ? Les conversions et validations peuvent conduire à l’affichage de messages d’erreur ? Lorsqu’une action s’est bien déroulée il faut le signaler à l’utilisateur par un message d’information / de succès R. Grin JSF page 117 | Affichage des messages ? <h:messages> indique un emplacement de la page où sont affichés tous les messages ? <h:message> indique un emplacement pour afficher un message pour un seul composant identifié par l’attribut for ? Ces 2 balises ont de nombreux attributs R. Grin JSF page 118 | ||
| Format d’affichage des messages ? Les attributs styleClass et style indiquent un style CSS pour affichage des messages ? D’autres attributs définissent un style lié à la sévérité du message (errorStyle, errorClass, infoStyle, infoClass,…) R. Grin JSF page 119 | Exemples ? Messages de sévérité « ERROR » affichés avec la classe CSS « erreur » et messages de sévérité « INFO » affichés en vert et caractères gras <h:messages errorClass="erreur" infoStyle="color:green;font-weight:bold;"/> ? <h:messages globalOnly="true"/> affiche la liste des messages qui ne sont pas liés à un composant particulier ? <h:message for="nom" /> ? <h:message for="nom" showSummary="true" showDetail="false" /> R. Grin JSF page 120 | ||
| Messages standards ? Les convertisseurs et validateurs standards produisent des messages d’erreur standards ? Les attributs des composants standards requiredMessage, converterMessage ou validatorMessage permettent de modifier ces messages ? Exemple : <h:inputText id="nom" required="true" requiredMessage="Le nom est requis"/> R. Grin JSF page 121 | Améliorer les messages standards ? Un message d’erreur peut comporter l’identifiant du composant concerné par l’erreur ? Pour rendre les messages plus clairs, il faut donner des identifiants significatifs (attribut id) aux formulaires et aux composants pour éviter les « j_idt6:j_idt8 » dans les messages ? On peut aussi utiliser l’attribut label des composants ; ce label sera utilisé pour désigner le composant dans les messages R. Grin JSF page 122 | |||||
| Messages personnalisés ? Les convertisseurs et validateurs personnalisés permettent aussi d’afficher facilement des messages d’erreur ? S’ils ne peuvent être utilisés (par exemple validation qui englobe plusieurs composants) ou pour afficher un message de succès, le développeur peut ajouter ses messages dans les pages JSF par programmation Java ? Les transparents suivants étudient les classes et méthodes Java utilisées pour afficher ces messages R. Grin JSF page 123 | Classe FacesMessage ? La classe FacesMessage du paquetage javax.faces.application représente un message affiché par <h:messages> ou <h:message> ? Propriétés d’un message : ? sévérité (SEVERITY_FATAL, SEVERITY_ERROR, SEVERITY_WARN, SEVERITY_INFO de la classe interne Severity) ? message détaillé ? message résumé R. Grin JSF page 124 | |||||
| ||||||
| ||||||
| ||||||
| Identificateur « client » ? Pas toujours facile de trouver les id « client » ? Regarder le code HTML généré aide ? Identificateur client composé de plusieurs niveaux, avec le séparateur « : » ; par exemple, « formulaire:j_idt41 » ? Pour faciliter, donner des ids aux composants (y compris composants englobants) et/ou utiliser l’attribut prependId="false" pour les formulaires qui les contiennent ? Identificateur doit exister dans la page HTML générée (attention aux rendered="false") R. Grin JSF page 131 | Message après redirection ? Puisqu’un message ne dure qu’une seule requête, il ne s’affichera pas après une redirection ? Si on veut qu’il s’affiche, il faut un code un peu plus complexe qui utilise la classe Flash R. Grin JSF page 132 | |||||
| |||||||
| Événements R. Grin JSF page 135 | Types d’événements ? 2 grands types d’événements : ? Généré par une action de l’utilisateur (de type « application ») ? Généré à un moment du cycle de vie (de type « lifecycle ») R. Grin JSF | page 136 | |||||
| Événements « application » ? ValueChangeEvent : valeur d’un composant modifiée par l’utilisateur (champ de saisie de texte, menu, liste déroulante,…) ; liés aux composants tels que <h:selectOneMenu> ou <h:inputText> ? ActionEvent : clic sur un bouton ou un lien ; liés aux composants tels que <h:commandButton> ou <h:commandLink> R. Grin JSF page 137 | Écouteur ? Les événements sont traités par des écouteurs, ? méthodes (attribut xxxListener) ? ou classe (sous-balise <f:xxxListener>) R. Grin JSF page 138 | ||||||
| R. Grin | Ajax JSF page 141 | Ajax ? Asynchronous Javascript and XML ? Une requête Ajax envoyée par le client est lancée « en arrière-plan » ; l’utilisateur peut continuer à travailler avec la page en cours ? La réponse du serveur à la requête ne modifie qu’une partie de la page en cours R. Grin JSF page 142 | |
| <f:ajax> ? Ajoute des fonctionnalités « Ajax » au composant JSF dans lequel il est inclus ? Un événement déclencheur sur ce composant provoque l’envoi d’une requête Ajax au serveur sans attendre la soumission du formulaire ? Par exemple, une liste déroulante peut envoyer une requête Ajax quand l’utilisateur fait un nouveau choix ; la réponse du serveur ne mettra à jour qu’une partie de la page, par exemple une 2ème liste déroulante dont les valeurs dépendent du choix fait par l’utilisateur dans la 1ère liste R. Grin JSF page 143 | <f:ajax> - les attributs ? event : événement déclencheur de la requête ; valeur par défaut dépend du composant, par exemple, valueChange pour les <h:inputText> ou action pour les <h:commandButton> ? execute : composants pris en compte pour l’envoi de la requête (espace séparateur) ; valeur par défaut @this, le composant qui contient <f:ajax> ? render : composants mis à jour au moment de la réponse du serveur (espace séparateur) ; valeur par défaut @none R. Grin JSF page 144 | ||
| Identificateurs « client » ? Utilisés dans les attributs execute et surtout render ? Revoir section « Messages d’erreur ou d’information » R. Grin JSF page 147 | Mélange d’Ajax et de requête normale ? Quand un champ de saisie lance une requête Ajax, et que l’utilisateur appuie sur la touche [Entrée] après avoir saisi la valeur, un message d’avertissement indique qu’une requête Ajax a été mélangée avec une requête « normale » (l’appui sur la touche [Entrée] déclenche la soumission du formulaire en même temps que l’action « Ajax ») ? Pour ne plus avoir cet avertissement, il suffit de passer le bouton de soumission en Ajax : <h:commandButton …><f:ajax execute="@form" render="@form"/></h:commandButton> R. Grin JSF page 148 | |||||
| ||||||
| Exemple d’utilisation ? Un écouteur peut récupérer ? un client à partir d’un id saisi par l’utilisateur ? tous les noms qui commencent par les caractères tapés par l’utilisateur sont affichés comme suggestion (complétion de nom) R. Grin JSF page 151 | JSF et HTML5 R. Grin JSF page 152 | |||
| Pages HTML5 ? Les pages HTML générées par JSF sont maintenant déclarées comme des documents HTML5 avec <DOCTYPE html> R. Grin JSF page 153 | Composants HTML5 ? Avant JSF 2.2, pour profiter d’un nouveau composant HTML dans JSF il fallait écrire un composant JSF ? JSF 2.2 permet de profiter des services offerts par JSF (validation de données, affichage automatique des messages d’erreur, utilisation simple d’Ajax, …) tout en utilisant un attribut ou un composant HTML5 R. Grin JSF page 154 | |||
| 2 possibilités ? On peut utiliser un attribut HTML5 (attribut « passthrough ») dans un composant JSF ? Exemple : attribut placeholder de <input> alors qu’il n’est pas un attribut de <h:inputText> ? L’attribut sera passé tel quel à la balise HTML générée à la fin du cycle de vie JSF ? On peut aussi utiliser une balise HTML5, tout en profitant des facilités de JSF avec des attributs traités par JSF R. Grin JSF page 155 | ? un composant JSF R. Grin | Attributs HTML5 en JSF Etudions d’abord le cas d’un attribut HTML5 dans JSF | page 156 | |
|
| Composant HTML5 traité par JSF ? Le composant HTML5 est transformé en un composant JSF suivant un mapping qui tient compte du nom de la balise et éventuellement de certains attributs de la balise ? Exemple : <input type="file"> est transformé en <h:inputFile> R. Grin JSF page 161 | Composant HTML5 sans équivalent JSF ? Si le composant HTML5 n’a pas de correspondance dans JSF, JSF crée un composant spécial de balise <jsf:element> ? On peut ajouter des capacités Ajax à un tel composant (voir exemple à suivre), mais seulement quelques attributs JSF liés aux événements JavaScript ? Les valeurs des attributs HTML5 peuvent contenir des expressions EL comme pour les composants JSF R. Grin JSF page 162 |
| Ressources R. Grin JSF page 165 | Ressources des pages Web ? Les pages HTML font le plus souvent appel à des ressources externes : images, fichier CSS, code Javascript,… ? Il faut utiliser des balises JSF dédiées aux ressources à la place des balises HTML ; en ce cas JSF va chercher les ressources dans le répertoire resources placé sous la racine des pages Web R. Grin JSF page 166 | |
| CSS ? Le plus souvent on met les fichiers CSS dans un sous-répertoire css du répertoire resources <h:outputStylesheet name=""/> R. Grin JSF page 167 | JavaScript ? Le plus souvent on met les fichiers JavaScript dans un sous-répertoire js du répertoire resources <h:outputScript name="" /> ? Par défaut, le script sera placé dans la page HTML à l’endroit où on a mis la balise ; on peut ajouter un attribut target pour indiquer où le mettre (par exemple target="head") R. Grin JSF page 168 |
| Image <h:graphicImage name="" /> R. Grin JSF page 169 | Thèmes ? Depuis JSF 2.2 on peut avoir des thèmes qui réunissent les ressources en utilisant l’attribut library des balises que l’on vient de voir ? En ce cas, chaque librairie correspondra alors à un thème différent, par exemple on aura un thème « defaut » et un thème « dark » ? Sous chacun des répertoires defaut et dark (placés sous le répertoire resources), on retrouvera les répertoire css, js et image qu’on vient de voir ? Il suffit alors de changer de librairie pour changer à la fois le CSS, le JavaScript et les images R. Grin JSF page 170 | |
| Flots (faces flow) R. Grin JSF page 171 | Présentation ? A la manière des « wizards », les flots de pages (en fait, flots de nœuds, comme on le verra plus loin) sont des ensembles de pages qui partagent des informations communes (entreposées dans un backing bean de portée Flow) R. Grin JSF page 172 | |
| Exemple ? Les pages qui permettent à un utilisateur de créer un compte avec ses informations personnelles, l’adresse de livraison, l’adresse de facturation et les informations sur sa carte de crédit ? Chaque type d’information est donnée sur une page différente ? Souvent la dernière page demande confirmation de toutes les données saisies et on peut lancer leur enregistrement ou un traitement avec les informations recueillies sur toutes les pages R. Grin JSF page 173 | Navigation avec un flot ? On ne peut entrer dans le flot que par la page de démarrage ; les autres pages du flot ne sont pas atteignables de l’extérieur du flot ? Quand on est dans le flot, on ne peut aller que vers des pages du flot ou vers la page de sortie ? Pour sortir du flot il suffit de naviguer depuis une page du flot vers la page de sortie ? Dès que la navigation amène à la page de sortie, les backing beans de portée flow sont supprimés automatiquement par CDI R. Grin JSF page 174 |
| Navigation par requête POST ? Malheureusement la navigation ne marche pas toujours bien si on utilise des requêtes GET ou des requêtes POST avec redirection (on oublie le modèle PRG dans les flots) ? Il est donc conseillé de n’utiliser que des requêtes POST ; dans les cas simples on peut tester avec des requêtes GET mais souvent on se retrouve avec des messages d’erreurs pour des adresses non trouvées ou bien avec une impossibilité de sortie du flot R. Grin JSF page 175 | Plusieurs flots ? Les flots peuvent être enchaînés séquentiellement ou bien emboités les uns dans les autres R. Grin JSF | page 176 | |||||
| Portée ? Comme la portée conversation le portée flot (annotation des backing beans par @FlowScoped) est entre la portée requête et la portée session ? La portée flot est une portée CDI ? Au contraire de la portée session, la portée flot n’a pas de problème si l’utilisateur ouvre plusieurs onglets du navigateur sur la même application R. Grin JSF page 177 | Utilité ? L’utilisation d’un enchaînement de pages pour obtenir de l’utilisateur un ensemble d’informations est fréquent ? Avant JSF 2.2, un backing bean de portée conversation était le plus souvent utilisé, avec les difficultés occasionnées par cette portée ? Un flot de pages ? simplifie la programmation d’une telle situation ? facilite la modularité ? peut être réutilisé dans des applications différentes R. Grin JSF page 178 | ||||||
| Similaire à une méthode Java ? Un seul point d’entrée, plusieurs points de sortie possibles ? Paramètres d’entrée et valeur de retour ? Peut être appelé d’un autre point de l’application ? Interface bien définie mais les détails de l’implémentation sont cachés ? Un flot peut en appeler un autre et les portées s’empilent et se dépilent comme dans une pile d’exécution de méthodes R. Grin JSF page 179 | Définition d’un flot ? Suit le principe « Convention plutôt que configuration » : on peut définir un flot en créant un répertoire dans la racine des pages JSF de l’application ? Si on n’utilise pas la « convention », le flot peut être configuré dans le fichier <nom-flot> placé dans le répertoire qui contient les pages du flot, dans le fichier ou bien par programmation avec un producteur de Flow CDI R. Grin JSF page 180 | ||||||
| Définition d’un flot par convention ? Répertoire dans la racine des pages, du même nom que le flot ? Dans le répertoire, ? Une page du même nom que le répertoire (et suffixe .xhtml) comme nœud de démarrage du flot ? Les pages qui sont dans le flot ? Un fichier de configuration obligatoire nommé <nom-flot>-flow.xhtml (vide si on n’a rien à configurer) ? En dehors du répertoire la page de sortie de nom <nom-flot>-return.xhtml R. Grin JSF page 181 | Code pour entrer et sortir ? Les exemples suivants supposent que la convention a été suivie (pas de configuration) ? Exemple de code pour entrer dans le flot nommé flot1 (page flot1.xhtml mise dans le répertoire flot1) : <h:commandButton id="start1" value="Entrer dans Flot1" action="flot1"/> ? Exemple de code pour sortir du flot nommé : <h:commandButton id="home" value="home" action="/flot1-return" /> Fichier flot1-return.xhtml situé en dehors du répertoire flot1 R. Grin JSF page 182 | ||||||
| |||||||
| Configuration avec fichier XML (2/2) ? Le fichier peut aussi configurer ? le nœud de démarrage ? d’autres nœuds du flot ? des paramètres à passer au flot (<inbound-parameter>) ? un initialiseur, méthode exécutée avant l’entrée dans le flot ; pourra avoir accès aux paramètres dans la version JSF 2.3, buggé dans les versions précédentes ? un « finalizer », méthode appelée juste avant la sortie du flot R. Grin JSF page 185 |
Exemple de fichier XML minimal
<faces-config version="2.2" xmlns="; xmlns:xsi="; xsi:schemaLocation="
">
<flow-definition id="flot1"> <flow-return id="return1">
<from-outcome>#{()}</from-outcome>
</flow-return>
</flow-definition> En valeur retour, l’id de la vue
</faces-config> ou bien, si la vue n’est pas définie,
le chemin par rapport à la racine ; par exemple /index (sans le suffixe)
R. Grin JSF page 186
| Types de nœuds ? Les types de nœud sont décrits dans la javadoc de la classe .FlowHandler) : ? View, page JSF « normale » ? Switch, liste d’expressions EL de type boolean ; la 1ère expression qui est évaluée à true détermine le prochain nœud ? Return, arrête le flot en cours et définit la page affichée à la sortie du flot (page qui n’est pas dans le flot) ? Method Call, appel d’une méthode (avec paramètres) dont la valeur de retour détermine le prochain nœud ? Faces Flow Call, appel d’un autre flot ; au retour de cet autre flot, le flot reprend la main (pile de flots) R. Grin JSF page 187 | En savoir plus sur les flots… ? Les informations détaillées sur ces nœuds et les autres façons de définir et de configurer un flot ne seront pas étudiées dans cette section d’introduction aux flots ? Références pour plus de détails : ? Tutoriel Java EE 7, partie III : #CHDGFCJF ? (extrait livre MASTERING JAVASERVER FACES 2.2 de Anghel Leonard). R. Grin JSF page 188 |
