Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Validation d'un formulaire JSF

Votre première page JSF Validation d'un formulaire JSF par annotations



Accès rapide :
La vidéo
Introduction à la validation d'un formulaire JSF
Petit historique
Rappels sur la validation d'un formulaire en HTML 5
Rendre la saisie d'un champ obligatoire avec JSF
Utilisation des tags de validation JSF
Exemple d'utilisation d'un tag de validation
Exemple d'utilisation d'un tag de validation à base d'expression régulière
Mise en oeuvre de validateurs personnalisés
Couper la validation du formulaire pour un bouton particulier
Activation du support HTML5 de validation des champs du formulaire
Utilisation de la taglib http://xmlns.jcp.org/jsf/passthrough
Utilisation de la taglib http://xmlns.jcp.org/jsf
Technique de hacking pour débrayer la validation côté client

La vidéo

Cette vidéo vous montre comment mettre en oeuvre la validation de vos formulaires JSF en utilisant les tags et les attributs de validation proposés par le framework.


Validation de vos formulaires JSF

Introduction à la validation d'un formulaire JSF

Petit historique

La validation d'un formulaire HTML, n'est pas si simple qu'il n'y parait. Effectivement, dans ses premières versions le langage HTML ne proposait aucun mécanisme de validation de formulaire. Pour autant, on pouvait ajouter du code JavaScript pour vérifier le contenu de chaque champ avec la soumission du formulaire. Le problème à utiliser une validation côté client réside dans le fait qu'on peut très facilement demander les outils de développement de votre navigateur (en appuyant sur la touche F12) et débrayer ces vérifications avant la soumission de votre formulaire. Il est donc impératif de vérifier les données soumises, côté serveur.

A l'époque d'HTML 4.01, JSF a donc proposé un ensemble de possibilités afin de valider, côté serveur, les données soumises par le navigateur. Il est beaucoup plus difficile pour un hacker de tenter de débrayer une validation côté serveur. Il est donc impératif de toujours garantir qu'on vérifie les données côté serveur. Par contre, JSF ne produisait pas de code JavaScript pour compléter le processus de validation avec une couche côté client : dommage, cela aurait pu éviter des allers/retours inutiles vers le serveur tant que le formulaire n'est pas correctement renseigné.

Depuis 2014, HTML 5.0 a proposé des extensions, sur les tags HTML liés aux formulaires, permettant de simplifier considérablement la gestion de la validation côté client. Ces nouveautés HTML sont assez différentes, dans leurs mises en oeuvre, des choix fait sur JSF. Il n'est donc pas si simple de cumuler l'approche JSF avec l'approche HTML5. Il est important de noter que, comme l'approche utilisant JavaScript, il est extrêmement simple de désactiver les vérifications faites par le navigateur : les hackers peuvent se servir de ce point pour envoyer des données corrompues au serveur.

De mon point de vue, les deux approches sont complémentaires et intéressantes. Valider le formulaire côté client permet de limiter les allers/retours entre le navigateur et le serveur : tant que les données ne sont pas correctes, on réduit donc la charge du serveur et la consommation de la bande passante. Si l'utilisateur a tenté de tricher sur les données soumises au serveur, la validation côté serveur permet de sécuriser efficacement le formulaire.

Rappels sur la validation d'un formulaire en HTML 5

