SpringMVC学习指南【笔记4】数据绑定、表单标签库、转换器、格式化、验证器

表单标签库

<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<form:form commandName="book" action="saveBook" method="post">
</form:form>
<form:input id="city" path="city" />
<form:password id="pwd" path="password" cssClass="normal" />
<form:hidden path="productId" />
<form:textarea path="note" tabindex="4" rows="5" cols="80" />
<form:checkbox path="outOfStock" value="out of stock" />
<form:radiobutton path="newsletter" value="computing now" />
<form:radiobutton path="newsletter" value="modern health" />
<form:checkboxes path="category" items="${categoryList}" />
<form:radiobuttons path="category" items="${categoryList}" />
<form:select id="category" path="category.id" items="${categories}" itemLabel="name" itemValue="id" >
    <option value="0">-- please select --</option>
</form:select>
<form:errors path="*" /><!--显示了所有字段的错误信息-->
<form:errors path="author" /><!--显示了author属性相关的错误信息-->

jstl

<%@taglib prefix="c" uri="http://java.sun.com/jsp/core" %>

 

转化器和格式化

转换器converter,需要实现org.springframework.core.convert.converter.Converter接口

格式化formatter,需要实现org.springframework.format.Formatter接口

可以利用转化器和格式化来引导spring mvc应用程序中的数据绑定。Converter是一般工具,可以将任意类型转换成另一种类型,而Formatter只能将String类型转换成另一种Java类型。Formatter更适合于web层。

 

验证器

在spring mvc中,有两种方式可以验证输入,一是利用spring自带的验证框架,二是利用JSR 303实现。

Converter和Formatter作用于field级,在mvc应用程序中,将String转换或格式化成另一种Java类型;验证器作用于object级,决定某一个对象中的所有field是否均是有效的以及是否遵循某些规则。

如果一个应用程序中既使用了Formatter又使用了Validator,那么在调用Controller期间,先格式化,格式化完成之后验证器介入。

验证器要实现org.springframework.validation.Validator接口。

指定的验证器处理指定的Class文件,supports方法将返回true,validate方法会验证目标对象,并将验证错误填入Errors对象中。

工具类org.springframework.validation.ValidationUtils有助于编写spring验证器。

if(firstName==null || firstName.isEmpty()){
    errors.rejectValue("price");
}
// 相当于
ValidationUtils.rejectIfEmpty("price");

if(firstName==null || firstName.trim().isEmpty()){
    errors.rejectValue("price");
}
// 相当于
ValidationUtils.rejectIfEmptyOrWhitespace("price");
package com.xsl.springmvc;

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

public class ProductValidator implements Validator {
    @Override
    public boolean supports(Class<?> arg0) {
        return Product.class.isAssignableFrom(arg0);
    }
    @Override
    public void validate(Object arg0, Errors arg1) {
        Product product = (Product) arg0;
        ValidationUtils.rejectIfEmpty(arg1, "name", "productname.required");
        ValidationUtils.rejectIfEmpty(arg1, "price", "price.required");
        Float price = product.getPrice();
        if(price != null && price < 0){
            arg1.rejectValue("price", "price.negative");
        }
    }
}

写好验证器类之后,如果想要从某个属性文件中获取错误信息,则需要通过声明messageSource bean,告诉spring要去哪里找这个文件,例如:

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

上面代码意思是,错误码和错误信息可以在/WEB-INF/resource目录下的messages.properties文件中找到,例如:

productname.required=please enter a product name
price.required=please enter a price
date.invalid=invalid date

验证的三种方法:

方法一:new出验证器类对象,调用validate方法,并在BindingResult中调用hasErrors方法看是否生成错误信息。

package com.xsl.springmvc;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ProductController {
    private static final Log logger = LogFactory.getLog(ProductController.class);
    @RequestMapping(value="/saveProduct")
    public String saveProduct(@ModelAttribute Product product,BindingResult bindingResult,Model model){
        ProductValidator validator = new ProductValidator();
        validator.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";
    }
}

方法二:在controller中编写initBinder方法,并将验证器传到WebDataBinder,并调用其validate方法,会使验证器应用于Controller类中所有处理请求的方法。

    @InitBinder
    public void initBinder(WebDataBinder binder){
        // this will apply the validation to all request-handing methods
        binder.setValidator(new ProductValidator());
        binder.validate();
    }

方法三:利用@javax.validation.Valid对要验证的对象参数进行标注(Valid标注类型是在JSR 303中定义的)。

实体类上面嵌入约束

package com.xsl.springmvc;
import java.io.Serializable;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class Product implements Serializable {
    private static final long serialVersionUID = 748392348L;
    @Size(min=2,max=10)
    private String name;
    @NotNull
    private String description;
    @Min(0)
    private float price;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }
    
}

为了覆盖JSR303的错误信息,可以在属性文件中使用键,例如:

Size.product.name、NotNull.product.description、Min.product.price

在controller中,必须要对调用的方法的参数进行标注

    @RequestMapping(value="/saveProduct")
    public String saveProduct(@Valid @ModelAttribute Product product,BindingResult bindingResult,Model model){
        if(bindingResult.hasErrors()){
            FieldError fieldError = bindingResult.getFieldError();
            logger.info("code:"+fieldError.getCode()+",field:"+fieldError.getField());
            return "productForm";
        }
        model.addAttribute("product", product);
        return "productDetails";
    }    

为了定制来自验证器的错误信息,要在messages.properties文件中使用两个键。

Size.product.name = name must be 2 to 10 characters long
NotNull.product.description = description must be not null
Min.product.price = price must be greater than 0

JSR303约束

@AssertFalse  应用于boolean属性,该属性值必须为false

@AssertTrue  应用于boolean属性,该属性值必须为true

@DecimalMax  该属性值必须为小于或等于指定值的小数

@DecimalMin  该属性值必须为大于或等于指定值的小数

@Digits  该属性值必须在指定范围内,integer属性定义该数值的最大整数部分,fraction属性定义该数值的最大小数部分,例如@Digits(integer=5,fraction=2)

@Future  该属性值必须是未来的一个日期

@Max  该属性值必须是一个小于或等于指定值的整数

@Min  该属性值必须是一个大于或等于指定值的整数

@NotNull  该属性值不能为null

@Null  该属性值必须为null

@Past  该属性值必须是过去的一个日期

@Pattern  该属性值必须与指定的常规表达式相匹配

@Size  该属性值必须在指定范围内

posted @ 2018-12-24 17:38  HelloWorld1815  阅读(274)  评论(0编辑  收藏  举报