Spring学习笔记-springMVC校验框架

输入校验是Web开发最重要的任务之一。SpringMVC作为当今最流行的MVC框架,自然也对输入校验做了很好的支持。

在SpringMVC中可以用两种方式来进行输入校验
1)利用SpringMVC自带的校验框架
2)利用JSR 303

下面我们对着两种校验方式做详细的描述。

  • Spring验证框架
    spring的验证框架入口为Validator接口,该接口的签名是这样的:
public interface Validator {
     boolean supports(Class<?> clazz);
     void validate(Object target, Errors errors);
}

Spring在完成校验动作时,首先会调用supoorts()方法,判断当前的object在不在校验队列中,如果在,则紧接着调用validate方法,进行校验。
在应用校验框架是,我们最常用的可能就是Errors接口了,这个接口有一些实现类,我们可以吧它理解为一个存放错误信息的容器,里面存放着一系列的域错误(FieldError)和对象错误(ObjectError),同时,它还提供了获取错误信息和加入错误信息的方法,例如:

void reject(String errorCode, Object[] errorArgs, String defaultMessage);
void rejectValue(String field, String errorCode, Object[] errorArgs, String defaultMessage);
boolean hasFieldErrors();
List<FieldError> getFieldErrors();
List<ObjectError> getAllErrors();
......

利用这些方法,我们就可以在这个“错误容器”里方便的存取错误数据。

在进行数据校验时,我们以往经常要写很多向下面这样 代码:

if(firstName == null && firstName.isEmpty())
        errors.rejectValue("price");

或者

if(firstName == null || firstName.trim().isEmpty())
     errors.rejectValue("price");

这样的代码虽然是必须的,但是大量的重复往往令人头疼,幸好,Spring为我们提供了一个工具类,可以很好的解决上面的问题,ValidtionUtils,利用这个工具类就可以吧具有上面功能 代码写的很优雅:

ValidationUtils.rejectIfEmpty("price");
ValidationUtils.rejectIfEmptyOrWhitespace("price");

该工具类还保护很多重载方法,大家可以自己查看API文档。
看起来也是蛮强大的吧……

下面,我们就用一个简单是范例,来说明一下Spring校验框架的基本用法。

1)首先,创建一个POJO类

@SuppressWarnings("serial")
public class Product implements Serializable{

    private String name;
    private String description;
    private Float price;
    private Date productionDate;
    setter/getter....
}

2)编写一个实现了Validator接口的校验器

public class ProductValidator implements Validator{
    Logger logger = Logger.getLogger(ProductValidator.class);
    //spring通过调用该方法确定是否对某个对象进行校验(validate(target,errors))
    @Override
    public boolean supports(Class<?> clazz) {
        //验证类型是否一样
        return Product.class.isAssignableFrom(clazz);
    }
    @Override
    public void validate(Object target, Errors errors) {
        Product product = (Product)target;    //强转对象类型
        //校验开始
        ValidationUtils.rejectIfEmpty(   //验证null 和 "" 空字符串
                errors, 
                "name",  //域名称
                "productname.required"       //错误编码
                );

        ValidationUtils.rejectIfEmpty(
                    errors, 
                    "price", 
                    "price.required"
                  );

        ValidationUtils.rejectIfEmpty(errors, 
                 "productionDate", "productionDate.required");
        //手动向errors中添加错信息的示例
        Float price = product.getPrice();
        if(price != null && price < 0){ errors.rejectValue("price", "price.negative");}
        Date productionDate = product.getProductionDate();
        if(productionDate != null){
            //与当前时间比较,如果在当前时间后,则判定错误 
            if(productionDate.after(new Date())){
                logger.info(" productDate error");
                errors.rejectValue("productionDate", "productiondate.invalid");
            }
        }
    }
}

3)创建一个用于显示错误信息的资源文件(.properties)

productname.required.product.name=Please enter a product name
price.required=Please enter a price
productiondate.required=Please enter a production date
productiondate.invalid=Invalid production date. Please ensure the production date is not later than today

4)紧接着,要把这个资源文件注册到spring环境中,这样在检验器中才能得到具体的错误提示。

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
              <property name="basename" value="/WEB-INF/resource/messages"></property>
        </bean>

5)最后,要编写一个应用了校验器的Controller来完成校验任务。

