SpringMVC的数据验证

  • 数据验证
  • Spring 验证器
  • Validator接口
  • ValidationUtils类
  • 验证示例
  • JSR 303验证
  • 下载
  • 配置验证器
  • 标注类型
  • 空检查
  • boolean检查
  • 长度检查
  • 日期检查
  • 数值检查
  • 其他检查
  • 验证示例
  • 运行效果

数据验证

数据验证主要用于过滤用户输入的错误数据,保证数据的合法性。
数据验证分为客户端验证服务器端验证。客户端验证主要通过JavaScript代码实现数据合法性校验;服务器端是整个应用程序阻止非法数据的最后防线。
在SpringMVC中,进行数据验证可以利用Spring自带的验证器框架验证数据,也可以使用JSR303实现数据验证。

Spring 验证器

Validator接口

创建自定义Spring验证器需要实现org.springframework.validation.Validator接口,该接口主要有两个方法:

  • boolean supports(Class<?> aClass):当返回true时,验证器可以处理指定的Class
  • void validate(Object object, Errors errors):该方法功能是验证目标对象object,并将验证的错误消息存放在Errors对象中。

Errors对象存入错误消息主要有rejectrejectValue方法:

void reject(String errorCode);
void reject(String errorCode,String defaultMessage);
void rejectValue(String field,String errorCode);
void rejectValue(String field,String errorCode,String defaultMessage)

一般只要给reject或者rejectValue方法一个错误代码,SpringMVC就会在消息属性文件中查找错误代码,获取错误消息。例如:

if (productDate != null && productDate.after(new Date())) {
	//date指定验证错误对象的属性域,date.invalid为错误代码
	errors.rejectValue("date", "date.invalid");
}

在上述中,“date.invalid”就是对应消息属性文件的key。例如有个消息属性文件如下:

price.invalid=价格在0和100之间
date.invalid=需要的是一个过去的时间

当然也可以直接写入错误消息,即:

errors.rejectValue("date", "需要的是一个过去的时间");
ValidationUtils类

org.springframework.validation.ValidationUtils是一个工具类,提供了相关的方法帮助判断数据是否为空。
例如:

//判断目标对象name属性是否为null或者empty
ValidationUtils.rejectIfEmpty(errors, "name", "商品名称不能为空");
//判断目标对象name属性被trim后是否为null或者empty
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "商品名称不能为空");
验证示例

需要验证的目标对象

public class Product {
	private String name; //不能为空
	private String description; //不能为空
	private double price; //0到100之间
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	private Date date;  //不能在当前时间之后
	//省略setter和getter方法
}

使用Spring验证器进行数据验证,不需要添加额外配置,只需要添加@Component注解将自定义验证器类声明为验证组件,并在Controller控制器中使用@Resource或者@Autowired注解注入自定义验证器。
自定义验证器类

@Component
public class ProductValidator implements Validator {
	@Override
	public boolean supports(Class<?> aClass) {
		// 要验证的model,返回值为false则不验证
		// 判断参数aClass是否是Product本身或者子类
		return Product.class.isAssignableFrom(aClass);
	}
	@Override
	public void validate(Object object, Errors errors) {
		Product product = (Product) object; // object要验证的对象
		// 往Errors对象存入错误消息
		ValidationUtils.rejectIfEmpty(errors, "name", "商品名称不能为空");
		ValidationUtils.rejectIfEmpty(errors, "description", "商品描述不能为空");
		if (product.getPrice() > 100 || product.getPrice() < 0) {
			errors.rejectValue("price", "价格在0和100之间");
		}
		Date productDate = product.getDate();
		// 在系统时间之后
		if (productDate != null && productDate.after(new Date())) {
			errors.rejectValue("date", "创建日期不能是将来时间");
		}
	}
}

在控制器中执行验证

@Controller
@RequestMapping("/product")
public class ProductController {
	//省略相关代码
	@Resource
	private Validator validator;
	
	//省略相关代码
	@RequestMapping("/add")
	// BindingResult对象用于接收校验返回的错误消息,必须紧跟在验证对象的后面(两者相邻)
	public String addProduct(Product product, BindingResult result, Model model) {
	//执行数据验证,传入目标对象和错误消息接收对象
		this.validator.validate(product, result);
		if (result.hasErrors()) { // 如果校验错误
			for (FieldError error : result.getFieldErrors()) {
			//后台打印错误消息
				System.out.println(error.getField() + ":" + error.getDefaultMessage());
			}
			//把错误消息写进model,用于前端显示
			model.addAttribute("errors", result.getFieldErrors());
			return "addProduct";
		}
		//省略相关代码
		return "productList";
	}
}

JSR 303验证

JSR 303验证主要有两个方式实现,一个是Hibernate Validator,一个是Apache BVal 。这里主要使用Hibernate Validator进行数据验证。

