春季 MVC 验证器注释 + 自定义验证

2022-09-01 09:21:07

我正在研究弹簧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
        }
    }
}

那么,是否可以同时使用自定义验证器和注释?如果是,如何?


答案 1

我知道这是一个古老的问题,但是,对于谷歌用户来说......

您应该使用 代替 。如下所示:addValidatorssetValidator

@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

如果我正确理解您的问题,一旦您使用自定义验证程序,注释的默认验证将不再发生。这在使用spring时很常见:如果您覆盖默认给定的功能,则必须显式调用它。@NotEmpty

您必须生成一个并将其与消息源(如果有)一起注入。然后,在自定义验证程序中注入该基本验证程序,并向其委派注释验证。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");
        }
    }
}

推荐