Validation automatique des données saisies avec HTML5 et Spring3
J’ai appris il y a longtemps qu’il était toujours nécessaire de contrôler et valider les données saisies par vos utilisateurs, du côté client comme du côté serveur (en HTML/JavaScript et en Java pour ma part), car généralement les erreurs ou les attaques viennent de là. Je n’ai jamais apprécié personnellement cette partie du travail car c’est à chaque fois la même chose et à chaque fois on doit tout refaire à la main …

Validation côté client (HTML5)
Avec HTML5 la validation de surface se fait déjà plus aisément, les nombreux « type » paramétrable dans nos champs de saisie limitent considérablement la saisie au mauvais format, exemple : , , , … (liste complète ici avec support des différents navigateurs).
Ensuite de nouveaux attributs ont vu le jour comme required, min, max, list … qui nous évitent de devoir contrôler que le champ est bien saisi, qu’il est compris dans un intervalle donné ou bien qu’il fait partie d’une liste prédéfinie de valeurs.
Dans mon nouveau projet j’utilise HTML5 comme validateur client de surface plutôt que JavaScript.
Les données envoyées au serveur sont au format JSON, la transformation de mon formulaire en objet JSON est faite avec form2js et l’envoi se fait avec jQuery de la façon suivante :
$("form").submit(function(event) {
var action = $(this).attr('action');
var formAsObject = $(this).toObject(); // form2js
$.ajax({
url: action,
type: "post",
data: formAsObject,
dataType: 'json',
success: function(jsonFromServer) {
// callback du serveur
}
});
return false;
});A retenir : il faut utiliser la méthode « submit » de jQuery sur le formulaire plutôt que la méthode « on » ou « bind » sur le bouton submit car sinon la validation des données en HTML5 ne se fera pas.
Validation côté serveur (Spring3)
C’est là que Spring3 entre en jeu ainsi que ses nombreuses annotations qui nous facilitent la tâche, dans notre cas je parle de @ModelAttribute et @Validated.
@RequestMapping(value="/login", method=RequestMethod.POST)
@ResponseBody
public UserModel login(@Validated({ UserLoginGroup.class }) @ModelAttribute UserModel user, BindingResult result, HttpServletRequest request, HttpServletResponse response) {
// validation de surface faite avec @annotations
if (result.hasErrors()) {
// des erreurs de validation
} else {
// aucune erreur de validation en surface
}
}La première (@ModelAttribute) permet de transformer automatiquement l’objet json envoyé par notre requête Ajax en objet Java : chaque attribut de l’objet json ayant le même nom (case sensitive) qu’un attribut de l’objet Java sera récupéré automatiquement.
La seconde (@Validated) indique que l’objet annoté doit être validé, la validation est écrite uniquement via des annotations, il en va de même pour les messages d’erreur à retourner. J’utilise les annotations de Hibernate Validator qui offrent un plus grand choix, allant de @Email à @NotBlank en passant par @Future pour valider que la date saisie est dans le futur.
Malheureusement il n’existe encore aucun moyen nativement de comparer deux attributs de l’objet à valider, par exemple « email » et « emailConfirm » ou encore « password » et « passwordConfirm », la communauté s’en est chargé en créant une annotation maison « FieldMatch » que j’utilise et qui marche à merveille, voici le lien vers cette annotation.
Vous l’avez compris, avec Spring3 la validation côté serveur est rendue très simple, voici un copier coller d’un objet que je valide automatiquement avec cette méthode :
@FieldMatch.List({
@FieldMatch(first = "password", second = "passwordConfirm", message = "Votre confirmation de mot de passe est invalide", groups = { UserRegisterGroup.class }),
@FieldMatch(first = "email", second = "emailConfirm", message = "Votre confirmation d'email est invalide", groups = { UserRegisterGroup.class })
})
public class UserModel implements Serializable {
private static final long serialVersionUID = -6014837207296264624L;
@NotBlank(message = "Votre email est obligatoire", groups = { UserLoginGroup.class, UserRegisterGroup.class, UserLostPasswordGroup.class })
@Email(message = "Votre email a un format incorrect", groups = { UserLoginGroup.class, UserRegisterGroup.class, UserLostPasswordGroup.class })
@Length(min=3, max=100, message = "Votre email doit faire entre 3 et 100 caractères", groups = { UserLoginGroup.class, UserRegisterGroup.class, UserLostPasswordGroup.class })
private String email;
// FieldMatch suffit pour les contrôles
private String emailConfirm;
@NotBlank(message = "Votre mot de passe est obligatoire", groups = { UserLoginGroup.class, UserRegisterGroup.class })
@Length(min=6, max=100, message = "Votre mot de passe doit faire entre 6 et 100 caractères", groups = { UserLoginGroup.class, UserRegisterGroup.class })
private String password;
// FieldMatch suffit pour les contrôles
private String passwordConfirm;
Suite de l'article :
Après :
18 avril 2012
16h02
15h55
14h07
14h06
13h56
13h00
11h55
11h40
11h11
10h41
9h59
8h26
7h05
5h49
3h59
3h56
17 avril 2012
21h43
20h38
17h28
17h13
15h39
14h23
14h12
13h22
13h21
13h17
12h44
12h31
12h30
12h14
11h48
11h34
11h02
11h01
10h06
10h01
9h14
9h10
8h50
2h28
16 avril 2012
20h42
20h13
18h57

