Spring MVC【五】数据验证

目录

一、JavaBean标准效验

二、Spring核心容器的验证

1.Bean有效性验证

2.方法级别的有效性验证

三、Spring MVC容器的验证

四、验证器配置及增加自定义验证器

自定义验证器


一、JavaBean标准效验

Java官方对Bean的验证定义经历了三个版本的规范:

  • Bean Validation 1.0(JSR-303)。主要是对JavaBean进行验证,比如Bean的属性是否可以为空。该规范定义了基于注解的JavaBean验证方式,常用的注解有@NotNull、@Max等。
  • Bean Validation 1.1(JSR-349)。提供了方法级别的验证和依赖注入的验证支持。
  • Bean Validation 2.0(JSR-380)。支持容器效验、日期效验(@Past、@Future)及拓展元素数据(@Email、@Positive和@Negative等)

Java官方只是提供了验证的标准接口(javax.validation),并没有提供具体的实现。使用Spring+Hibernate的组合进行开发就可以使用Hibernate的验证实现,但如果使用MyBatis等其他持久层框架,则选择Hibernate的Bean验证就不合适了。但Apache提供了Bval用来实现标准接口规范。使用JavaBean Validation的标准验证接口需要导入javax.validation依赖包及Bval实现的依赖包,使用Maven导入依赖配置如下:

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>
<!-- 除了使用org.apache.bval.bundle,还可以使用org.hibernate.validator。(具体可以视情形而定) -->
<dependency>
    <groupId>org.apache.bval</groupId>
    <artifactId>org.apache.bval.bundle</artifactId>
    <version>2.0.0</version>
</dependency>

下面以User类中年龄的整型属性userAge为例,使用@Max注解限定最大用户年龄在100岁,属性的限定注解如下:

@Max(value = 100, message = "年龄太大了")    //message用于指定验证不合格后的提示消息
private int userAge;

添加限定注解后,就可以构造验证器(Validation)对象的validate()方法对User类型对象中的属性值进行验证。

public static void main(String[] args) {
    // 使用Validation构造器工厂并获取验证器(获取的就是Bval的验证器对象)
    Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
    User user = new User();
    user.setUserAge(180);
    // 对user对象进行验证并返回验证结果集
    Set<ConstraintViolation<User>> violations = validator.validate(user);
    // 打印有问题的属性和错误信息
    for (ConstraintViolation<User> data : violations) {
        System.out.println(data.getPropertyPath().toString() + " --- " + data.getMessage());
    }
    // 控制台输出:userAge --- 年龄太大了
}

除@Max注解外,JavaBean Validation提供的常用限制注解及其分类如下图所示,这些限制注解可以使用在方法、字段、参数和构造器等元素中。

Validation会通过SPI的方式找到所有ValidationProvider接口的实现只要加入依赖包,就会被自动加载。上面引入了Bval依赖包,也就是使用JavaBean 验证API的时候,默认使用Bval实现。

二、Spring核心容器的验证

数据绑定类DataBinder除了数据转换和绑定的功能之外,DataBinder最重要的作用就是可以用来验证绑定对象的有效型。Spring支持标准的JavaBean Validation及其相关实现(比如Bval)对JavaBean的验证,另外,Spring还支持方法级别的验证和依赖注入的验证。当然,也需要在Spring项目中导入验证标准接口及实现的依赖包。Spring会默认从classpath下找到可用的Bean Validation,除非需要自定义验证器,一般不需要显式地配置Validation。Spring可以在Bean初始化后对其进行有效性验证,也可以对方法级别地参数和返回值进行效验

1.Bean有效性验证

Spring通过PostProcessor的初始化回调方式对Bean进行有效性效验,实现方式是配置BeanValidationPostProcessor的Bean,在XML中的配置如下:

<bean class="org.springframework.validation.beanvalidation.BeanValidationPostProcessor"></bean>

沿用上面对User类中的userAge进行验证,上面userAge属性已经有@Max(value = 100, message = "年龄太大了")的限定,如果Bean的配置如下:

<bean id = "user" class="com.mec.springmvc.model.User">
    <property name="userAge" value="180"></property> <!-- 超过限制的设置 -->
</bean>

以上配置完成后,容器在初始化启动的时候就会提示初始化Bean失败的错误。

2.方法级别的有效性验证

传统的开发方式是开发者在方法代码中自行处理判断逻辑,比如参数是否有效,返回值是否为空。Spring提供了MethodValidationPostProcessor可以对方法参数和返回值进行验证,但同样需要配置初始化回调的Bean,在XML中配置如下:

<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"></bean>

配置以上Bean之后,在需要验证的方法类上标注@Validated注解之后(用在类型、方法和方法参数上。但不能用于成员属性),就可以使用限制注解对参数和返回值进行限制设定了,示例如下:

