Qu'indique l'annotation @Valid dans Spring?

87

Dans l'exemple suivant, le ScriptFileparamètre est marqué d'une @Validannotation.

Que fait l' @Validannotation?

@RequestMapping(value = "/scriptfile", method = RequestMethod.POST)    
public String create(@Valid ScriptFile scriptFile, BindingResult result, ModelMap modelMap) {    
    if (scriptFile == null) throw new IllegalArgumentException("A scriptFile is required");        
    if (result.hasErrors()) {        
        modelMap.addAttribute("scriptFile", scriptFile);            
        modelMap.addAttribute("showcases", ShowCase.findAllShowCases());            
        return "scriptfile/create";            
    }        
    scriptFile.persist();        
    return "redirect:/scriptfile/" + scriptFile.getId();        
}    
Gary Ford
la source

Réponses:

63

C'est à des fins de validation.

Validation Il est courant de valider un modèle après y avoir lié l'entrée utilisateur. Spring 3 prend en charge la validation déclarative avec JSR-303. Cette prise en charge est activée automatiquement si un fournisseur JSR-303, tel que Hibernate Validator, est présent sur votre chemin de classe. Lorsqu'il est activé, vous pouvez déclencher la validation simplement en annotant un paramètre de méthode Controller avec l'annotation @Valid: Après avoir lié les paramètres POST entrants, le AppointmentForm sera validé; dans ce cas, pour vérifier que la valeur du champ de date n'est pas nulle et se produit dans le futur.


Regardez ici pour plus d'informations:
http://blog.springsource.com/2009/11/17/spring-3-type-conversion-and-validation/

mhshams
la source
36

En ajoutant aux réponses ci-dessus, jetez un œil à ce qui suit. AppointmentFormLa datecolonne de est annotée avec quelques annotations. En ayant une @Validannotation qui déclenche des validations sur le AppointmentForm(dans ce cas @NotNullet @Future). Ces annotations peuvent provenir de différents fournisseurs JSR-303 (par exemple, Hibernate, Spring..etc).

    @RequestMapping(value = "/appointments", method = RequestMethod.POST)
    public String add(@Valid AppointmentForm form, BindingResult result) {
        ....
    }

    static class AppointmentForm {

        @NotNull @Future
        private Date date;
    }
Charith De Silva
la source
1
J'ai un code similaire. J'avais supprimé @Validle ApplicationFormparamètre mais les validations étaient toujours déclenchées sur datele nullchamp (défini comme ). S'il vous plaît, expliquez.
lupchiazoem
17

IIRC @Valid n'est pas une annotation Spring mais une annotation JSR-303 (qui est le standard de validation de Bean). En gros, il vérifie si les données que vous envoyez à la méthode sont valides ou non (il validera le scriptFile pour vous).

Mateusz Dymczyk
la source
2
Que signifie «cela validera le scriptFile pour vous»? Vérifiez qu'il n'est pas nul, qu'il a une syntaxe ou un contenu? En d'autres termes, qu'est-ce que cela valide et comment? L'utilisateur doit-il implémenter quelque chose? Où puis-je obtenir des informations à ce sujet? Merci!
nephewtom le
Veuillez répondre à la question de @ nephewtom, ce n'est pas une réponse suffisante pour valider avec le point principal manquant qui est "contre quoi"?
monami
17

@Validen soi n'a rien à voir avec le printemps. Cela fait partie de la spécification Bean Validation (il y en a plusieurs, le dernier étant le JSR 380 au second semestre 2017), mais il @Validest très ancien et dérive entièrement de JSR 303.

Comme nous le savons tous, Spring est très efficace pour intégrer toutes les bibliothèques JSR et java en général (pensez à JPA, JTA, Caching, etc.) et bien sûr, ces gars-là se sont également occupés de la validation. L'un des composants clés qui facilite cela est MethodValidationPostProcessor .

Essayer de répondre à votre question @Validest très pratique pour ce que l'on appelle la validation en cascade lorsque vous souhaitez valider un graphique complexe et pas seulement des éléments de premier niveau d'un objet. Chaque fois que vous voulez aller plus loin, vous devez utiliser @Valid. C'est ce que dicte JSR. Spring se conformera à cela avec quelques écarts mineurs (par exemple, j'ai essayé de mettre à la @Validatedplace de la @Validméthode RestController et la validation fonctionne, mais la même chose ne s'appliquera pas pour un beans "service" réguliers).

