Что обозначает аннотация @Valid в Spring?

В следующем примере параметр ScriptFile отмечен аннотацией @Valid.

Что делает аннотация @Valid?

@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();        
}    

person Gary Ford    schedule 29.08.2010    source источник


Ответы (9)


Это для целей проверки.

Валидация Обычно модель проверяют после привязки к ней вводимых пользователем данных. Spring 3 обеспечивает поддержку декларативной проверки с помощью JSR-303. Эта поддержка включается автоматически, если в вашем пути к классам присутствует поставщик JSR-303, такой как Hibernate Validator. Если этот параметр включен, вы можете инициировать проверку, просто аннотируя параметр метода контроллера с помощью аннотации @Valid: после привязки входящих параметров POST будет проверяться форма AppointmentForm; в этом случае, чтобы убедиться, что значение поля даты не равно нулю и происходит в будущем.


Дополнительные сведения см. здесь:
http://blog.springsource.com/2009/11/17/spring-3-type-conversion-and-validation/

person mhshams    schedule 29.08.2010

Добавляя к приведенным выше ответам, взгляните на следующие. Столбец date AppointmentForm снабжен парой аннотаций. Имея аннотацию @Valid, которая запускает проверки для AppointmentForm (в данном случае @NotNull и @Future). Эти аннотации могут поступать от разных поставщиков JSR-303 (например, Hibernate, Spring и т. Д.).

    @RequestMapping(value = "/appointments", method = RequestMethod.POST)
    public String add(@Valid AppointmentForm form, BindingResult result) {
        ....
    }

    static class AppointmentForm {

        @NotNull @Future
        private Date date;
    }
person Charith De Silva    schedule 07.10.2015
comment
У меня похожий код. Я удалил @Valid в параметре ApplicationForm, но все же проверки были запущены в поле date (установлено как null). Пожалуйста, объясни. - person lupchiazoem; 10.01.2019

@Valid сам по себе не имеет ничего общего с Spring. Это часть спецификации Bean Validation (их несколько, последней из которых является JSR 380 на вторую половину 2017 года), но @Valid очень старый и полностью унаследован от JSR 303.

Как мы все знаем, Spring очень хорош в обеспечении интеграции со всеми различными JSR и java библиотеками в целом (подумайте о JPA, JTA, кешировании и т. Д.), И, конечно же, эти ребята позаботились и о валидации. Одним из ключевых компонентов, способствующих этому, является MethodValidationPostProcessor.

Пытаюсь ответить на ваш вопрос - @Valid очень удобен для так называемого каскадирования валидации, когда вы хотите проверить сложный график, а не только элементы верхнего уровня объекта. Каждый раз, когда вы хотите углубиться, вы должны использовать @Valid. Это то, что диктует JSR. Spring будет соответствовать этому с некоторыми незначительными отклонениями (например, я попытался поставить @Validated вместо @Valid в метод RestController, и проверка работает, но то же самое не относится к обычным "служебным" компонентам).

person yuranos    schedule 09.11.2017
comment
Но что подтверждает? - person nephewtom; 09.06.2020
comment
Пожалуйста, уточните, @nephewtom. Что вы хотите уточнить? - person yuranos; 10.06.2020
comment
Я прочитал JSR 303: Bean Validation, beanvalidation.org/1.0/spec, но все равно не получаю какая проверка будет выполняться на ScriptFile scriptFile. - person nephewtom; 10.06.2020
comment
ScriptFile внутри него, вероятно, имеет кучу полей, и эти поля также имеют аннотации к ним. Здесь и начинается проверка. Исходя из исходного вопроса, неясно, что именно находится внутри класса ScriptFile. - person yuranos; 10.06.2020
comment
Хорошо спасибо. Не могли бы вы привести пример того, что можно проверить, если в его полях есть String, Integer и Bean? - person nephewtom; 10.06.2020
comment
Например, @Email (message = Email должен быть действительным) private String email, если вы используете последние спецификации, в которые добавлена ​​поддержка по электронной почте. Или @Pattern (message = Invalid pattern., Regexp = ^. + @. + \\.) Частный шаблон String; - person yuranos; 10.06.2020

IIRC @Valid - это не аннотация Spring, а аннотация JSR-303 (которая является стандартом проверки компонентов). Что он делает, так это в основном проверяет, действительны ли данные, которые вы отправляете методу (он проверяет scriptFile за вас).

person Mateusz Dymczyk    schedule 29.08.2010
comment
Что это значит, что он проверит файл scriptFile за вас? Проверить, не является ли он нулевым, имеет какой-то синтаксис или какое-то содержание? Другими словами, что он подтверждает и как? Следует ли пользователю что-то реализовать? Где я могу получить информацию об этом? Спасибо! - person nephewtom; 09.06.2020
comment
Пожалуйста, ответьте на вопрос @nephewtom, этого недостаточно, чтобы подтвердить отсутствие основного пункта, против чего? - person monami; 06.11.2020

Я хотел добавить больше подробностей о том, как работает @Valid, особенно весной.

