W poniższym przykładzie ScriptFile
parametr jest oznaczony @Valid
adnotacją.
Co robi @Valid
adnotacja?
@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();
}
źródło
@Valid
naApplicationForm
parametr, ale nadal validations padły nadate
(ustawionej jakonull
) pola. Proszę wytłumacz.@Valid
samo w sobie nie ma nic wspólnego ze Springiem. Jest to część specyfikacji Bean Validation (jest ich kilka, najnowsza to JSR 380 na drugą połowę 2017 roku), ale@Valid
jest bardzo stara i wywodzi się w całości z JSR 303.Jak wszyscy wiemy, Spring jest bardzo dobry w zapewnianiu integracji ze wszystkimi różnymi JSR i ogólnie bibliotekami java (pomyśl o JPA, JTA, buforowaniu itp.) I oczywiście ci faceci zadbali również o walidację. Jednym z kluczowych składników, który to ułatwia, jest MethodValidationPostProcessor .
Próba odpowiedzi na Twoje pytanie -
@Valid
jest bardzo przydatna w przypadku tzw. Kaskadowania walidacji, gdy chcesz zweryfikować złożony wykres, a nie tylko elementy obiektu najwyższego poziomu. Za każdym razem, gdy chcesz wejść głębiej, musisz użyć@Valid
. Tak nakazuje JSR. Spring dostosuje się do tego z pewnymi drobnymi odchyleniami (np. Próbowałem@Validated
zamiast@Valid
RestController wstawić metodę i walidację, ale to samo nie będzie dotyczyło zwykłych "usługowych" fasoli).źródło
ScriptFile scriptFile
.IIRC @Valid nie jest adnotacją Spring, ale adnotacją JSR-303 (która jest standardem Bean Validation). Po prostu sprawdza, czy dane wysyłane do metody są prawidłowe, czy nie (zweryfikuje plik scriptFile za Ciebie).
źródło
public String create(@Valid @NotNull ScriptFile scriptFile, BindingResult result, ModelMap modelMap) { if (scriptFile == null) throw new IllegalArgumentException("A scriptFile is required");
Myślę, że ta
@NotNull
adnotacja jest ważna, więc jeśli warunek nie jest potrzebny.źródło
Myślę, że wiem, dokąd zmierza twoje pytanie. A ponieważ to pytanie pojawia się w głównych wynikach wyszukiwania Google, mogę udzielić prostej odpowiedzi na temat tego, co robi adnotacja @Valid.
Przedstawię 3 scenariusze dotyczące korzystania z @Valid
Model:
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> ...
Kontroler dla scenariusza 1:
@RequestMapping("processForm") public String processFormData(@Valid @ModelAttribute("employee") Employee employee){ return "employee-confirmation-page"; }
W tym scenariuszu po przesłaniu formularza z pustym polem lastName zostanie wyświetlona strona błędu, ponieważ stosujesz reguły walidacji, ale w ogóle jej nie obsługujesz.
Przykład błędu: strona wyjątków
Kontroler dla scenariusza 2:
@RequestMapping("processForm") public String processFormData(@Valid @ModelAttribute("employee") Employee employee, BindingResult bindingResult){ return bindingResult.hasErrors() ? "employee-form" : "employee-confirmation-page"; }
W tym scenariuszu przekazujesz wszystkie wyniki z tego walidacji do bindingResult, więc od Ciebie zależy, co zrobić z wynikami walidacji tego formularza.
Kontroler dla scenariusza 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 }
W tym scenariuszu nadal nie obsługujesz błędów, jak w pierwszym scenariuszu, ale przekazujesz to do innej metody, która zajmie się wyjątkiem, który wyzwala @Valid podczas przetwarzania modelu formularza. Sprawdź to, zobacz, co zrobić z mapowaniem i tak dalej.
Podsumowując : @Valid samodzielnie, nie robiąc nic więcej, co wyzwala walidację pól z adnotacjami JSR 303 ( @NotNull, @Email, @Size, itp. ), Nadal musisz określić strategię tego, co robić z wynikami tej walidacji.
Mam nadzieję, że udało mi się wyjaśnić coś dla ludzi, którzy mogą się z tym potknąć.
źródło
Wystarczy dodać do powyższej odpowiedzi, w aplikacji internetowej
@valid
jest stosowana, gdy fasola być weryfikowane są również opatrzone walidacja adnotacje np@NotNull
,@Email
(hibernacji adnotacja), więc gdy przy pobieraniu wejście od użytkownika wartości mogą być zatwierdzone i wiążący wynik będzie miał walidacji wyniki.bindingResult.hasErrors()
powie, jeśli jakakolwiek weryfikacja się nie powiodła.źródło
Innym przydatnym aspektem @Valid, o którym nie wspomniano powyżej, jest to, że (np. Użycie Postmana do testowania punktu końcowego) @Valid sformatuje wynik nieprawidłowego wywołania REST do sformatowanego JSON zamiast bloba ledwo czytelnego tekstu. Jest to bardzo przydatne, jeśli tworzysz komercyjny interfejs API dla swoich użytkowników.
źródło
Chciałem dodać więcej szczegółów na temat tego, jak
@Valid
działa, zwłaszcza wiosną.Wszystko, co chciałbyś wiedzieć o walidacji na wiosnę, jest jasno i szczegółowo wyjaśnione w https://reflectoring.io/bean-validation-with-spring-boot/ , ale skopiuję odpowiedź, jak
@Valid
działa, w przypadku linku idzie w dół.@Valid
Adnotacji mogą być dodawane do zmiennych w spoczynku metody kontrolera, aby je zatwierdzić. Istnieją 3 typy zmiennych, które można zweryfikować:Więc teraz… w jaki sposób wiosna "sprawdza się"? Możesz zdefiniować ograniczenia dla pól klasy, dodając do nich adnotacje. Następnie przekazujesz obiekt tej klasy do walidatora, który sprawdza, czy ograniczenia są spełnione.
Na przykład załóżmy, że mam taką metodę kontrolera:
@RestController class ValidateRequestBodyController { @PostMapping("/validateBody") ResponseEntity<String> validateBody(@Valid @RequestBody Input input) { return ResponseEntity.ok("valid"); } }
Jest to więc żądanie POST, które przyjmuje treść odpowiedzi i mapujemy tę treść odpowiedzi na klasę
Input
.Oto klasa
Input
:class Input { @Min(1) @Max(10) private int numberBetweenOneAndTen; @Pattern(regexp = "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$") private String ipAddress; // ... }
Adnotacja @Valid poinformuje spring, aby przeszła i zweryfikowała dane przekazane do kontrolera, sprawdzając, czy liczba całkowita
numberBetweenOneAndTen
mieści się w zakresie od 1 do 10 włącznie z powodu tych adnotacji min i max. Sprawdza również, czy przekazany adres IP pasuje do wyrażenia regularnego w adnotacji.uwaga boczna: wyrażenie regularne nie jest doskonałe… możesz podać 3-cyfrowe liczby większe niż 255 i nadal pasowałoby do wyrażenia regularnego.
Oto przykład sprawdzania poprawności zmiennej zapytania i zmiennej ścieżki:
@RestController @Validated class ValidateParametersController { @GetMapping("/validatePathVariable/{id}") ResponseEntity<String> validatePathVariable( @PathVariable("id") @Min(5) int id) { return ResponseEntity.ok("valid"); } @GetMapping("/validateRequestParameter") ResponseEntity<String> validateRequestParameter( @RequestParam("param") @Min(5) int param) { return ResponseEntity.ok("valid"); } }
W tym przypadku, ponieważ zmienna zapytania i zmienna ścieżki są po prostu liczbami całkowitymi, a nie tylko złożonymi klasami, umieszczamy adnotację ograniczenia
@Min(5)
bezpośrednio na parametrze zamiast używać@Valid
.źródło