yuranos
la source
Mais qu'est-ce qui valide?
nephewtom le
Veuillez préciser, @nephewtom. Que souhaitez-vous clarifier?
yuranos
J'ai lu JSR 303: Bean Validation, beanvalidation.org/1.0/spec mais je n'obtiens toujours pas sur quelle validation sera effectuée ScriptFile scriptFile.
nephewtom
ScriptFile à l'intérieur contient probablement un tas de champs et ces champs ont également des annotations. C'est là que la validation entre en jeu. Sur la base de la question d'origine, il n'est pas clair ce qu'il y a exactement à l'intérieur de la classe ScriptFile.
yuranos
OK merci. Pourriez-vous mettre un exemple de ce qui pourrait valider si ses champs étaient une chaîne, un entier et un bean?
nephewtom
2
public String create(@Valid @NotNull ScriptFile scriptFile, BindingResult result, ModelMap modelMap) {    
    if (scriptFile == null) throw new IllegalArgumentException("A scriptFile is required");        

Je suppose que cette @NotNullannotation est valide si la condition n'est pas nécessaire.

mzlobecki
la source
1

En ajoutant simplement à la réponse ci-dessus, dans une application Web @validest utilisée où le bean à valider est également annoté avec des annotations de validation @NotNull, par exemple @Email(annotation d'hibernation), donc lors de l'obtention de l'entrée de l'utilisateur, les valeurs peuvent être validées et le résultat de la liaison aura la validation résultats. bindingResult.hasErrors()dira si une validation a échoué.

puneet goyal
la source
1

Un autre aspect pratique de @Valid non mentionné ci-dessus est que (c'est-à-dire en utilisant Postman pour tester un point de terminaison) @Valid formatera la sortie d'un appel REST incorrect en JSON formaté au lieu d'un blob de texte à peine lisible. Ceci est très utile si vous créez une API commercialement consommable pour vos utilisateurs.

Sean Gildea
la source
0

Je pense savoir où va votre question. Et comme cette question est celle qui apparaît dans les principaux résultats de recherche de Google, je peux donner une réponse claire sur ce que fait l'annotation @Valid.

Je vais présenter 3 scénarios sur la façon dont j'ai utilisé @Valid

Modèle:

public class Employee{
private String name;
@NotNull(message="cannot be null")
@Size(min=1, message="cannot be blank")
private String lastName;
 //Getters and Setters for both fields.
 //...
}

JSP:

...
<form:form action="processForm" modelAttribute="employee">
 <form:input type="text" path="name"/>
 <br>
 <form:input type="text" path="lastName"/>
<form:errors path="lastName"/>
<input type="submit" value="Submit"/>
</form:form>
...

Contrôleur pour le scénario 1:

     @RequestMapping("processForm")
        public String processFormData(@Valid @ModelAttribute("employee") Employee employee){
        return "employee-confirmation-page";
    }

Dans ce scénario, après avoir soumis votre formulaire avec un champ lastName vide, vous obtiendrez une page d'erreur puisque vous appliquez des règles de validation mais que vous ne le gérez pas du tout.

Exemple de ladite erreur: page d'exception

Contrôleur pour le scénario 2:

 @RequestMapping("processForm")
    public String processFormData(@Valid @ModelAttribute("employee") Employee employee,
BindingResult bindingResult){
                return bindingResult.hasErrors() ? "employee-form" : "employee-confirmation-page";
            }

Dans ce scénario, vous transmettez tous les résultats de cette validation à bindingResult, c'est donc à vous de décider quoi faire avec les résultats de validation de ce formulaire.

Contrôleur pour le scénario 3:

@RequestMapping("processForm")
    public String processFormData(@Valid @ModelAttribute("employee") Employee employee){
                return "employee-confirmation-page";
            }
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, String> invalidFormProcessor(MethodArgumentNotValidException ex){
  //Your mapping of the errors...etc
}

Dans ce scénario, vous ne gérez toujours pas les erreurs comme dans le premier scénario, mais vous le transmettez à une autre méthode qui prendra en charge l'exception que @Valid déclenche lors du traitement du modèle de formulaire. Vérifiez ceci pour voir quoi faire avec la cartographie et tout ça.

Pour résumer : @Valid seul avec ne rien faire de plus qui déclenche la validation des champs annotés JSR 303 de validation ( @NotNull, @Email, @Size, etc ... ), il vous reste à spécifier une stratégie de ce qu'il faut faire avec les résultats de ladite validation.

J'espère que j'ai pu dégager quelque chose pour les gens qui pourraient trébucher avec ça.

Alan Balderas Sánchez
la source