Подтвердить что ты не робот

Spring аннотация + валидатор MVC + пользовательская проверка

Я работаю над приложением spring mvc, где я должен использовать проверку достоверности на основе валидатора spring MVC. Я первый шаг для этого, я добавил аннотацию для контроллера класса и установки, и он отлично работает. И теперь мне нужно реализовать специальный валидатор для выполнения сложной логики, но я хочу использовать существующую аннотацию и просто добавить дополнительную проверку.

Мой класс пользователя:

public class User
{
    @NotEmpty
    private String name;

    @NotEmpty
    private String login; // should be unique
}

Мой валидатор:

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

Мой контроллер:

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

Итак, возможно ли совместное использование валидатора и аннотации? И если да, то как?

4b9b3361

Ответ 1

Я знаю, что это своего рода старый вопрос, но для гуглеров...

вы должны использовать addValidators вместо setValidator. Пример:

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

PS: addValidators принимает несколько параметров (многоточие)

если вы проверяете источник org.springframework.validation.DataBinder, вы увидите:

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

    ....

}

как вы видите, setValidator очищает существующий (по умолчанию) валидатор, поэтому аннотация @Valid не работает должным образом.

Ответ 2

Ну, для меня вам нужно удалить

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

Оставьте

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

И после того, как в функции make

validator.validate(user,result)

Таким образом, вы будете использовать базовый валидационный код с помощью @Valid и после того, как вы поместите его, выполните более сложную проверку.

Поскольку с initBinder вы устанавливаете валидацию своей сложной логикой и ставите основную логику.

Возможно, неправильно, я всегда использую @Valid без какого-либо валидатора.

Ответ 3

Если я правильно понимаю вашу проблему, как только вы используете пользовательский валидатор, подтверждение по умолчанию для аннотации @NotEmpty больше не происходит. Это обычно используется при использовании spring: если вы переопределяете функциональную функцию, заданную по умолчанию, вы должны ее явно называть.

Вам нужно сгенерировать LocalValidatorFactoryBean и ввести его с источником сообщения (если есть). Затем вы добавляете этот базовый валидатор в свой пользовательский валидатор и делегируете ему аннотацию.

Используя java-конфигурацию, он может выглядеть так:

@Configuration
public class ValidatorConfig {
    @Autowired
    private MessageSource messageSource;

    @Bean
    public Validator basicValidator() {
        LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
        validator.setValidationMessageSource(messageSource);
        return validator;
    }
}

Затем вы изменяете UserValidator, чтобы использовать его:

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