spring
Spring JSR 303 Bean Validation
Ricerca…
introduzione
Spring ha il supporto per la validazione del bean JSR303. Possiamo usarlo per fare la convalida del bean di input. Logica di convalida separata dalla logica aziendale utilizzando JSR303.
JSR303 Validazioni basate su annotazioni negli esempi di Springs
Aggiungere qualsiasi implementazione JSR 303 al classpath. Quello più usato è il validatore Hibernate di Hibernate.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.2.0.Final</version>
</dependency>
Diciamo che c'è una pausa per creare utenti nel sistema
@RequestMapping(value="/registeruser", method=RequestMethod.POST)
public String registerUser(User user);
L'esempio di input json sarà simile a quello seguente
{"username" : "[email protected]", "password" : "password1", "password2":"password1"}
User.java
public class User {
private String username;
private String password;
private String password2;
getXXX and setXXX
}
Possiamo definire le convalide JSR 303 sulla classe utente come di seguito.
public class User {
@NotEmpty
@Size(min=5)
@Email
private String username;
@NotEmpty
private String password;
@NotEmpty
private String password2;
}
Potremmo anche aver bisogno di avere un validatore aziendale come password e password2 (conferma password) uguali, per questo possiamo aggiungere un validatore personalizzato come di seguito. Scrivi un'annotazione personalizzata per annotare il campo dati.
@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 {};
}
Scrivi una classe Validator per applicare la logica di convalida.
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());
}
}
Aggiunta di questa convalida a User Class
@GoodPassword
public class User {
@NotEmpty
@Size(min=5)
@Email
private String username;
@NotEmpty
private String password;
@NotEmpty
private String password2;
}
@Valid convalida dei trigger in primavera. BindingResult è un oggetto iniettato dalla molla che ha una lista di errori dopo la validazione.
public String registerUser(@Valid User user, BindingResult result);
L'annotazione JSR 303 contiene attributi di messaggi che possono essere utilizzati per fornire messaggi personalizzati.
@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;
}
Convalida Spring JSR 303 - Personalizza i messaggi di errore
Supponiamo di avere una semplice classe con annotazioni di validazione
public class UserDTO {
@NotEmpty
private String name;
@Min(18)
private int age;
//getters/setters
}
Un controller per verificare la validità di 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);
}
}
E 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"));
}
Sia il nome che l'età non sono validi, pertanto in BindingResult sono presenti due errori di convalida. Ognuno ha una serie di codici.
Codici per il controllo min
0 = "Min.userDTO.age"
1 = "Min.age"
2 = "Min.int"
3 = "Min"
E per il controllo NotEmpty
0 = "NotEmpty.userDTO.name"
1 = "NotEmpty.name"
2 = "NotEmpty.java.lang.String"
3 = "NotEmpty"
Aggiungiamo un file custom.properties per sostituire i messaggi predefiniti.
@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);
}
}
Se aggiungiamo al file custom.properties la riga
NotEmpty=The field must not be empty!
Il nuovo valore è mostrato per l'errore. Per risolvere il messaggio di validatore guarda attraverso i codici a partire dall'inizio per trovare i messaggi corretti.
Pertanto, quando definiamo la chiave NotEmpty
nel file .properties per tutti i casi in cui viene utilizzata l'annotazione @NotEmpty
viene applicato il nostro messaggio.
Se definiamo un messaggio
Min.int=Some custom message here.
Tutte le annotazioni in cui la nostra app verifica i valori integer utilizzano il messaggio appena definito.
La stessa logica potrebbe essere applicata se abbiamo bisogno di localizzare i messaggi di errore di convalida.
@Valore valido per convalidare POJO nidificati
Supponiamo di avere un utente della classe POJO che dobbiamo convalidare.
public class User {
@NotEmpty
@Size(min=5)
@Email
private String email;
}
e un metodo di controllo per convalidare l'istanza utente
public String registerUser(@Valid User user, BindingResult result);
Estendiamo l'utente con un indirizzo POJO nidificato che dobbiamo anche convalidare.
public class Address {
@NotEmpty
@Size(min=2, max=3)
private String countryCode;
}
Basta aggiungere annotazione @Valid
sul campo indirizzo per eseguire la convalida dei POJO nidificati.
public class User {
@NotEmpty
@Size(min=5)
@Email
private String email;
@Valid
private Address address;
}