validaciones valid mvc mensajes internacionalización formulario ejemplo commandname bindingresult java spring validation spring-mvc

java - mensajes - Anotación del validador Spring MVC+validación personalizada



spring mvc formulario ejemplo (3)

Estoy trabajando en la aplicación spring mvc, donde debería aplomar la validación basada en el validador Spring MVC. El primer paso para eso es que agregué una anotación para la clase y el controlador de configuración, y funciona bien. Y ahora necesito implementar un validador personalizado para realizar una lógica compleja, pero quiero usar la anotación existente y simplemente agregar una verificación adicional.

Mi clase de usuario:

public class User { @NotEmpty private String name; @NotEmpty private String login; // should be unique }

Mi validador:

@Component public class UserValidator implements Validator { @Autowired private UserDAO userDAO; @Override public boolean supports(Class<?> clazz) { return User.class.equals(clazz) || UsersForm.class.equals(clazz); } @Override public void validate(Object target, Errors errors) { /* ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "NotEmpty.user"); ValidationUtils.rejectIfEmptyOrWhitespace(errors, "login", "NotEmpty.user"); */ User user = (User) target; if (userDAO.getUserByLogin(user.getLogin()) != null) { errors.rejectValue("login", "NonUniq.user"); } } }

Mi controlador:

@Controller public class UserController { @Autowired private UserValidator validator; @InitBinder protected void initBinder(final WebDataBinder binder) { binder.setValidator(validator); } @RequestMapping(value = "/save") public ModelAndView save(@Valid @ModelAttribute("user") final User user, BindingResult result) throws Exception { if (result.hasErrors()) { // handle error } else { //save user } } }

Entonces, ¿es posible usar un validador y una anotación personalizados juntos? Y si es así, ¿cómo?


Bueno, para mí, tienes que eliminar el

@InitBinder protected void initBinder(final WebDataBinder binder) { binder.setValidator(validator); }

Deja el

@Valid @ModelAttribute("user") final User user, BindingResult result

Y luego en la función make

validator.validate(user,result)

De esta forma, utilizará la validación básica con @Valid y luego hará una validación más compleja.

Porque con el initBinder está configurando la validación con su lógica compleja y poniendo de una manera la lógica básica.

Tal vez esté mal, siempre uso el @Valid sin ningún validador.


Sé que esta es una especie de vieja pregunta, pero, para googlers ...

deberías usar addValidators lugar de setValidator . Como siguiendo:

@InitBinder protected void initBinder(final WebDataBinder binder) { binder.addValidators(yourCustomValidator, anotherValidatorOfYours); }

PD: addValidators acepta múltiples parámetros (puntos suspensivos)

si selecciona la fuente de org.springframework.validation.DataBinder , verá:

public class DataBinder implements PropertyEditorRegistry, TypeConverter { .... public void setValidator(Validator validator) { assertValidators(validator); this.validators.clear(); this.validators.add(validator); } public void addValidators(Validator... validators) { assertValidators(validators); this.validators.addAll(Arrays.asList(validators)); } .... }

como ve, setValidator borra el setValidator existente (predeterminado) para que la anotación @Valid no funcione como se esperaba.


Si entiendo correctamente su problema, tan pronto como use su validador personalizado, ya no se realizará la validación predeterminada para la anotación @NotEmpty . Eso es común cuando se usa la primavera: si anula una funcionalidad dada por defecto, debe llamarla explícitamente.

LocalValidatorFactoryBean generar un LocalValidatorFactoryBean e inyectarlo con su origen de mensaje (si corresponde). Luego, usted inyecta ese validador básico en su validador personalizado y le delega la validación de la anotación.

Usando la configuración de java podría verse así:

@Configuration public class ValidatorConfig { @Autowired private MessageSource messageSource; @Bean public Validator basicValidator() { LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); validator.setValidationMessageSource(messageSource); return validator; } }

Luego modifica UserValidator para usarlo:

@Component public class UserValidator implements Validator { @Autowired @Qualifier("basicValidator") private Validator basicValidator; @Autowired private UserDAO userDAO; // ... @Override public void validate(Object target, Errors errors) { basicValidator.validate(target, errors); // eventually stop if any errors // if (errors.hasErrors()) { return; } User user = (User) target; if (userDAO.getUserByLogin(user.getLogin()) != null) { errors.rejectValue("login", "NonUniq.user"); } } }