HTML5 a donc enrichie les tags de formulaires avec des nouveaux attributs (ou valeurs d'attributs) permettant de renforcer le contrôle des données saisies. En autre, HTML5 propose des nouveaux types de champs <input> :

Citons aussi quelques nouveaux attributs pouvant être utilisés sur vos champs <input> :

Le souci que je vois à utiliser ces possibilités, c'est que le rendu visuel des messages d'erreur est spécifique à chaque navigateur et surtout, ce rendu visuel est très différent de celui produit par la validation JSF. Plus tard dans ce document, je vous montrerai comment coupler la validation côté serveur avec une validation HTML5 côté client.

Rendre la saisie d'un champ obligatoire avec JSF

La première possibilité de validation, via l'API JSF, que je souhaite vous montrer consiste à rendre la saisie un champ du formulaire obligatoire. Cela passe par l'ajoute d'un attribut required sur vos tags JSF de saisie de valeurs. Voici un exemple de code.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
<h:form>
    <h:messages styleClass="errorBlock" /><br/>

    Login: 
    <h:inputText id="login" value="#{loginBean.login}" required="true" />
    <br/>

    Password:
    <h:inputSecret id="password" value="#{loginBean.password}" required="true" />
    <br/><br/>

    <h:commandButton action="#{loginBean.returnAction}" value="Connect" />
</h:form>
Rendre la saisie d'un champ JSF obligatoire
l'attribut JSF required agit uniquement côté serveur. Il ne produit pas l'attribut required HTML5 sur vos tags <input />.

Vous aurez noté la présence d'un tag <h:messages /> : il permet de concentrer les erreurs constatées en tête du formulaire. Il est possible d'appliquer une classe de style à ce composant (pour ma part, texte affiché en rouge). Il est aussi possible de contrôler comment vos erreurs seront restituées. Par défaut, c'est une liste à puces qui est produite, comme le montre la capture d'écran suivante.

Restitution des erreurs constatées.

Si vous souhaitez plutôt afficher vos messages d'erreur dans un tableau, fixez la valeur de l'attribut layout à table (par défaut, cet attribut est fixé à la valeur list).

 1 
<h:messages styleClass="errorBlock" layout="table" />
Affichage des erreurs dans un tableau

Il se peut que le message d'erreur produit ne pas convienne pas (personnellement, je pense que le nom technique du tag JSF n'a rien à faire dans le message d'erreur): dans ce cas, vous pouvez le modifier en rajoutant un attribut requiredMessage. Voici un petit exemple d'utilisation (ligne 6 et 11).

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
<h:form>
    <h:messages styleClass="errorBlock" /><br/>

    Login: 
    <h:inputText id="login" value="#{loginBean.login}" required="true" 
                 requiredMessage="La saisie du login est obligatoire !" />
    <br/>

    Password:
    <h:inputSecret id="password" value="#{loginBean.password}" required="true"
                   requiredMessage="La saisie du mot de passe est obligatoire !" />
    <br/><br/>

    <h:commandButton action="#{loginBean.returnAction}" value="Connect" />
</h:form>
Personnalisation des messages d'erreurs
il est possible d'internationaliser vos messages d'erreurs (les fournir dans différentes langues). Nous étudierons cette possibilité dans un futur chapitre de ce cours.

Voici le résultat produit en l'absence de texte saisie dans les champs du formulaire.

Je vous préfèrez avoir chaque message d'erreur à côté du champ de saisie qu'il lui est associé, il est possible d'utiliser des tags <h:message /> (sans s final) à la place du tag <h:messages />. Dans ce cas, chaque tag <h:message /> doit avoir un attribut for pour l'associer au champ de saisie correspondant.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
<h:form>
    Login: 
    <h:inputText id="login" value="#{loginBean.login}" required="true" 
                 requiredMessage="La saisie du login est obligatoire !" />
    <h:message for="login" styleClass="errorBlock" />
    <br/>

    Password:
    <h:inputSecret id="password" value="#{loginBean.password}" required="true"
                   requiredMessage="La saisie du mot de passe est obligatoire !" />
    <h:message for="password" styleClass="errorBlock" />
    <br/><br/>

    <h:commandButton action="#{loginBean.returnAction}" value="Connect" />
</h:form>
Un message d'errreur par champ de saisie

Et voici le résultat obtenu si le formulaire n'est pas correctement renseigné.

Utilisation des tags de validation JSF

Outre le fait de rendre un champ de saisie obligatoire, il existe divers tags JSF de validation des données renseignées. Voici une liste des principaux tags de validation JSF.

L'attribut for n'est pas obligatoire : si le tag de validation est placé dans le tag du champ de saisie, alors l'attachement est implicitement réalisé. Dans ce cas, n'oubliez pas de correctement terminer le tag correspondant au champ de saisie.

Vous pouvez contrôler le message d'erreur produit lors de la validation grâce à l'attribut validatorMessage de votre composant de saisie de texte.

Exemple d'utilisation d'un tag de validation

Commençons par un exemple de validation d'un mot de passe dont la longueur devra être comprise entre 3 à 12 caractères. Dans cet exemple, j'ai choisi de placer le tag de validation directement comme enfant du tag <h:inputSecret />.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
Password:
<h:inputSecret id="password" value="#{loginBean.password}" required="true"
               requiredMessage="La saisie du mot de passe est obligatoire !"
               validatorMessage="Votre mot de passe doit contenir entre 3 à 12 caractères">
    <f:validateLength minimum="3" maximum="12" />
</h:inputSecret>
<h:message for="password" styleClass="errorBlock" />
Exemple de contrôle sur la longueur d'un mot de passe (entre 3 et 12 caractères)

Exemple d'utilisation d'un tag de validation à base d'expression régulière

Voici un autre exemple d'utilisation d'un tag de validation : nous allons vérifier que le login saisi correspond bien au format d'une adresse email. Un tag de validation basé sur une expression régulière devrait faire l'affaire.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
Login: 
<h:inputText id="login" value="#{loginBean.login}" required="true"
             requiredMessage="La saisie du login est obligatoire !"
             validatorMessage="Le login doit correspondre à un email">
    <f:validateRegex pattern="^[\w.+-]+@[\w.+-]+\.[a-z]{2,}$" />
</h:inputText>
<h:message for="login" styleClass="errorBlock" />
<br/>
On vérifie si une chaîne de caractères respecte un format donné (ici un email).

Pour de plus amples informations sur la syntaxe des expressions régulières, je vous renvoie vers les chapitres relatifs à la mise en oeuvre d'expressions régulières en Java.

Voici les messages produits si vous ne renseignez pas correctement notre formulaire.

Mise en oeuvre de validateurs personnalisés

Il est possible de définir votre propre méthode de validation (du code Java) : cela se fait directement sur la classe de « backing bean » utilisée par votre formulaire. Une telle méthode doit respecter une signature bien précise imposée par le framework JSF. Dans l'exemple que je vous propose, on cherche à savoir si la donnée saisie contient bien un caractère #.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
public void validateAField(FacesContext context, UIComponent component, Object value) throws ValidatorException {
    String inputValue = (String) value;
    if ( ! inputValue.contains( "#" ) ) {
        FacesMessage msg = new FacesMessage( "Mauvais format : doit contenir un #" );
        msg.setSeverity( FacesMessage.SEVERITY_ERROR );
        throw new ValidatorException(msg);
    }
}
Exemple d'une méthode de validation personalisée

Et voici maintenant le code XML permettant de liée la validation de votre zone de saisie à la méthode de validation.

 1 
 2 
 3 
 4 
 5 
Truc : 
<h:inputText id="aField" requiredMessage="La saisie du champ est obligatoire !"
             validator="#{backingBean.validateAField}" />
<h:message for="aField" styleClass="errorBlock" />
<br/>
Liaison de la méthode de validation

Couper la validation du formulaire pour un bouton particulier

Imaginons que vous souhaitez ajouter un bouton (avec un traitement côté serveur) qui requière de ne pas exécuter la validation : par exemple un bouton « cancel ». Dans ce cas, il faudra lui rajouter un attribut supplémentaire pour couper la validation en cas de clic sur cet élément. Cet attribut se nomme immediate et peut valoir true ou false. Voici un exemple d'utilisation.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
<h:form>
    Login: 
    <h:inputText id="login" value="#{loginBean.login}" required="true"
                 requiredMessage="La saisie du login est obligatoire !" />
    <h:message for="login" styleClass="errorBlock" />
    <br/>
    
    Password:
    <h:inputSecret id="password" value="#{loginBean.password}" required="true"
                   requiredMessage="La saisie du mot de passe est obligatoire !" />
    <h:message for="password" styleClass="errorBlock" />
    <br/><br/>
    
    <h:commandButton action="#{loginBean.returnAction}" value="Connect" />
    <br/>
    <h:commandButton action="#{loginBean.cancelAction}" value="Cancel" immediate="true" />
</h:form>
On coupe la validation pour un bouton particulier (cancel)
pour fonctionner correctement, cet exemple nécessite de rajouter l'action cancelAction (une simple méthode) sur votre classe de « backing bean ».

Activation du support HTML5 de validation des champs du formulaire

Deux techniques peuvent permettre de coupler le support HTML5 de validation de formulaire avec JSF. Dans les deux cas, cela passe par l'utilisation d'une taglib (librairie de tags) particulière.

Utilisation de la taglib http://xmlns.jcp.org/jsf/passthrough

Si vous le souhaitez, le framework JSF propose une extension permettant de contrôler la production d'attributs HTML5 sur vos champs de saisie. Pour profiter de cette extension, il faut ajouter une taglib supplémentaire à votre page JSF : http://xmlns.jcp.org/jsf/passthrough. Je vous propose d'associer cette taglib au préfixe p (voir ligne 4). L'exemple suivant vous montre la mise en oeuvre de cette possibilité.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
<!DOCTYPE html>
<html xmlns:f="http://xmlns.jcp.org/jsf/core" 
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:p="http://xmlns.jcp.org/jsf/passthrough">
    <f:view>
        <head>
            <title>Login screen</title>
            <link rel="stylesheet" type="text/css" href="../styles.css" />
        </head>
        <body>
            <h1>Login screen</h1>
                    
            <h:form>
                Login: 
                <h:inputText id="login" value="#{loginBean.login}" 
                             required="true" p:required="true" 
                             requiredMessage="La saisie du login est obligatoire !" />
                <h:message for="login" styleClass="errorBlock" />
                <br/>
                
                Password:
                <h:inputSecret id="password" value="#{loginBean.password}"
                               required="true" p:required="true" 
                               requiredMessage="La saisie du mot de passe est obligatoire !" />
                <h:message for="password" styleClass="errorBlock" />
                <br/><br/>
                
                <h:commandButton action="#{loginBean.returnAction}" value="Connect" />
                
           </h:form>
        </body>
    </f:view>
</html>
Combinaison des techniques JSF et HTML5 pour la validation de vos formulaires
vous pouvez aussi utiliser p:placeholder="requis" pour afficher un message dans un champ de saisi si celui n'est pas encore renseigné.
il est important de constater que la manière de vous informer d'un problème diffère (visuellement) entre les deux mécanismes de validation.

Utilisation de la taglib http://xmlns.jcp.org/jsf

La seconde technique consiste à transformer un simple tag HTML en un élément JSF assujetti au cycle de vie (côté serveur) d'un composant JSF. Cela se fait en changeant la taglib http://xmlns.jcp.org/jsf, traditionnellement associée au préfixe jsf. Ainsi, vous pourrez associer les deux aspects (client et serveur) de validation du champ considéré. Voici un petit exemple d'utilisation.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
<!DOCTYPE html>
<html xmlns:f="http://xmlns.jcp.org/jsf/core" 
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:jsf="http://xmlns.jcp.org/jsf">
    <f:view>
        <head>
            <title>Login screen</title>
            <link rel="stylesheet" type="text/css" href="../styles.css" />
        </head>
        <body>
            <h1>Login screen</h1>
                    
            <h:form>
                Login: 
                <input jsf:id="login" jsf:value="#{loginBean.login}" type="text"
                       jsf:required="true" required="required" 
                       jsf:requiredMessage="La saisie du login est obligatoire !" />
                <h:message for="login" styleClass="errorBlock" />
                <br/>
                
                Password:
                <input jsf:id="password" jsf:value="#{loginBean.password}" type="password"
                       jsf:required="true" required="required" 
                       jsf:requiredMessage="La saisie du mot de passe est obligatoire !" />
                <h:message for="password" styleClass="errorBlock" />
                <br/><br/>
                
                <input type="submit" jsf:action="#{loginBean.returnAction}" value="Connect" />
                
           </h:form>
        </body>
    </f:view>
</html>
Seconde approche de combinaison des techniques JSF et HTML5 pour la validation de vos formulaires
en HTML5, on peut dire que la saisie d'un champ est obligatoire en ajoutant l'attribut required sans lui fixer valeur ou bien en lui donnant la valeur required (required="required"). La technologie Facelet, utilisée par JSF, étant basée sur du XML, la première proposition ne peut pas fonctionner. Vous êtes donc obligé d'y définir cet attribut ainsi : required="required".
pour que le moteur JSF puisse correctement gérer ce code, il lui faut impérativement être capable d'identifier la nature de chaque input de votre formulaire. Même si par défaut, en HTML et en l'absence de l'attribut type, un champ de saisie est considéré de type text, il est obligatoire de le préciser pour JSF (attribute type="text" en ligne 15 de l'exemple précédent). Dans le cas contraire, le champ sera purement et simplement ignoré par JSF.

