数据验证分为客户端验证和服务器验证,客户端验证主要是过滤正常用户的误操作,主要通过JavaScript完成;仅有客户端验证是不够的,攻击者还可以绕过客户端验证直接进行非法输入,这样可能会引起系统的异常,为了确保数据的合法性,还必须加上服务器的验证。
服务器端验证是整个应用阻止非法数据的最后防线,主要通过在应用中通过编程实现。SpringMVC的Converter和Formatter在进行类型转换时,是将输入数据转换成领域对象的属性值(一种Java类型),一旦成功,服务器端验证器就会介入。也就是说,在SprignMVC框架中,先进行数据类型转换,再进行服务器端验证。
在SpringMVC框架中,有两种方法可以验证输入数据(服务器端验证):
(1)利用SpringMVC自带的验证框架。
(2)利用JSR303实现。
Spring验证器
Validator接口
创建自定义Spring验证器,需要实现org.springframework.validation.Validator接口。
该接口有两个接口方法:
boolean supports(Class<?> klass)
void validate(Object object, Errors errors)
supports方法返回True时,验证器可以处理指定的Class。validate方法的功能是验证目标对象object,并将验证错误消息存入errors对象。往errors对象存入错误消息的方法是reject或rejectValue方法。这两个方法的部分重载方法如下:
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框架就会在消息属性文件中查找错误代码,获取相应错误消息。例:
errors.rejectValue("gprice","gprice.invalid");//gprice.invalid为错误代码
ValidationUtils类
org.springframework.validation.ValidationUtils是一个工具类,该类有几个方法帮助判定值是否为空。
例:
if(goods.getGname()==null || goods.getGname().isEmpty()){
errors.rejectValue("gname","goods.gname.required")
}
上述if语句可以使用ValidationUtils类的rejectIfEmpty方法:
ValidationUtils.rejectIfEmpty(errors,"gname","goods.gname.required");
验证示例
1、定义领域模型类Goods,封装输入参数。
2、编写验证器类GoodsValidator,使用@Component注解将GoodsValidator类声明为组件。
package validator;
import java.util.Date;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import domain.Goods;
@Component
public class GoodsValidator implements Validator{
@Override
public boolean supports(Class<?> klass) {
// 要验证的Model,返回值为false则不验证。
return Goods.class.isAssignableFrom(klass);
}
@Override
public void validate(Object object, Errors errors) {
Goods goods = (Goods)object;//object要验证的对象
//goods.gname.required是错误消息属性文件中的编码
ValidationUtils.rejectIfEmpty(errors, "gname", "goods.gname.required");
ValidationUtils.rejectIfEmpty(errors, "gdescription", "goods.gdescription.required");
if(goods.getGprice() > 100 || goods.getGprice() < 0){
errors.rejectValue("gprice", "gprice.invalid");
}
Date goodsDate = goods.getGdate();
//在系统时间之后
if(goodsDate != null && goodsDate.after(new Date())){
errors.rejectValue("gdate", "gdate.invalid");
}
}
}
3、编写错误消息属性文件。在/WEB-INF/resources目录下,编写属性文件errorMessages.properties。文件内容如下:
goods.gname.required=请输入商品名称
goods.gdescription.required=请输入商品详情
gprice.invalid=价格在0~10之间
gdate.invalid=创建日期不能在系统日期之后
Unicode编码(Eclipse带有将汉字转换成Unicode编码的功能)的属性文件内容如下:
goods.gname.required=\u8BF7\u8F93\u5165\u5546\u54C1\u540D\u79F0\u3002
goods.gdescription.required=\u8BF7\u8F93\u5165\u5546\u54C1\u8BE6\u60C5\u3002
gprice.invalid=\u4EF7\u683C\u57280-100\u4E4B\u95F4\u3002
gdate.invalid=\u521B\u5EFA\u65E5\u671F\u4E0D\u80FD\u5728\u7CFB\u7EDF\u65E5\u671F\u4E4B\u540E\u3002
属性文件创建完成后,想要告诉SpringMVC从该文件中获取错误消息,则需要在配置文件中声明一个messageSource bean:
<!-- 配置消息属性文件 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/WEB-INF/resource/errorMessages"/>
</bean>
JSR 303验证
未完待续……