Blog ENI : Toute la veille numérique !
En raison d'une opération de maintenance, le site Editions ENI sera inaccessible le mardi 10 décembre, en début de journée. Nous vous invitons à anticiper vos achats. Nous nous excusons pour la gêne occasionnée
En raison d'une opération de maintenance, le site Editions ENI sera inaccessible le mardi 10 décembre, en début de journée. Nous vous invitons à anticiper vos achats. Nous nous excusons pour la gêne occasionnée

Le framework de présentation JSF

Présentation générale

L’utilisation des servlets et des JSP dans un projet d’envergure n’est pas chose aisée. Il est préférable d’utiliser un framework proposant un cadre d’architecture bien défini et un ensemble de composants limitant le code redondant et fastidieux. Le présent chapitre a pour objectif de découvrir les rudiments du framework MVC JSF 3.0 (Jakarta Server Faces). C’est un framework orienté composants.

Un framework orienté composants est un framework manipulant des composants visuels et métiers en limitant au maximum l’usage direct des technologies web. Dans ce sens, ce type de framework s’approche du développement d’une application client/serveur. Les développeurs novices en développement web peuvent donc obtenir des résultats rapidement.

On oppose ce type de framework aux frameworks orientés actions. Ce type de framework manipule, quant à lui, des requêtes et des réponses HTTP. Un framework de ce type est beaucoup plus proche du protocole HTTP et des technologies satellites. Il se base clairement sur les technologies présentées dans les chapitres précédents. C’est le cas par exemple de Struts 2.

Ces deux types de frameworks respectent toutefois le pattern MVC (modèle-vue-contrôleur). Ils proposent donc...

Présentation de JSF

1. Généralités

JSF est une technologie Jakarta actuellement dans sa version 3.0. La documentation officielle est disponible à l’adresse suivante : https://jakarta.ee/specifications/faces/3.0/jakarta-faces-3.0.pdf

L’implémentation de référence, nommée Mojarra 3.0, sera utilisée dans le cadre de ce chapitre. Le site de référence de cette implémentation est accessible à cette adresse : https://eclipse-ee4j.github.io/mojarra/

JSF est constitué des éléments suivants :

  • Une API permettant de représenter les composants et de gérer leur état. Ces composants sont nommés managedBeans (on parle aussi de backingBeans).

  • Une API permettant de gérer les événements, les validations côté serveur, la conversion des données, la navigation, l’internationalisation.

  • Des bibliothèques de tags à l’image de ceux disponibles pour les JSP (les balises JSTL) afin de proposer un rendu adapté des managedBeans. Les pages JSF sont appelées facelets.

2. Principes de fonctionnement

Le fonctionnement repose sur un ensemble d’étapes (cycle de vie) entre l’arrivée de la requête HTTP jusqu’à la restitution de la réponse. Le schéma suivant présente ce fonctionnement. 

images/05EP01N.png

Le cycle de vie est composé de six étapes entre lesquelles s’intercalent des phases de gestion d’événements (Process Events) non abordées dans cet ouvrage :

  • Restore View : c’est la première étape exécutée lorsqu’une requête vers...

Le paramétrage général

1. Le fichier faces-config.xml

Le fichier faces-config.xml, situé dans le répertoire webapp/WEB-INF, est un fichier de paramétrage optionnel dans l’utilisation de JSF. Il doit avoir le contenu minimal suivant avec la balise racine <faces-config> :

<?xml version="1.0" encoding="UTF-8"?> 
<?xml version="1.0" encoding="UTF-8"?> 
<faces-config 
    xmlns="https://jakarta.ee/xml/ns/jakartaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee  
    https://jakarta.ee/xml/ns/jakartaee/web-facesconfig_3_0.xsd" 
    version="3.0"> 
 
</faces-config> 

Pour information, ce fichier n’est que peu modifié dans le cadre de ce chapitre car les exemples mis en œuvre sont relativement simples et utilisent les annotations ou les paramétrages par défaut.

2. Le fichier beans.xml

Le fichier beans.xml, situé dans le répertoire webapp/WEB-INF, est un fichier de paramétrage nécessaire pour pouvoir utiliser l’injection de dépendances via l’API Weld. Il doit avoir le contenu minimal suivant avec la balise racine...

L’exemple

L’exemple utilisé dans la suite du chapitre va mettre en œuvre un formulaire permettant la saisie d’un nouveau sport. Pour cela, il est nécessaire d’utiliser les classes Java du package fr.editions_eni.jakartaee.models des projets précédents. Pour rappel, voici le contenu de ce package :

images/05EP03N.png

L’ajout d’un sport nécessite la saisie d’un nom, d’un nombre de joueurs et la sélection des terrains sur lesquels le sport peut être pratiqué. Les classes Sport et Terrain sont donc utilisées. Ces deux classes respectent les conventions d’un JavaBean.