配置验证器
<!-- 配置数据校验 -->
<bean id="localValidator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
	<!-- 
		如果将错误消息放在属性文件,则需要配置属性文件,
		并且配置以下属性,将属性文件与HibernateValidator关联
	-->
	<!-- Hibernate校验器 -->
	<!-- <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/> -->
	<!-- 指定校验使用的资源文件,在文件中配置校验错误消息,如果不指定,默认使用classpath下的ValidationMessages.properties -->
	<!-- <property name="validationMessageSource" ref=""/> -->
</bean>
<!-- 配置属性文件关联HibernateValidator时需要设置validator的值-->
<mvc:annotation-driven validator="localValidator"/>

如果没有属性文件,则直接配置LocalValidatorFactoryBean即可。

<bean id="localValidator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
标注类型

JSR 303不需要写验证器,但需要使用它的标注类型在模型属性上进行约束。

空检查
  • @Null :验证对象是否为null,不为null即验证错误。
  • @NotNull :验证对象是否为null,无法检测长度为0的字符串。
  • @NotBlank:检查约束字符串是不是null,并且判断被trim后长度是否大于0。
  • @NotEmpty :检查约束元素是否为null,或者为empty。
@NotBlank(message = "商品名不能为空")
private String name;
boolean检查
  • @AssertTrue:验证boolean属性是否为true。
  • @AssertFalse:验证boolean属性是否为true。
长度检查
  • @Size(min= ,max= ):验证对象(Array、Collection、Map、String)长度是否在给定范围。
  • @Length(min= ,max= ):验证字符串长度是否在给定范围。
日期检查
  • @Past:验证Date和Calendar对象是否在当前时间之前。
  • @Future:验证Date和Calendar对象是否在当前时间之后。
@Past(message = "创建日期需要是一个过去时间")
private Date date;
数值检查
  • @Min:验证Number和String对象是否大于指定值。
  • @Max:验证Number和String对象是否小于指定值。
  • @DecimalMax: 被标注的值必须不大于约束中指定的最大值,这个约束的參数是一个通过BigDecimal定义的最大值的字符串表示,小数存在精度。
  • @DecimalMin:被标注的值必须不小于约束中指定的最小值,这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示,小数存在精度。
  • @Digits: 验证Number和String的构成是否合法。
  • @Digits(integer= , fraction=): 验证字符串是否符合指定格式的数字,integer 指定整数精度,fraction 指定小数精度。
  • @Range(min= , max= ):检查数字是否介于min和max之间。
  • @CreditCardNumber:信用卡验证。
  • @Email:验证是否为邮件地址,如果为null,不进行验证, 直接通过。
@Range(min = 0, max = 100, message = "价格只能在0和100之间")
private double price;
其他检查
  • @Pattern:验证String对象是否符合正则表达式。
  • @Valid: 对关联对象进行校验,如果关联对象是个集合或者数组,那么对其中的元素进行校验,如果是一个map, 则对其中的值部分进行校验。

在Controller控制器中的处理方法中,通过@Valid注解指定需要验证的对象。

@RequestMapping("/add")
// BindingResult对象用于接收校验返回的错误消息,必须紧跟在验证对象的后面(两者相邻)
public String addProduct(@Valid Product product, BindingResult result, Model model)
验证示例

需要验证的目标对象类

public class Product {
	@NotBlank(message = "商品名不能为空")
	private String name;

	@NotBlank(message = "商品描述不能为空")
	private String description;

	@Range(min = 0, max = 100, message = "价格只能在0和100之间")
	private double price;

	@Past(message = "创建日期需要是一个过去时间")
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	private Date date;
	//省略setter和getter方法
}

控制器关键代码

@Controller
@RequestMapping("/product")
public class ProductController {
	// 获得日志记录对象
	private static final Log logger = LogFactory.getLog(ProductController.class);
	@Autowired
	private ProductService productService;
	
	@RequestMapping("/add")
	// BindingResult对象用于接收校验返回的错误消息,必须紧跟在验证对象的后面(两者相邻)
	public String addProduct(@Valid Product product, BindingResult result, Model model) {
		if (result.hasErrors()) { // 如果校验错误
			for (FieldError error : result.getFieldErrors()) {
				System.out.println(error.getField() + ":" + error.getDefaultMessage());
			}
			model.addAttribute("errors", result.getFieldErrors());
			return "addProduct";
		}
		if (!productService.add(product)) {
			return "addProduct";
		}
		logger.info("添加成功");
		model.addAttribute("products", productService.getProducts());
		return "productList";
	}
}

运行效果

spring 手动调用验证参数 spring 数据验证_spring 手动调用验证参数


spring 手动调用验证参数 spring 数据验证_数据验证_02