@Validated // Spring验证注解。告诉MethodValidationPostProcessor此Bean需要开启方法级别验证支持
public class UserService {
    // 添加了参数和返回值限制注解的方法。
    // @Valid注解可以用在方法、构造函数、方法参数及返回值和成员属性上,注意如果被@Valid注解的类中有另外一个引用类B的成员b
    // 那么要想成员b中的限制注解生效,则需要在该成员上添加@Valid。(也就是说验证对像为自定义引用类型的话需要逐层添加,也就是嵌套验证)
    public @Valid User get(@NotNull(message = "参数不能为空") String name) {
        User user = new User();
        user.setUserAge(180);
        return user;
    }
}

由于userAge属性上添加了@Max注解对其进行了限制,且get()方法返回User对象,添加@Valid注解之后返回的user对象中的@Max限制注解就会生效。如果不合法会输出message里的值。

@Validated和@Valid注解的异同

  • @Validated和@Valid功能很类似,都可以在controller层开启数据校验功能。
  • @Valid可以注解在成员属性(字段)上,但是@Validated不行(也是基于这一点,所以该注解不能做嵌套验证,但是可以配合@Valid做嵌套验证)。
  • @Valid只能用在controller层的类上。@Validated可以用在其他被spring管理的类上。(比如这里的UserService,如果将其类上的注解换成@Valid则验证不能生效)
  • @Validated和@Valid都可以用在controller层的参数前面,但这只能在controller层生效。
  • @Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制。没有添加分组属性时,默认验证没有分组的验证属性;@Valid不支持分组。

BeanValidationPostProcessor和MethodValidationPostProcessor会自动查找类路径下的验证器并使用,也可以通过validator属性注入自定义的验证器。

三、Spring MVC容器的验证

在SpringMVC中,前端参数传递通过WebDataBinder转换为后端类型对象,同时可以对转换的对象进行效验。在SpringMVC的请求映射方法中,前端请求参数会自动匹配请求方法的对象参数,在请求方法的参数中可以使用@Validated注解对装配的参数进行验证。验证出错不会像对Bean和方法的验证那样抛出异常,而是记录到BindingResult对象中,在该请求处理方法中增加一个BindingResult的参数就可以获取BindingResult的结果了,如下:

@RequestMapping("/saveUser")
public User save(@Validated User user, BindingResult bindingResult) {    //BindingResult必须跟在实体类之后
    List<ObjectError> list = bindingResult.getAllErrors();
    for (ObjectError objectError : list) {
        FieldError fe = (FieldError) objectError;
        System.out.println(fe.getField());// 错误的属性:userAge
	System.out.println(fe.getRejectedValue());// 错误的值180
	System.out.println(fe.getCode());// 错误码,Max
    }
    return user;
}

BindingResult除了可以获取错误信息外还可以得到目标对象,模型对象和属性编辑器注册器(PropertyEditorRegistry)。

四、验证器配置及增加自定义验证器

由于Validation会通过SPI的方式找到所有ValidationProvider接口的实现,所以一般情况下不需要对验证器进行显式的配置如果有多个验证器实现需要选择或者需自定义错误信息,在SpringMVC中通过指定可以通过<mvc:annotation-driven>的validator属性指定验证器JavaBean Validation标准接口有多个实现,常见的有BVal和Hibernate。配置示例如下:

<mvc:annotation-driven validator="validator" />
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <!-- 校验器提供类,这里使用Bval的校验。当然还可以指定org.hibernate.validator.HibernateValidator,前提是有相关的依赖包 -->
    <property name="providerClass" value="org.apache.bval.jsr.ApacheValidationProvider"></property>
</bean>

自定义验证器

//org.springframework.validation.Validator
public class UserValidator implements Validator {

	// 用于限定验证对象的类型
	@Override
	public boolean supports(Class<?> clazz) {
		return User.class.isAssignableFrom(clazz); // 用于判断类是否为给定类或者其子类
	}

	// 验证的方法,其中,errors用于存放验证失败的信息
	@Override
	public void validate(Object target, Errors errors) {
		User user = (User) target;
		int userAge = user.getUserAge();
		if (userAge < 0) {
			errors.rejectValue("age", "非法年龄值");    //添加错误信息
		} else if (userAge > 120) {
			errors.rejectValue("age", "年龄过大");
		}
	}

}

自定义验证器可以结合@InitBinder添加到某个控制器的WebDataBinder中。添加方式是使用WebDataBinder的addValidators()和setValidator()方法来添加和设置验证器该验证器可使用在整个控制器中

@Controller
public class UserWithValidatorController {

	@InitBinder
	protected void initBinder(WebDataBinder binder) {
		binder.addValidators(new UserValidator()); // 添加自定义验证器
	}

	@RequestMapping(value = "/addUserWithValidator")
	// 通过initBinder方法添加了自定义验证器,使用Validated注解会自动调用UserValidator。
	public ModelAndView add(@Validated User user, BindingResult bindingResult) {
		ModelAndView mv = new ModelAndView();
		if (bindingResult.hasErrors()) {
			List<ObjectError> validateErrorList = bindingResult.getAllErrors();
			mv.addObject("validateErrorList", validateErrorList);
		}
		mv.addObject("user", user);
		mv.setViewName("login");
		return mv;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值