Technique de hacking pour débrayer la validation côté client

Si vous souhaitez tester une tentative de triche au niveau du code HTML, lancer la page Web dans votre navigateur puis appuyez sur la touche F12. Les outils de développement devraient apparaître comme le montre la capture d'écran ci-dessous.

Une fois les outils de développement du navigateur affichés, ouvrez bien l'onglet « Elements » puis veuillez suivre les étapes suivantes :

  1. Cliquez une fois sur le bouton « Select an element in the page and inspect it ». Point 1, dans la capture d'écran.

  2. Puis sélectionnez le champ <input /> sur lequel vous souhaiter travailler. Pour complétement supprimer la validation sur le formulaire, il faudra répéter la procédure pour le login et le mot de passe.

  3. Dans la partie inférieure, localisez l'attribut required et double-cliquez dessus pour entrer en mode édition. Supprimer totalement l'attribut et sa valeur.

  4. Fermer les outils de développement et soumettre le formulaire. Si tout se passe bien, notre validation côté serveur doit rattraper la situation.

la procédure ci-dessus est donnée pour le navigateur Chrome. Pour autant, chaque navigateur vous propose des outils équivalents et vous ne devriez pas rencontrer de difficulté pour arriver au même résultat.


Votre première page JSF Validation d'un formulaire JSF par annotations