/** * @Description: 校验框架测试 controller. * @Author:Zander * @CreateDate:Aug 8, 2015 * @Company: */
@Controller
public class ProductController {

    private static final Logger logger = Logger.getLogger(ProductController.class);

    @RequestMapping(value="/product_input")
    public String inutProduct(Model model){
        model.addAttribute("product", new Product());
        return "productionForm";
    }

    public String saveProduct(@ModelAttribute Product product,
            BindingResult bindingResult, Model model){

        ProductValidator productValidator = new ProductValidator();
        productValidator.validate(product, bindingResult);   //调用校验器

        //校验未通过
        if(bindingResult.hasErrors()){
            //得到校验是写入的错误信息
            FieldError fieldError = bindingResult.getFieldError();
            logger.info("Code:" + fieldError.getCode() + ", field:" + fieldError.getField());
            //返回表单视图
            return "productForm";
        }

        //校验通过

        model.addAttribute("product", product);
        return "productDetails";
    }
}

完成。

  • 利用JSR 303进行校验。
    首先要说明的是,JSR是一系列的规范,它本身并没有使用意义,如果想在JSR规范的基础上完成校验,则需要导入它的实现。目前JSR303的实现有两种:Hibernate Validator 和 Apache BVal。

下面先说明一下JSR 303的规范。

 @AssertFalse    应用于boolean属性,该属性值必须为False  
      @AssertFalse boolean hasChildern
 @AssertTrue     应用于boolean属性,该属性值必须为True      
      @AssertTrue boolean isEmpty
 @DecimalMax     该属性必须为小于或等于指定的小树                           @DecimalMax("1.1") BigDecimal price
 @DecimalMin     该属性必须大于或等于指定值的小数                           @DecimalMin("0.04")
 @Digits         该属性必须在指定的范围内                    
      @Digits(integer=5,fraction=2)
      BigDecimal price;
 @Future         该属性值必须是未来的一个日期                              @Future  Date shippingDate
 @Max            该属性值必须是一个小于或等于指定数值的整数                   @Max(150) int age
 @Min            该属性值必须是一个大于或等于指定数值的整数          
      @Min(150)  int age
@NotNull  String firstName
@Null           该值必须为null                          
      @Null String testString
@Past           该值必须为过去的一个时间                                   @Past Date birthDate
@Pattern        该属性hi必须与指定的常规表达式匹配                          @Pattern(regext="\\d{3}")
@Size            该属性值必须在制定范围内                                  @Size(min=2,max=140) String description

利用这些注解直接表述bean中的域就可以方便的实现校验。

下面我们还是通过一个小例子,来看一下它的具体用法。
1)创建JavaBean,利用JSR注解标注

/** * @Description: JSR校验 * @Author:Zander * @CreateDate:Aug 8, 2015 * @Company: */
public class Product2 {

    @Size(min=1,max=10)
    private String name;
    private String description;
    private Float price;

    @Past
    private Date productionDate;
    geter()/setter()
    ...
}

2)创建Controller,不用实现校验器了哦!这是重点。

/** * @Description: JSR 校验测试Controller. * @Author:Zander * @CreateDate:Aug 8, 2015 * @Company: */
@Controller
public class ProductController2 {

    private static final Logger logger = Logger.getLogger(ProductController2.class);

    public String inutProduct(Model model){
        model.addAttribute("product", new Product2());
        return "productForm";
    }

    public String saveProduct(@Valid @ModelAttribute Product2 product2,
            BindingResult bingBindingResult, Model model){

        //判断是否通过校验 此处利用@Valid 注解 加上 JSR注解 就不用显示的创建校验器
        if(bingBindingResult.hasErrors()){
            FieldError fieldError = bingBindingResult.getFieldError();
            logger.info("Code:" + fieldError.getCode() + ", object:" + fieldError.getObjectName() + 
                     ", field : " + fieldError.getField());
            return "productForm";
        }
        //save product
        model.addAttribute("product", product2);
        return "productDetails";

    }
}

3)配置一个资源文件,用于提示信息的显示。

Size.product.name=Product name mast be 1 to 10 characters long
Past.product.productionDate=Production date must a past time

4)再像上面的那样,注册资源文件到spring容器。

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
              <property name="basename" value="/WEB-INF/resource/messages"></property>
        </bean>

哦了,搞定,就这么用。

你可能感兴趣的:(spring)