Добавление нескольких валидаторов с помощью 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
.
Как я могу это исправить?
Ответы
Ответ 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);