spring
Wiosenna walidacja fasoli JSR 303
Szukaj…
Wprowadzenie
Wiosna ma obsługę sprawdzania poprawności komponentu JSR303. Możemy to wykorzystać do sprawdzenia poprawności komponentu bean. Oddziel logikę sprawdzania poprawności od logiki biznesowej za pomocą JSR303.
JSR303 Sprawdzanie poprawności oparte na adnotacjach w przykładach Springs
Dodaj dowolną implementację JSR 303 do ścieżki klasy. Popularnym jest walidator Hibernacja od Hibernacji.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.2.0.Final</version>
</dependency>
Powiedzmy, że istnieje interfejs API umożliwiający utworzenie użytkownika w systemie
@RequestMapping(value="/registeruser", method=RequestMethod.POST)
public String registerUser(User user);
Próbka wejściowa json wyglądałaby jak poniżej
{"username" : "[email protected]", "password" : "password1", "password2":"password1"}
User.java
public class User {
private String username;
private String password;
private String password2;
getXXX and setXXX
}
Możemy zdefiniować walidacje JSR 303 w klasie użytkownika, jak poniżej.
public class User {
@NotEmpty
@Size(min=5)
@Email
private String username;
@NotEmpty
private String password;
@NotEmpty
private String password2;
}
Może być też konieczne, aby walidator biznesowy, taki jak hasło i hasło2 (potwierdź hasło) są takie same, w tym celu możemy dodać niestandardowy walidator, jak poniżej. Napisz niestandardową adnotację do opisu pola danych.
@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 {};
}
Napisz klasę walidatora do stosowania logiki walidacji.
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());
}
}
Dodanie tej weryfikacji do klasy użytkownika
@GoodPassword
public class User {
@NotEmpty
@Size(min=5)
@Email
private String username;
@NotEmpty
private String password;
@NotEmpty
private String password2;
}
@ Ważny uruchamia sprawdzanie poprawności wiosną. BindingResult to obiekt wstrzykiwany przez sprężynę, który ma listę błędów po sprawdzeniu poprawności.
public String registerUser(@Valid User user, BindingResult result);
Adnotacja JSR 303 zawiera atrybuty wiadomości, których można używać do dostarczania wiadomości niestandardowych.
@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 - Dostosuj komunikaty o błędach
Załóżmy, że mamy prostą klasę z adnotacjami sprawdzania poprawności
public class UserDTO {
@NotEmpty
private String name;
@Min(18)
private int age;
//getters/setters
}
Kontroler do sprawdzania ważności 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);
}
}
I 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"));
}
Zarówno imię, jak i wiek są nieprawidłowe, więc w BindingResult mamy dwa błędy sprawdzania poprawności. Każdy ma szereg kodów.
Kody kontroli min
0 = "Min.userDTO.age"
1 = "Min.age"
2 = "Min.int"
3 = "Min"
I dla czeku NotEmpty
0 = "NotEmpty.userDTO.name"
1 = "NotEmpty.name"
2 = "NotEmpty.java.lang.String"
3 = "NotEmpty"
Dodajmy plik custom.properties, aby zastąpić komunikaty domyślne.
@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);
}
}
Jeśli dodamy do pliku custom.properties linię
NotEmpty=The field must not be empty!
Nowa wartość jest wyświetlana dla błędu. Aby rozwiązać problem, sprawdzacz poprawności przegląda kody od początku, aby znaleźć odpowiednie komunikaty.
Tak więc, gdy definiujemy NotEmpty
klucz w pliku .properties wszystkich przypadkach, w których @NotEmpty
służy adnotacja stosowana jest nasze przesłanie.
Jeśli zdefiniujemy wiadomość
Min.int=Some custom message here.
Wszystkie adnotacje, w których sprawdzamy min. Wartości całkowite, używają nowo zdefiniowanej wiadomości.
Tę samą logikę można zastosować, jeśli musimy zlokalizować komunikaty o błędach sprawdzania poprawności.
@ Prawidłowe użycie do sprawdzania zagnieżdżonych POJO
Załóżmy, że mamy użytkownika klasy POJO, który musimy zweryfikować.
public class User {
@NotEmpty
@Size(min=5)
@Email
private String email;
}
oraz metoda kontrolera do sprawdzania poprawności instancji użytkownika
public String registerUser(@Valid User user, BindingResult result);
Rozszerzmy użytkownika o zagnieżdżony adres POJO, który również musimy zweryfikować.
public class Address {
@NotEmpty
@Size(min=2, max=3)
private String countryCode;
}
Wystarczy dodać adnotację @Valid
w polu adresu, aby uruchomić sprawdzanie poprawności zagnieżdżonych POJO.
public class User {
@NotEmpty
@Size(min=5)
@Email
private String email;
@Valid
private Address address;
}