Spring 4 @Validation аннотация с BindingResult не работает

Когда я использую BindingResult с аннотацией @Validated в методе, проверка не работает. Если я уберу BindingResult из параметров метода, он будет работать нормально. Я использовал @ControllerAdvice.

Любая идея, почему это не работает?

Мой код ниже:

public ResponseEntity<?> dologin(
        @Validated({ Group.Login.class }) @RequestBody User user,
        BindingResult errors)
{
    // somecode
}

В соответствии с Проверка данных Документация по привязке и преобразованию типов, любое сообщение о проверке будет автоматически добавлено в файл BindingResult подшивки.

Если я удалю его, не будет никаких последствий, верно?


person bNd    schedule 17.03.2017    source источник


Ответы (2)


Поскольку вы предоставили код только из своего метода контроллера, я добавляю некоторую дополнительную информацию, которая необходима для того, чтобы проверка работала в приложении Spring 4, чтобы вы могли видеть, где могут быть какие-либо различия. Я минимально предполагаю следующее:

  1. Включите JAR-файл bean-validation-api в путь к классам. . Это дает вам аннотацию.
  2. Включите JAR-файл реализации проверки компонентов (например, эталонную реализацию, hibernate-validator) в пути к классам. Это включает структуру проверки.
  3. Сопоставление вашего запроса может иметь одну из следующих форм:

@RequestMapping(method = RequestMethod.POST)
public String dologin(@Valid @ModelAttribute("userForm") User user, final BindingResult bindingResult) throws Exception

@RequestMapping(method = RequestMethod.POST)
public String dologin(@Validated @ModelAttribute("userForm") User user, final BindingResult bindingResult) throws Exception

или, если используются группы проверки< /а>:


@RequestMapping(method = RequestMethod.POST)
public String dologin(@Validated({ User.Login.class }) @ModelAttribute("userForm") User user, final BindingResult bindingResult) throws Exception

  1. Ваша аннотация в классе User должна быть встроена в ключи свойств сообщения:

@NotBlank(message = "{firstName.required}")
@Size(min = 2, max = 24, message = "{firstName.size}")
@Pattern(regexp = "^[’' \\.\\-\\p{L}\\p{M}]*$", message = "{firstName.format}")
private String firstName;

или, если используются группы проверки< /а>:


public interface Login extends Default {}

@NotBlank(message = "{firstName.required}", groups = {Login.class})
@Size(min = 2, max = 24, message = "{firstName.size}", groups = {Login.class})
@Pattern(regexp = "^[’' \\.\\-\\p{L}\\p{M}]*$", message = "{firstName.format}", groups = {Login.class})
private String firstName;

  1. Свойства вашего сообщения должны быть в src/main/resources:

firstName.required=First name is required.
firstName.size=First name must be between {min} and {max} characters long.
firstName.format=First name may contain only letters, apostrophes, spaces and hyphens.

Убедитесь, что ваша версия проверки компонента соответствует версии вашей реализации. API проверки компонентов 2.0 был выпущен в августе 2017 года. Эталонная реализация Bean Validation 2.0: Hibernate Validation Engine 6.0.

Ошибки проверки будут добавлены к BindingResult, если они присутствуют в параметрах метода. В качестве альтернативы вы можете использовать Errors вместо BindingResult — API по сути тот же. Оба они работают одинаково в моей реализации выше.

Однако, если я оставлю параметр вне своего метода контроллера, я вижу (из журнала), что проверка запускается и возникают соответствующие ошибки, и сопоставление моих ключей сообщений с их свойствами выполняется успешно, но вместо этого отображается моя страница ошибки сервера. ожидаемого мною вида. Дополнительные сведения о требованиях к этому параметру см. в соответствующем вопросе о параметре BindingResult/Errors.


Aug 31, 2017 2:21:56 PM com.test.spring.controller.ErrorController handleException
SEVERE: Server Error
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'userForm' on field 'firstName': rejected value []; codes [Size.userForm.firstName,Size.firstName,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userForm.firstName,firstName]; arguments []; default message [firstName],24,2]; default message [First name must be between 2 and 24 characters long.]
Field error in object 'userForm' on field 'firstName': rejected value []; codes [NotBlank.userForm.firstName,NotBlank.firstName,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userForm.firstName,firstName]; arguments []; default message [firstName]]; default message [First name is required.]
    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:117)

Я вижу очень последовательное поведение во всех вышеперечисленных комбинациях.

Одно отличие, которое я отмечаю, заключается в том, что вы используете @ControllerAdvice в своем примере. Большинство моих контроллеров используют @Controller аннотация (ошибки локального контроллера), а не @ControllerAdvice (используется для глобальных ошибок, например для отображения страниц ошибок HTTP 404 или 500). См. этот связанный вопрос/ответ для использования @ControllerAdvice.

В приведенном выше журнале ошибок вы видите, что ErrorController сообщает об ошибках проверки, если я пропускаю параметр BindingResult/Errors, и действительно, это мой класс контроллера, который использует аннотацию @ControllerAdvice вместо @Controller. Используя @ControllerAdvice на вашем контроллере входа в систему, вы можете мешать нормальной обработке ошибок.

Поскольку вы используете Hibernate-specific @Validated групповая аннотация проверки вместо JSR-303/349/380 спецификация @Valid могут быть некоторые различия между используемой реализацией (я предполагаю, что версия 5 соответствует API 1.1). Я использую версию 6.0.2, которая соответствует новому (август 2017 г.) Bean Validation Framework API 2.0.

person vallismortis    schedule 31.08.2017
comment
@Valid не предоставляет способ использования групп, он использует группу по умолчанию (без группы) для проверки. И это не то, что он хочет использовать в своем коде, я полагаю - person Miron Balcerzak; 31.08.2017
comment
@MironBalcerzak Да, мне потребовалось некоторое время, чтобы создать рабочий пример, отражающий его вариант использования. Я добавил новую информацию в свой ответ, чтобы отразить группы проверки, в дополнение к более простой версии, не основанной на группах (в основном для моей справки). Я вижу последовательные результаты с обоими подходами. - person vallismortis; 31.08.2017

Hibernate Validator 6 не работает с Spring 4 из коробки, потому что Spring 4 LocalValidatorFactoryBean еще не использует Service Provider для обнаружения реализации валидатора, поэтому вам нужно создать валидатор самостоятельно, указав реализацию.

При использовании @EnableWebMvc:

@Bean
public javax.validation.Validator localValidatorFactoryBean() {
    LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
    bean.setProviderClass("org.hibernate.validator.HibernateValidator");
    return bean;
}

Или в XML:

<mvc:annotation-driven validator="validator-adapter"/>

<bean id="validator-adapter" 
  class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <property name="providerClass"
              value="org.hibernate.validator.HibernateValidator" />
</bean>
person stephan f    schedule 22.01.2021
comment
См. также stackoverflow.com/questions/23604540/ - person stephan f; 22.01.2021