SpringMVC数据校验

152 阅读4分钟

cd8bac15e162a355c6f546d8ac54f554_800_337.jpg

清新素雅的乌镇让人向往,代码中的世界是不是也是如此呢?老牌参数验证方式,JSR303校验 你值得拥有!❤️

介绍

  • JSR303是Java为Bean数据合法性校验提供的标准框架
  • 通过在Bean属性上标注类似于@NotNull@Max等标准的注解指定校验规则,并通过标准的验证接口对Bean进行验证
    • @Null:被注释的元素必须为null
    • @NotNull:被注释的元素必须为不能为null
    • @AssertTrue:被注释的元素必须为true
    • @AssertFalse:被注释的元素必须为false
    • @Min(value):被注释的元素必须是一个数字,值必须必须大于等于value
    • @Max(value):被注释的元素必须是一个数字,值必须必须小于等于value
    • @DecimalMin(value):被注释的元素必须是一个数字,值必须必须大于等于value
    • @DecimalMax(value):被注释的元素必须是一个数字,值必须必须小于等于value
    • @Size(max, min):被注释的元素大小必须在指定的范围内
    • @Digits(integer, fraction):被注释的元素必须是一个数字,值必须在可接收的范围内
    • @Past:被注释的元素必须是一个过去的日期
    • @Future:被注释的元素必须是一个将来的日期
    • @Pattern:被注释的元素必须符合指定的正则表达式

SpringMVC数据校验

  • Spring4.0拥有自己独立的数据校验框架,同时支持JSR303标准的校验框架
  • Spring在进行数据绑定时,可同时调用校验框架完成数据的校验工作。在SpringMVC中,可直接通过注解驱动的方式进行数据校验
  • Spring的LocalValidatorFactoryBean既实现了Spring的Validator接口,也实现了JSR303的 Validator接口,只要在Spring容器中定义了一个LocalValidatorFactoryBean,即可将其注入到需要数据校验的Bean中
  • Spring本身并没有提供JSR303的实现,所以必须手动引入JSR303的实现jar
  • <mvc:annotation-driven/> 会默认装配好一个LocalValidatorFactoryBean,通过在处理方法的入参上标注@Valid注解即可让SpringMVC在完成数据绑定后执行数据校验的工作
  • 在已经该标注了JSR303注解的表单对象前标注一个@Valid,SpringMVC框架在将请求参数绑定到该入参对象后,就会调用校验框架根据注解声明的校验规则实施校验
  • SpringMVC是通过对处理方法签名的规约来保存校验结果的
    • 前一个表单对象的校验结果保存到随后的入参中,这个保存校验结果的入参必须是BindingResultErrors类型
    • 这两个类都在org.springframework.validation包中

上手操作

  • 使用JSR303验证标准
  • 加入hibernate validator 验证框架jar包
  • springMvc 配置文件中添加<mvc:annotation-driven/>
  • 需要在bean的属性上添加对应的注解
  • 在目标方法bean类型的前面添加@Valid注解
  • 验证出错转向页面
  • 错误消息显示,将错误消息国际化
public class Car{
    @NotNull
    private Stirng name;
    
    @Max(18)
    private Integer age;
    

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }

}
@RequestMapping("/testValidate")
public String testValidate(@Valid Car car, BindResult result, 
            Map<String, Object> map, HttpservletRequrst request, HttpServletResponse response){
    response.setCharacterEncoding("utf-8");
    
    System.out.println("car: "+car);
    if(result.getErrorCount()>0){
        System.out.println("出错了");
        for(FieldError error: result.getFieldErrors()){
            System.out.println(error.getField()+" : "+error.getDefaultMessage());
        }
        map.put("car", car);
        return "/File1";
    }
    
    return "success";
}
  • 加载国际化资源文件:
    • 新建资源文件 ValidationMessages.properties
    • key值为 NotEmpty.car.name格式(注解名.类名首字母小写.属性名)
    • springMvc中配置
NotEmpty.car.name=名字得添上啊
Min.car.age=未满18岁不能进入
<!--springmvc中配置-->
<mvc:annotation-driven validator="validator"></mvc:annotation-driven>

<!--jsr303数据验证-->
<bean id="validator" 
      class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <!--hibernate校验器-->
    <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
    <!--指定校验使用的资源文件,在文件中配置校验信息,如果不指定则默认使用classpath下的ValidationMessages.properties-->
    <property name="validationMessageSource" ref="messageSource"/>
</bean>

<!--配置国际化资源文件-->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basenames">
        <list>
            <value>classpath:ValidationMessages</value>
        </list>
    </property>
    <property name="fileEncodings" value="UTF-8" />
    <property name="cacheSeconds" value="60" />
</bean>

<!--还可以这样因为mvc annotation driven 注解默认装配了LocalValidatorFactoryBean-->
<!--第二种配置方式-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basenames" value="ValidationMessages"></property>

</bean>

  • 每个属性在数据绑定和数据校验发生错误的时候,都会生成一个对应的FieldError对象
  • 当一个属性校验失败后,校验框架会为该属性生成4个消息代码,这些代码以校验注解类名为前缀,结合modleAttribute、属性名以及属性类名生成多个对应的消息代码例如User类的password属性标注了@Pattern注解,当该属性的值不满足校验规则的时候,会产生如下四个错误代码
    • Pattern.user.password
    • Pattern.password
    • Pattern.java.long.Stirng
    • Pattern
  • 当使用SpringMVC标签显示错误消息的时候,SpirngMVC会查看web上下文中是否装配了对应的国际化资源消息,如果没有,则显示默认的错误消息,否则使用国际化消息

image.png

自定义校验注解

  • 新建一个注解
//其中的三个属性为校验所必须的三个属性。
//@constraint注解指示具体的校验类:

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {MyConstraintValidator.class})
public @interface Myconstraint{
    String message() default "{javax.validation.constraints.NotNull.message}";
    
    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };
}
public class MyConstraintValidator implements ConstrainValidator<Myconstraint, String>{
    
    @Override
    public void initialize(Myconstraint constraintAnnotation){
        System.out.println("initialize...");
    }
    
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context){
        System.out.println(value);
        String defaultConstraintMessageTemplate = context.getDefaultConstrainMessageTemplate();
        System.out.println(defaultConstraintMessageTemplate);
        return true;
    }
}

  • 校验类需要实现 ConstraintValidator 接口,第一个泛型是自己新建的校验注解,第二个泛型是校验什么字段类型。
  • 其中的 initialize 方法不是在项目启动的时候调用,是在这个注解第一次使用的时候调用。isValid 方法是具体的校验方法,返回true校验成功,返回false校验失败.
  • 这个方法上的第一个参数value:是校验字段的值,第二个参数是该校验注解注解信息。
  • 使用的时候就在需要校验的字段上面添加@Myconstraint注解