Recherche…


Introduction

Spring a le support de validation du haricot JSR303. Nous pouvons l'utiliser pour faire la validation des beans d'entrée. Séparez la logique de validation de la logique métier à l'aide de JSR303.

JSR303 Validation basée sur des annotations dans des exemples de ressorts

Ajoutez toute implémentation JSR 303 à votre chemin de classe. Le plus utilisé est le validateur Hibernate de Hibernate.

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>4.2.0.Final</version>
</dependency>

Disons qu'il y a un api de repos pour créer un utilisateur dans le système

@RequestMapping(value="/registeruser", method=RequestMethod.POST)
public String registerUser(User user);

L’échantillon json d’entrée ressemblerait à celui ci-dessous

{"username" : "[email protected]", "password" : "password1", "password2":"password1"}

User.java

public class User {

    private String username;
    private String password;
    private String password2;

    getXXX and setXXX

}

Nous pouvons définir les validations JSR 303 sur la classe d’utilisateur ci-dessous.

public class User {

    @NotEmpty
    @Size(min=5)
    @Email
    private String username;
    
    @NotEmpty
    private String password;
    
    @NotEmpty
    private String password2;

}

Nous pouvons également avoir besoin d'un validateur d'entreprise comme le mot de passe et le mot de passe2 (confirmer le mot de passe) sont les mêmes, pour cela nous pouvons ajouter un validateur personnalisé comme ci-dessous. Ecrivez une annotation personnalisée pour annoter le champ de données.

@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PasswordValidator.class)
public @interface GoodPassword {
    String message() default "Passwords wont match.";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Ecrivez une classe de validateur pour appliquer la logique de validation.

public class PastValidator implements ConstraintValidator<GoodPassword, User> {
    @Override
    public void initialize(GoodPassword annotation) {}
    
    @Override
    public boolean isValid(User user, ConstraintValidatorContext context) {
        return user.getPassword().equals(user.getPassword2());
    }
}

Ajout de cette validation à la classe d'utilisateurs

@GoodPassword
public class User {

    @NotEmpty
    @Size(min=5)
    @Email
    private String username;
    
    @NotEmpty
    private String password;
    
    @NotEmpty
    private String password2;
}

@Valid déclenche la validation au printemps. BindingResult est un objet injecté par Spring qui a la liste des erreurs après validation.

public String registerUser(@Valid User user, BindingResult result);

L'annotation JSR 303 contient des attributs de message qui peuvent être utilisés pour fournir des messages personnalisés.

@GoodPassword
public class User {

    @NotEmpty(message="Username Cant be empty")
    @Size(min=5, message="Username cant be les than 5 chars")
    @Email(message="Should be in email format")
    private String username;
    
    @NotEmpty(message="Password cant be empty")
    private String password;
    
    @NotEmpty(message="Password2 cant be empty")
    private String password2;

}

Spring JSR 303 Validation - Personnalisez les messages d'erreur

Supposons que nous ayons une classe simple avec des annotations de validation

public class UserDTO {
    @NotEmpty
    private String name;

    @Min(18)
    private int age;

//getters/setters
}

Un contrôleur pour vérifier la validité de UserDTO.

@RestController
public class ValidationController {

    @RequestMapping(value = "/validate", method = RequestMethod.POST)
    public ResponseEntity<String> check(@Valid @RequestBody UserDTO userDTO,
           BindingResult bindingResult) {
        return new ResponseEntity<>("ok" , HttpStatus.OK);
    }
}

Et un test

@Test
public void testValid() throws Exception {
    TestRestTemplate template = new TestRestTemplate();
    String url = base + contextPath + "/validate";
    Map<String, Object> params = new HashMap<>();
    params.put("name", "");
    params.put("age", "10");

    MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
    headers.add("Content-Type", "application/json");

    HttpEntity<Map<String, Object>> request = new HttpEntity<>(params, headers);
    String res = template.postForObject(url, request, String.class);

    assertThat(res, equalTo("ok"));
}

Le nom et l'âge ne sont pas valides. Dans le BindingResult, nous avons deux erreurs de validation. Chacun a un tableau de codes.

Codes pour vérification min.

0 = "Min.userDTO.age"
1 = "Min.age"
2 = "Min.int"
3 = "Min"

Et pour le chèque NotEmpty

0 = "NotEmpty.userDTO.name"
1 = "NotEmpty.name"
2 = "NotEmpty.java.lang.String"
3 = "NotEmpty"

Ajoutons un fichier custom.properties pour remplacer les messages par défaut.

@SpringBootApplication
@Configuration
public class DemoApplication {

    @Bean(name = "messageSource")
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource bean = new ReloadableResourceBundleMessageSource();
        bean.setBasename("classpath:custom");
        bean.setDefaultEncoding("UTF-8");
        return bean;
    }

    @Bean(name = "validator")
    public LocalValidatorFactoryBean validator() {
        LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
        bean.setValidationMessageSource(messageSource());
        return bean;
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

Si nous ajoutons au fichier custom.properties la ligne

NotEmpty=The field must not be empty!

La nouvelle valeur est affichée pour l'erreur. Pour résoudre le message, le validateur examine les codes en commençant par le début pour trouver les messages appropriés.

Ainsi, lorsque nous définissons la clé NotEmpty dans le fichier .properties pour tous les cas où l'annotation @NotEmpty est utilisée, notre message est appliqué.

Si on définit un message

Min.int=Some custom message here.

Toutes les annotations où nous appliquons min check à des valeurs entières utilisent le message nouvellement défini.

La même logique pourrait être appliquée si nous devons localiser les messages d'erreur de validation.

Utilisation de @Valid pour valider les POJO imbriqués

Supposons que nous ayons un utilisateur de classe POJO que nous devons valider.

public class User {

    @NotEmpty
    @Size(min=5)
    @Email
    private String email;
}

et une méthode de contrôleur pour valider l'instance d'utilisateur

public String registerUser(@Valid User user, BindingResult result);

Étendons l'utilisateur avec une adresse POJO imbriquée que nous devons également valider.

public class Address {

    @NotEmpty
    @Size(min=2, max=3)
    private String countryCode;
}

Ajoutez @Valid annotation @Valid le champ d'adresse pour exécuter la validation des POJO imbriqués.

public class User {

    @NotEmpty
    @Size(min=5)
    @Email
    private String email;

    @Valid
    private Address address;
}


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow