validator mvc example custom bindingresult validation spring-mvc

example - spring mvc validation bindingresult



Agregar mĂșltiples validadores usando initBinder (7)

Estoy agregando un validador de usuario usando el método initBinder :

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

Aquí está el 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 } }

El método de validate se llama correctamente durante la llamada al método del controlador.

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

Pero al regresar a la pantalla de pago recibo este error:

java.lang.IllegalStateException: destino no válido para Validator [com.validator.UserValidator@710db357]: com.domain.CustomerPayment [customerPaymentId = null] org.springframework.validation.DataBinder.setValidator (DataBinder.java:476) com.web. UserRegistrationController.initBinder (UserRegistrationController.java:43) sun.reflect.NativeMethodAccessorImpl.invoke0 (Método nativo) 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.annota tion.AnnotationMethodHandlerAdapter.handle (AnnotationMethodHandlerAdapter.java:414)

Esto puede deberse a que estoy devolviendo un CustomerPayment y no hay un validador definido para eso.

Tampoco puedo agregar múltiples validadores en el método initBinder .

¿Cómo puedo arreglar esto?


Declarar solicitud como

(... , Model model,HttpServletRequest request)

y cambio

model.addAttribute(customerPayment);

a

request.setAttribute("customerPayment",customerPayment);


El validador múltiple en un comando es compatible con Spring MVC 4.x ahora. Puede usar este código de fragmento:

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


Es un poco complicado de hacer, 1 controlador tiene solo 1 validador en 1 objeto de comando. necesita crear un "Validador compuesto" que obtendrá todos los validadores y los ejecutará por separado.

Aquí hay un tutorial que explica cómo hacerlo: usando múltiples validadores


Hay un truco simple, siempre devuelve true en el método de supports y delega la verificación de clase para validate . Entonces, básicamente, puede agregar múltiples validadores en el initBinder sin problema.

@Component public class MerchantRegisterValidator implements Validator { @Autowired private MerchantUserService merchantUserService; @Autowired private MerchantCompanyService merchantCompanyService; @Override public boolean supports(Class<?> clazz) { return true; // always true } @Override public void validate(Object target, Errors errors) { if (!XxxForm.getClass().equals(target.getClass())) return; // do checking here. RegisterForm registerForm = (RegisterForm) target; MerchantUser merchantUser = merchantUserService.getUserByEmail(registerForm.getUserEmail()); if (merchantUser != null) { errors.reject("xxx"); } MerchantCompany merchantCompany = merchantCompanyService.getByRegno(registerForm.getRegno()); if (merchantCompany != null) { errors.reject("xxx"); } } }


No veo una razón por la cual Spring no filtre todos los validadores que no son aplicables a la entidad actual de forma predeterminada, lo que obliga a usar elementos como CompoundValidator descrito por @ Rigg802.

InitBinder permite especificar solo el nombre, lo que le brinda cierto control pero no un control total sobre cómo y cuándo aplicar su validador personalizado. Que desde mi punto de vista no es suficiente.

Otra cosa que puede hacer es realizar una comprobación usted mismo y agregar un validador a la carpeta solo si es realmente necesario, ya que la carpeta tiene información de contexto vinculante.

Por ejemplo, si desea agregar un nuevo validador que funcione con su objeto Usuario además de los validadores incorporados, puede escribir algo como esto:

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

}


Puede agregar múltiples validadores al iterar sobre org.springframework.validation.Validator en un ApplicationContext y configurar los adecuados en @InitBinder para cada solicitud.

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

Ver mi proyecto para ejemplos y puntos de referencia simples. https://github.com/LyashenkoGS/spring-mvc-and-jms-validation-POC/tree/benchamark


@InitBinder establecer el valor de la anotación @InitBinder en el nombre del comando que desea validar. Esto le dice a Spring a qué aplicar la carpeta; sin él, Spring intentará aplicarlo a todo. Esta es la razón por la que está viendo esa excepción: Spring está tratando de aplicar la carpeta, con su UserValidator , a un parámetro de tipo CustomerPayment .

En su caso específico, parece que necesita algo como:

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

Para su segunda pregunta, como explicó Rigg802, Spring no admite la conexión de múltiples validadores a un solo comando. Sin embargo, puede definir múltiples métodos @InitBinder para diferentes comandos. Entonces, por ejemplo, puede poner lo siguiente en un solo controlador y validar su usuario y los parámetros de pago:

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