Les managedBeans

1. Présentation

Les managedBeans correspondent aux contrôleurs de votre projet. En ce sens, ils réagissent aux actions de l’utilisateur et fournissent les informations à afficher.

Un managedBean est simplement une classe Java annotée avec @Named ou déclarée comme telle dans le fichier faces-config.xml au travers de la balise <managed-bean>. L’annotation @Named possède un paramètre value permettant de donner un nom logique à cette classe. Si cet attribut n’est pas renseigné, le nom attribué par défaut est le nom de la classe (sans prendre en compte le nom du package) en minuscule. Ce nom est important pour utiliser le managedBean dans une facelet.

Un managedBean est souvent associé à une ou plusieurs facelets (correspondant à la vue). Il possède des propriétés (variables membres privées avec des getters/setters publics) correspondant aux informations affichées sur la facelet. Il possède aussi des méthodes appelées en fonction des actions opérées par l’utilisateur. Il possède nécessairement un constructeur sans paramètre.

Un managedBean est aussi annoté avec une annotation déterminant sa portée (@RequestScoped, @ViewScoped, @SessionScoped, @ApplicationScoped). Si l’état du managedBea.n ne doit pas être sauvegardé une fois la réponse retournée...

Les facelets

1. Les librairies

Depuis JSF 2.0, Facelets est la technologie standard d’affichage. Elle s’appuie sur un langage de balises XML. Parmi les librairies disponibles, citons les suivantes :

Librairie

URI

Préfixe

La librairie html

http://xmlns.jcp.org/jsf/html

h

La librairie core

http://xmlns.jcp.org/jsf/core

f

La librairie facelets

http://xmlns.jcp.org/jsf/facelets

ui

Une description détaillée de ces librairies est disponible à l’adresse suivante : https://javaserverfaces.java.net/nonav/docs/2.0/pdldocs/facelets

Il est aussi possible de référencer les librairies JSTL. Pour plus d’informations sur l’utilisation des balises JSTL, veuillez vous référer à la section Les balises JSTL du chapitre traitant des JSP.

La structure de base d’une facelet

La structure de base d’une facelet est la suivante :

<!DOCTYPE html>  
<html  
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets" 
    xmlns:h="http://xmlns.jcp.org/jsf/html" 
    xmlns:f="http://xmlns.jcp.org/jsf/core" 
    xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"> 
    <!--votre code--> 
</html> 

La balise racine <html> permet de déclarer les librairies utilisables. Les trois premières déclarations correspondent aux librairies de la technologie Facelets et la quatrième correspond à la librairie JSTL core.

L’extension du fichier est .xhtml. Ce n’est pas une JSP. Les balises <jsp:xxx> ne sont pas utilisables et le code Java est proscrit. Seul l’EL est exploitable. Une facelet est donc beaucoup plus homogène (dans son contenu) qu’une JSP.

La librairie html

La librairie html met à disposition les balises à utiliser pour les différents composants graphiques à afficher. Le nom des balises est suffisamment explicite pour comprendre leur utilité. Référez-vous à la documentation officielle pour connaître la liste exhaustive. Voici néanmoins quelques exemples :

  • La balise <h:form> : cette balise permet de paramétrer une balise html <form>.

  • La balise <h:commandButton> : cette balise permet de paramétrer une balise html <input> de type submit.

  • La balise <h:inputText>...

Les conversions

Le mécanisme de conversion est essentiel pour faire le pont entre la représentation textuelle côté client et la représentation objet côté serveur. La conversion se base sur l’implémentation de l’interface jakarta.faces.convert.Converter. Il existe des implémentations standards permettant les conversions les plus courantes d’une chaîne de caractères vers un type donné :

  • BigDecimalConverter

  • BigIntergerConverter

  • BooleanConverter

  • ByteConverter

  • CharacterConverter

  • DateTimeConverter

  • DoubleConverter

  • FloatConverter

  • IntegerConverter

  • LongConverter

  • NumberConverter

  • ShortConverter

Il n’existe bien sûr pas de convertisseur pour les terrains. Il est nécessaire qu’on le crée. Pour cela, il suffit de créer une classe implémentant l’interface Converter<T>. La classe TerrainConverter du package fr.editions_eni.jakartaee. converters implémente cette interface. Le code de cette classe est le suivant :

@FacesConverter(value="TerrainConverter") 
public class TerrainConverter implements Converter<terrain>  
{ 
 
    @Override 
    public Terrain getAsObject(FacesContext context, UIComponent 
component, String value)  
    { 
        return new Terrain(value, Surface.BETON); 
    } 
 
    @Override 
    public String getAsString(FacesContext context, UIComponent 
component, Terrain value)  
    { 
        return value!=null?value.getCode():null; 
    } 
} 

