Je travaille sur l'application Spring MVC, où je devrais appliquer la validation basée sur le validateur Spring MVC. J'ai la première étape pour cela, j'ai ajouté une annotation pour la classe et le contrôleur de configuration et cela fonctionne très bien. Et maintenant, je dois implémenter un validateur personnalisé pour effectuer une logique complexe, mais je veux utiliser les annotations existantes et ajouter simplement une vérification supplémentaire.
Ma classe d'utilisateurs:
public class User
{
@NotEmpty
private String name;
@NotEmpty
private String login; // should be unique
}
Mon validateur:
@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");
}
}
}
Mon contrôleur:
@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
}
}
}
Alors, est-il possible d'utiliser ensemble un validateur et une annotation personnalisés? Et si oui comment?
Je sais que c'est une sorte de vieille question mais, pour les googleurs ...
vous devez utiliser addValidators
au lieu de setValidator
. Comme suivant:
@InitBinder
protected void initBinder(final WebDataBinder binder) {
binder.addValidators(yourCustomValidator, anotherValidatorOfYours);
}
PS: addValidators
accepte plusieurs paramètres (points de suspension)
si vous extrayez la source de org.springframework.validation.DataBinder
tu verras:
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));
}
....
}
comme vous voyez setValidator
efface le validateur existant (par défaut) donc @Valid
l'annotation ne fonctionnera pas comme prévu.
Si je comprends bien votre problème, dès que vous utilisez votre validateur personnalisé, validation par défaut pour @NotEmpty
l'annotation ne se produit plus. Cela est courant lors de l'utilisation de spring: si vous surchargez une fonctionnalité donnée par défaut, vous devez l'appeler explicitement.
Vous devez générer un LocalValidatorFactoryBean
et l'injecter avec votre source de message (le cas échéant). Ensuite, vous injectez ce validateur de base dans votre validateur personnalisé et lui déléguez la validation des annotations.
En utilisant Java, cela pourrait ressembler à:
@Configuration
public class ValidatorConfig {
@Autowired
private MessageSource messageSource;
@Bean
public Validator basicValidator() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(messageSource);
return validator;
}
}
Ensuite, vous modifiez UserValidator
pour l'utiliser:
@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");
}
}
}
Eh bien, pour moi, vous devez supprimer le
@InitBinder
protected void initBinder(final WebDataBinder binder)
{
binder.setValidator(validator);
}
Quitter le
@Valid @ModelAttribute("user") final User user,
BindingResult result
Et après dans la fonction faire
validator.validate(user,result)
De cette façon, vous utiliserez la validation de base avec @Valid et après vous mettrez la validation la plus complexe.
Parce qu'avec initBinder vous définissez la validation avec votre logique complexe et mettez en place la logique de base.
C'est peut-être faux, j'utilise toujours le @Valid sans aucun validateur.