Все, что вам нужно знать о проверке весной, четко и подробно объяснено в https://reflectoring.io/bean-validation-with-spring-boot/, но я скопирую ответ о том, как @Valid работает, если ссылка не работает.

Аннотация @Valid может быть добавлена ​​к переменным в методе контроллера отдыха для их проверки. Есть 3 типа переменных, которые можно проверить:

  • тело запроса,
  • переменные в пути (например, id в / foos / {id}) и,
  • параметры запроса.

Итак ... как же весна проверяется? Вы можете определить ограничения для полей класса, аннотируя их определенными аннотациями. Затем вы передаете объект этого класса в валидатор, который проверяет выполнение ограничений.

Например, предположим, что у меня есть такой метод контроллера:

@RestController
class ValidateRequestBodyController {

  @PostMapping("/validateBody")
  ResponseEntity<String> validateBody(@Valid @RequestBody Input input) {
    return ResponseEntity.ok("valid");
  }

}

Итак, это запрос POST, который принимает тело запроса, и мы сопоставляем это тело запроса с классом Input.

Вот класс 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;
  
  // ...
}

Аннотация @Valid сообщит Spring, что нужно пойти и проверить данные, переданные в контроллер, проверив, что целое число numberBetweenOneAndTen находится в диапазоне от 1 до 10 включительно из-за этих аннотаций min и max. Он также проверит, соответствует ли переданный IP-адрес регулярному выражению в аннотации.

примечание: регулярное выражение не идеально ... вы можете передать трехзначные числа, которые больше 255, и оно все равно будет соответствовать регулярному выражению.


Вот пример проверки переменной запроса и переменной пути:

@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");
  }
}

В этом случае, поскольку переменная запроса и переменная пути являются просто целыми числами, а не просто сложными классами, мы помещаем аннотацию ограничения @Min(5) прямо в параметр вместо использования @Valid.

person SomeGuy    schedule 08.12.2020
comment
›Итак, это запрос POST, который принимает тело ответа, и мы сопоставляем это тело ответа с классом Input… Разве это не должен быть запрос POST, который принимает тело запроса? - person sss; 15.04.2021
comment
@sss: да, это была ошибка. Сейчас это исправлено - person SomeGuy; 17.04.2021

public String create(@Valid @NotNull ScriptFile scriptFile, BindingResult result, ModelMap modelMap) {    
    if (scriptFile == null) throw new IllegalArgumentException("A scriptFile is required");        

Я предполагаю, что эта аннотация @NotNull действительна, поэтому, если условие не требуется.

person mzlobecki    schedule 08.11.2015

Думаю, я знаю, к чему ведет ваш вопрос. И поскольку именно этот вопрос появляется в основных результатах поиска Google, я могу дать простой ответ о том, что делает аннотация @Valid.

Я представлю 3 сценария того, как я использовал @Valid

Модель:

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>
...

Контроллер для сценария 1:

     @RequestMapping("processForm")
        public String processFormData(@Valid @ModelAttribute("employee") Employee employee){
        return "employee-confirmation-page";
    }

В этом сценарии после отправки формы с пустым полем lastName вы получите страницу с ошибкой, поскольку вы применяете правила проверки, но не обрабатываете ее вообще.

Пример указанной ошибки: страница исключений

Контроллер для сценария 2:

 @RequestMapping("processForm")
    public String processFormData(@Valid @ModelAttribute("employee") Employee employee,
BindingResult bindingResult){
                return bindingResult.hasErrors() ? "employee-form" : "employee-confirmation-page";
            }

В этом сценарии вы передаете все результаты этой проверки в bindingResult, поэтому вам решать, что делать с результатами проверки этой формы.

Контроллер для сценария 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
}

В этом сценарии вы по-прежнему не обрабатываете ошибки, как в первом сценарии, но передаете это другому методу, который позаботится об исключении, которое @Valid вызывает при обработке модели формы. Проверьте это, посмотрите, что делать с сопоставлением и всем остальным.

Подводя итог: @Valid сам по себе не делает ничего, что запускает проверку аннотированных полей JSR 303 (@NotNull, @Email, @Size и т. д. ), вам все равно нужно указать стратегию того, что делать с результатами указанной проверки.

Надеюсь, я смог кое-что прояснить для людей, которые могут с этим споткнуться.

person Alan Balderas Sánchez    schedule 20.10.2020

Просто добавив к приведенному выше ответу, в веб-приложении используется @valid, где bean-компонент для проверки также аннотируется аннотациями проверки, например. @NotNull, @Email (аннотация спящего режима), поэтому при получении ввода от пользователя значения могут быть проверены, и результат привязки будет иметь результаты проверки. bindingResult.hasErrors() сообщит, если какая-либо проверка не удалась.

person puneet goyal    schedule 23.06.2015

Другой удобный аспект @Valid, не упомянутый выше, заключается в том, что (например, использование Postman для тестирования конечной точки) @Valid форматирует вывод неправильного вызова REST в форматированный JSON вместо капли с труднодоступным текстом. Это очень полезно, если вы создаете коммерчески доступный API для своих пользователей.

person Sean Gildea    schedule 12.01.2019