Spring的Validation校验框架

Spring拥有自己独立的数据校验框架.Spring在进行数据绑定时,可同时调用校验框架来完成数据校验工作.
Spring的校验框架在org.springframework.validation包中,其中重要的接口和类如下:
Validator
最重要的接口,该接口有两个方法:
boolean supports(Class<?>clazz):该校验器能够对clazz类型的对象进行校验.
void validate(Object target,Errors errors):对目标类target进行校验,并将校验错误记录在errors当中.
Errors
Spring用来存放错误信息的接口.SpringMVC框架在将请求数据绑定到入参对象后,就会调用校验框架实施校验,而校验结果保存在处理方法的入参对象之后的参数对象当中.这个保存校验结果的参数对象必须是Errors或者BindingResult类型.一个Errors对象中包含了一系列的FieldError和ObjectError对象,FieldError表示与被校验的对象中的某个属性相关的一个错误.BindingResult扩展了Errors接口,同时可以获取数据绑定结果对象的信息.
ValidationUtils
Spring提供的一个关于校验类的工具类.他提供了多个给Errors对象保存错误的方法
LocalValidatorFactoryBean
位于org.springframework.validation.beanvalidation包中,该类既实现了Spring的Validator接口,也实现了JSR303的validator接口,只要在Spring容器中定义一个LocalValidatorFactoryBean,即可将其注入到需要数据校验的Bean中.定义一个LocalValidatorFactoryBean的Bean非常简单
<bean id="vilidator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<mvc:annotation-driven />会默认装配好一个LocalValidatorFactoryBean,所以在实际开发中不需要手动配置LocalValidatorFactoryBean.需要注意的是,Spring本身没有提供JSR303的实现,如果要使用JSR303完成验证,则必须将JSR303的实现(注入Hibernate Validator)jar文件加入到应用程序的类路径下,这样Spring会自动加载并装备好JSR303的实现.
示例:测试Spring的Validator校验
1.表单视图
    <h2>测试Validator接口验证</h2>
    <form:form modelAttribute="user" action="/springTest/testValidator" method="post">
        
        登录名:<form:input path="loginname" />
        <form:errors path="loginname" cssStyle="color:red" />
        <br />
        密码:<form:input path="password" />
        <form:errors path="password" cssStyle="color:red" />
        <br />
        <input type="submit" value="submit" />
        
    </form:form>
2.模型
public class User implements Serializable
{
    private String loginname;
    private String password;
    
    public User()
    {
        super();
    }
...
3.模型校验器
//实现Spring的Validator接口
@Repository("userValidator")
public class UserValidator implements Validator
{
    //该校验器能够对clazz类型的对象进行校验
    @Override
    public boolean supports(Class<?> clazz)
    {
        //User指定的Class参数所表示的类或接口是否相同,或是否是其超类或超接口
        return User.class.isAssignableFrom(clazz);
    }
    
    //对目标类target进行校验,并将校验错误记录在errors当中
    @Override
    public void validate(
            Object target,
            Errors errors
            )
    {
        /**
         * 使用ValidationUtils中的一个静态方法rejectIfEmpty()来对loginname属性进行校验
         * 假若loginname属性是null或者空字符串的话,就拒绝验证通过
         */
        ValidationUtils.rejectIfEmpty(errors, "loginname", null,"登录名称不能为空!");
        ValidationUtils.rejectIfEmpty(errors, "password", null,"密码不能为空!");
        
        User user = (User)target;
        if(user.getLoginname().length() > 10)
        {
            //使用Errors的rejectValue方法验证
            errors.rejectValue("loginname", null, "用户名不能超过10个字符!");
        }
        if(
                user.getPassword() != null &&
                !user.getPassword().equals("") &&
                user.getPassword().length() < 6
                )
        {
            errors.rejectValue("password", null, "密码不能小于6位");
        }
    }
}
4.控制器
@Controller
public class TestValidatorController
{
    //注入UserValidator对象
    @Autowired
    @Qualifier("userValidator")
    private UserValidator userValidator;
    
    
    @GetMapping("/testValidator")
    public String testValidator(
            Model model
            )
    {
        User user = new User();
        model.addAttribute("user",user);
        return "Form7";
    }
    
    @PostMapping("/testValidator")
    public String commit(
            @ModelAttribute User user,
            Errors errors,
            Model model
            )
    {
        model.addAttribute("user",user);
        //调用userValidator的验证方法
        userValidator.validate(user,errors);
        //如果验证不通过跳转到loginForm视图
        if(errors.hasErrors())
        {
            return "Form7";
        }
        
        return "success";
    }
}