Подтвердить что ты не робот

Добавление нескольких валидаторов с помощью initBinder

Я добавляю валидатор пользователя с помощью метода initBinder:

@InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.setValidator(new UserValidator());
    }

Вот UserValidator

public class UserValidator implements Validator {

    public boolean supports(Class clazz) {
        return User.class.equals(clazz);
    }

    public void validate(Object target, Errors errors) {
        User u = (User) target;

        // more code here
    }
}

Метод validate получает должным образом вызов во время вызова метода контроллера.

@RequestMapping(value = "/makePayment", method = RequestMethod.POST)
public String saveUserInformation(@Valid User user, BindingResult result, Model model){

    // saving User here

    // Preparing CustomerPayment object for the payment page.
    CustomerPayment customerPayment = new CustomerPayment();
    customerPayment.setPackageTb(packageTb);
    model.addAttribute(customerPayment);
    logger.debug("Redirecting to Payment page.");

    return "registration/payment";
}

Но при возврате на экран оплаты я получаю эту ошибку:

java.lang.IllegalStateException: Недопустимая цель для Validator [[email protected]]: com.domain.CustomerPayment [customerPaymentId = null]         org.springframework.validation.DataBinder.setValidator(DataBinder.java:476)         com.web.UserRegistrationController.initBinder(UserRegistrationController.java:43)         sun.reflect.NativeMethodAccessorImpl.invoke0 (собственный метод)         sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)         sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)         java.lang.reflect.Method.invoke(Method.java:597)         org.springframework.web.bind.annotation.support.HandlerMethodInvoker.initBinder(HandlerMethodInvoker.java:393)         org.springframework.web.bind.annotation.support.HandlerMethodInvoker.updateModelAttributes(HandlerMethodInvoker.java:222)         org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:429)         org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414)

Возможно, это связано с тем, что я возвращаю CustomerPayment, и для этого не существует валидатора.

Я также не могу добавить несколько валидаторов в метод initBinder.

Как я могу это исправить?

4b9b3361

Ответ 1

Вам нужно установить значение аннотации @InitBinder на имя команды, которую вы хотите проверить. Это говорит Spring, к чему нужно применить связующее; без него Spring попытается применить его ко всему. Вот почему вы видите это исключение: Spring пытается применить связующее - с вашим UserValidator - к параметру типа CustomerPayment.

В вашем конкретном случае, похоже, вам нужно что-то вроде:

@InitBinder("user")
protected void initBinder(WebDataBinder binder) {
    binder.setValidator(new UserValidator());
}

К вашему второму вопросу, как объяснил Rigg802, Spring не поддерживает прикрепление нескольких валидаторов к одной команде. Однако вы можете определить несколько методов @InitBinder для разных команд. Так, например, вы можете поместить следующее в один контроллер и проверить свои параметры пользователя и оплаты:

@InitBinder("user")
protected void initUserBinder(WebDataBinder binder) {
    binder.setValidator(new UserValidator());
}

@InitBinder("payment")
protected void initPaymentBinder(WebDataBinder binder) {
    binder.setValidator(new CustomerPaymentValidator());
}

Ответ 2

Это немного сложно сделать, 1 контроллер имеет только 1 валидатор на 1 командный объект. вам нужно создать "Composite Validator", который получит все валидаторы и запустит их отдельно.

Вот учебник, в котором объясняется, как это сделать: с использованием нескольких валидаторов

Ответ 3

Я не вижу причины, почему Spring не отфильтровывает все валидаторы, которые по умолчанию не применимы к текущему объекту, что заставляет использовать такие вещи, как CompoundValidator, описанные @Rigg802.

InitBinder позволяет указать только имя, которое дает вам некоторый контроль, но не полный контроль над тем, как и когда применять ваш настраиваемый валидатор. Который с моей точки зрения недостаточно.

Еще одна вещь, которую вы можете сделать, - это проверить себя и добавить валидатор для связывания только в том случае, если это действительно необходимо, поскольку сам связующий имеет обязательную контекстную информацию.

Например, если вы хотите добавить новый валидатор, который будет работать с вашим объектом User, в дополнение к встроенным валидаторам, вы можете написать примерно так:

@InitBinder
protected void initBinder(WebDataBinder binder) {
  Optional.ofNullable(binder.getTarget())
      .filter((notNullBinder) -> User.class.equals(notNullBinder.getClass()))
      .ifPresent(o -> binder.addValidators(new UserValidator()));

}

Ответ 4

Вы можете добавить несколько валидаторов, выполнив итерацию по всему org.springframework.validation.Validator в ApplicationContext и настройте подходящие в @InitBinder для каждого запроса.

@InitBinder
public void setUpValidators(WebDataBinder webDataBinder) {
    for (Validator validator : validators) {
        if (validator.supports(webDataBinder.getTarget().getClass())
                && !validator.getClass().getName().contains("org.springframework"))
            webDataBinder.addValidators(validator);
    }
}

См. мой проект для примеров и простых тестов. https://github.com/LyashenkoGS/spring-mvc-and-jms-validation-POC/tree/benchamark

Ответ 5

Несколько валидаторов по одной команде поддерживаются с помощью Spring MVC 4.x. Вы можете использовать этот код фрагмента:

@InitBinder
protected void initBinder(WebDataBinder binder) {
    binder.addValidators(new UserValidator(), new CustomerPaymentValidator());
}

Ответ 6

Кроме того, @Annabelle, теперь можно добавить два Validator следующим образом: просто добавление автоустановленных валидаторов (beans объявлено в spring-context.xml) и использование только их.

@Autowired
@Qualifier("user")
private Validator userValidator;


@Autowired
@Qualifier("payment")
private Validator paymentValidator;

@InitBinder
private void initBinder(WebDataBinder binder) {
    binder.replaceValidators(userValidator, paymentValidator);

}

Ответ 7

Объявить запрос как

(... , Model model,HttpServletRequest request)

и измените

model.addAttribute(customerPayment);

к

request.setAttribute("customerPayment",customerPayment);