L’interface oblige à implémenter deux méthodes :

  • La méthode Object getAsObject(..., String value)

  • La méthode String getAsString(..., Object...

Les validations

La principale faiblesse du programme écrit actuellement est qu’il n’y a aucun contrôle de saisie. En effet, l’utilisateur peut saisir ce qu’il souhaite au niveau du nom et du nombre de joueurs. Ainsi la page de confirmation peut ressembler à cela :

images/05EP08N.png

L’application confirme la création d’un sport sans nom, sans terrain et avec un nombre de joueurs à -5. Il est important de faire des contrôles de saisie et d’alerter l’utilisateur en cas de problème. Cela correspond au mécanisme de validation.

La validation peut être déterminée à différents endroits :

  • Au niveau de la facelet en utilisant des validateurs prédéfinis.

  • Au niveau d’une classe Java correspondant à un validateur spécifique.

  • Au niveau des classes du modèle avec la spécification Bean Validation.

Voici les règles à mettre en place :

  • Le nom est obligatoire.

  • Au moins un terrain doit être sélectionné.

  • Le nombre de joueurs doit être compris entre 1 et 10.

1. La validation dans la facelet

La validation dans la facelet passe par l’utilisation des validateurs prédéfinis. Voici la liste de ces validateurs :

  • <f:validateDoubleRange> : ce validateur permet d’évaluer la valeur saisie dans le composant graphique associé. Cette valeur doit être un double valide compris entre les bornes définies par les attributs minimum et maximum. Au moins un de ces attributs doit être renseigné.

  • <f:validateLength> : ce validateur permet d’évaluer la taille de la saisie dans le composant graphique associé. La taille doit être comprise entre les bornes minimum et maximum. Au moins un de ces attributs doit être renseigné. La valeur de ces attributs doit être un double positif.

  • <f:validateLongRange> : ce validateur permet d’évaluer la valeur saisie dans le composant graphique associé. Cette valeur doit être un long valide compris entre les bornes définies par les attributs minimum et maximum. Au moins un de ces attributs doit être renseigné.

  • <f:validateRegex> : ce validateur permet de vérifier que la saisie du composant graphique associé respecte l’expression régulière définie...

L’internationalisation

L’internationalisation permet d’adapter l’application aux langages des utilisateurs. Le fonctionnement de base est le même que celui présenté dans le chapitre traitant des JSP dans la section Les balises JSTL - La librairie d’internationalisation et de formatage (fmt) - Les principes.

La suite de la section va exposer l’internationalisation se basant sur l’attribut de requête HTTP Accept-Language.

1. La création des fichiers .properties

La première étape consiste à créer les fichiers .properties pour l’ensemble des langages supportés par l’application. Dans le cadre de l’exemple, deux fichiers sont créés :

  • Messages.properties

  • Messages_en.properties

Le premier fichier correspond aux ressources par défaut. Les messages sont écrits en français. Le second correspond aux ressources écrites en anglais. Ces fichiers contiennent des informations sous la forme clé=valeur.

Ces deux fichiers sont positionnés dans le répertoire main/resources du projet afin qu’ils soient déployés dans le répertoire /WEB-INF/classes.

Le contenu du fichier Messages.properties est le suivant :

template.titre.defaut=Titre par défaut 
header.titre=En-tête JSF 
footer.contenu=Editions ENI 
sport.label.nom=Nom 
sport.label.terrains=Terrains 
sport.label.nombreJoueurs=Nombre de joueurs 
sport.bouton.valider=Valider 
sport.erreur.terrains=Veuillez sélectionner au moins un terrain 
zone.erreur.obligatoire=La valeur est obligatoire 

Le contenu du fichier Messages_en.properties est le suivant :

template.titre.defaut=Default title 
header.titre=JSF header 
footer.contenu=Editions ENI 
sport.label.nom=Name 
sport.label.terrains=Fields 
sport.label.nombreJoueurs=Number of players 
sport.bouton.valider=Submit 
sport.erreur.terrains=Please, select at least one field 
zone.erreur.obligatoire=The value is mandatory 

2. La déclaration dans le fichier faces-config.xml

La création de fichiers .properties impose leur déclaration dans le fichier faces-config.xml afin de faciliter leur utilisation dans les facelets. Voici la configuration à réaliser :

<application> 
    <resource-bundle> 
   ...

Conclusion

Ce chapitre vous a présenté les grandes lignes permettant de démarrer sereinement avec JSF.

L’utilisation d’un framework tel que JSF est un atout pour les projets d’une certaine taille car il impose une architecture avec une séparation claire des responsabilités entre les différents composants.

Pour aller plus loin, n’hésitez pas à consulter la documentation officielle de ce framework. L’ensemble des possibilités de ce framework n’a pas été abordé, tant s’en faut. Des sujets comme la sécurité, le couplage avec JavaScript… sont des éléments importants.