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