spring
Validation du haricot JSR 303 au printemps
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;
}