`

SpringMVC之验证Validation

阅读更多


SpringMVC验证可以通过实现Validator接口来实现,话不多说,来代码吧。
本文参考自:http://haohaoxuexi.iteye.com/blog/1812584
假设我们需要对一个User的实体类进行验证:

public class User {
 
    private String username;
   
    private String password;
 
    public String getUsername() {
       return username;
    }
 
    public void setUsername(String username) {
       this.username = username;
    }
 
    public String getPassword() {
       return password;
    }
 
    public void setPassword(String password) {
       this.password = password;
    }
   
    public String toString() {
       return username + ", " + password;
    }
   
}

 进行验证的实体类:Supports方法用于判断当前的Validator实现类是否支持校验当前需要校验的实体类,只有当supports方法的返回结果为true的时候,该Validator接口实现类的validate方法才会被调用来对当前需要校验的实体类进行校验。 

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
 
public class UserValidator implements Validator {
 
    public boolean supports(Class<?> clazz) {
       // TODO Auto-generated method stub
       return User.class.equals(clazz);
    }
 
    public void validate(Object obj, Errors errors) {
       // TODO Auto-generated method stub
       ValidationUtils.rejectIfEmpty(errors, "username", null, "Username is empty.");
       User user = (User) obj;
       if (null == user.getPassword() || "".equals(user.getPassword()))
           errors.rejectValue("password", null, "Password is empty.");
    }
 
}

 
       我们已经定义了一个对User类进行校验的UserValidator了,但是这个时候UserValidator还不能对User对象进行校验,因为我们还没有告诉Spring应该使用UserValidator来校验User对象。在SpringMVC中我们可以使用DataBinder来设定当前Controller需要使用的Validator。先来看下面一段代码:

import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.DataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
 
@Controller
public class UserController {
   
    @InitBinder
    public void initBinder(DataBinder binder) {
       binder.setValidator(new UserValidator());
    }
 
    @RequestMapping("login")
    public String login(@Valid User user, BindingResult result) {
       if (result.hasErrors())
           return "redirect:user/login";
       return "redirect:/";
    }
   
}

 
在上面这段代码中我们可以看到我们定义了一个UserController,该Controller有一个处理login操作的处理器方法login,它需要接收客户端发送的一个User对象,我们就是要利用前面的UserValidator对该User对象进行校验。首先我们可以看到我们login方法接收的参数user是用@Valid进行标注的,这里的@Valid是定义在JSR-303标准中的,我这里使用的是Hibernate Validation对它的实现。这里我们必须使用@Valid标注我们需要校验的参数user,否则Spring不会对它进行校验。另外我们的处理器方法必须给定包含Errors的参数,这可以是Errors本身,也可以是它的子类BindingResult,使用了Errors参数就是告诉Spring关于表单对象数据校验的错误将由我们自己来处理,否则Spring会直接抛出异常,而且这个参数是必须紧挨着@Valid参数的,即必须紧挨着需要校验的参数,这就意味着我们有多少个@Valid参数就需要有多少个对应的Errors参数,它们是一一对应的。前面有提到我们可以通过DataBinder来指定需要使用的Validator,我们可以看到在上面代码中我们通过@InitBinder标记的方法initBinder设置了当前Controller需要使用的Validator是UserValidator。这样当我们请求处理器方法login时就会使用DataBinder设定的UserValidator来校验当前的表单对象User,首先会通过UserValidator的supports方法判断其是否支持User对象的校验,若支持则调用UserValidator的validate方法,并把相关的校验信息存放到当前的Errors对象中。接着我们就可以在我们的处理器方法中根据是否有校验异常信息来做不同的操作。在上面代码中我们定义了在有异常信息的时候就跳转到登陆页面。这样我们就可以在登陆页面上通过errors标签来展示这些错误信息了。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.0.xsd
     http://www.springframework.org/schema/mvc
     http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
    
    <mvc:annotation-driven validator="userValidator"/>
   
    <bean id="userValidator" class="com.xxx.xxx.UserValidator"/>
 
    ...
</beans>

 
使用JSR-303 Validation进行验证 

       JSR-303是一个数据验证的规范,这里我不会讲这个规范是怎么回事,只会讲一下JSR-303SpringMVC中的应用。JSR-303只是一个规范,而Spring也没有对这一规范进行实现,那么当我们在SpringMVC中需要使用到JSR-303的时候就需要我们提供一个对JSR-303规范的实现,Hibernate Validator是实现了这一规范的,这里我将以它作为JSR-303的实现来讲解SpringMVCJSR-303的支持。

      JSR-303的校验是基于注解的,它内部已经定义好了一系列的限制注解,我们只需要把这些注解标记在需要验证的实体类的属性上或是其对应的get方法上。来看以下一个需要验证的实体类User的代码:

 
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotBlank;
 
public class User {
 
    private String username;
   
    private String password;
   
    private int age;
 
    @NotBlank(message="用户名不能为空")
    public String getUsername() {
       return username;
    }
 
    public void setUsername(String username) {
       this.username = username;
    }
 
    @NotNull(message="密码不能为null")
    public String getPassword() {
       return password;
    }
 
    public void setPassword(String password) {
       this.password = password;
    }
 
    @Min(value=10, message="年龄的最小值为10")
    public int getAge() {
       return age;
    }
 
    public void setAge(int age) {
       this.age = age;
    }
   
}

 我们可以看到我们在usernamepasswordage对应的get方法上都加上了一个注解,这些注解就是JSR-303里面定义的限制,其中@NotBlankHibernate Validator的扩展。不难发现,使用JSR-303来进行校验比使用Spring提供的Validator接口要简单的多。我们知道注解只是起到一个标记性的作用,它是不会直接影响到代码的运行的,它需要被某些类识别到才能起到限制作用。使用SpringMVC的时候我们只需要把JSR-303的实现者对应的jar包放到classpath中,然后在SpringMVC的配置文件中引入MVC Namespace,并加上<mvn:annotation-driven/>就可以非常方便的使用JSR-303来进行实体对象的验证。加上了<mvn:annotation-driven/>之后Spring会自动检测classpath下的JSR-303提供者并自动启用对JSR-303的支持,把对应的校验错误信息放到SpringErrors对象中。这时候SpringMVC的配置文件如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.0.xsd
     http://www.springframework.org/schema/mvc
     http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
    
    <mvc:annotation-driven/>
</beans>

 

接着我们来定义一个使用User对象作为参数接收者的Controller,其代码如下所示:

import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
 
@Controller
public class UserController {
 
    @RequestMapping("login")
    public String login(@Valid User user, BindingResult result) {
       if (result.hasErrors())
           return "user/login";
       return "redirect:/";
    }
   
}

 
这样当我们不带任何参数请求login.do的时候就不能通过实体对象User的属性数据有效性限制,然后会把对应的错误信息放置在当前的Errors对象中。

JSR-303原生支持的限制有如下几种

限制

说明

@Null

限制只能为null

@NotNull

限制必须不为null

@AssertFalse

限制必须为false

@AssertTrue

限制必须为true

@DecimalMax(value)

限制必须为一个不大于指定值的数字

@DecimalMin(value)

限制必须为一个不小于指定值的数字

@Digits(integer,fraction)

限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction

@Future

限制必须是一个将来的日期

@Max(value)

限制必须为一个不大于指定值的数字

@Min(value)

限制必须为一个不小于指定值的数字

@Past

限制必须是一个过去的日期

@Pattern(value)

限制必须符合指定的正则表达式

@Size(max,min)

限制字符长度必须在minmax之间


除了JSR-303原生支持的限制类型之外我们还可以定义自己的限制类型。定义自己的限制类型首先我们得定义一个该种限制类型的注解,而且该注解需要使用@Constraint标注。现在假设我们需要定义一个表示金额的限制类型,那么我们可以这样定义:

 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
import javax.validation.Constraint;
import javax.validation.Payload;
 
import com.xxx.xxx.constraint.impl.MoneyValidator;
 
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MoneyValidator.class)
public @interface Money {
   
    String message() default"不是金额形式";
   
    Class<?>[] groups() default {};
   
    Class<? extends Payload>[] payload() default {};
 
}

 

我们可以看到在上面代码中我们定义了一个Money注解,而且该注解上标注了@Constraint注解,使用@Constraint注解标注表明我们定义了一个用于限制的注解。@Constraint注解的validatedBy属性用于指定我们定义的当前限制类型需要被哪个ConstraintValidator进行校验。在上面代码中我们指定了Money限制类型的校验类是MoneyValidator另外需要注意的是我们在定义自己的限制类型的注解时有三个属性是必须定义的,如上面代码所示的messagegroupspayload属性。

       在定义了限制类型Money之后,接下来就是定义我们的限制类型校验类MoneyValidator了。限制类型校验类必须实现接口javax.validation.ConstraintValidator,并实现它的initializeisValid方法。我们先来看一下MoneyValidator的代码示例:

 
import java.util.regex.Pattern;
 
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
 
import com.xxx.xxx.constraint.Money;
 
public class MoneyValidator implements ConstraintValidator<Money, Double> {
 
    private String moneyReg = "^\\d+(\\.\\d{1,2})?$";//表示金额的正则表达式
    private Pattern moneyPattern = Pattern.compile(moneyReg);
   
    public void initialize(Money money) {
       // TODO Auto-generated method stub
      
    }
 
    public boolean isValid(Double value, ConstraintValidatorContext arg1) {
       // TODO Auto-generated method stub
       if (value == null)
           return true;
       return moneyPattern.matcher(value.toString()).matches();
    }
 
}

 
从上面代码中我们可以看到ConstraintValidator是使用了泛型的。它一共需要指定两种类型,第一个类型是对应的initialize方法的参数类型,第二个类型是对应的isValid方法的第一个参数类型。从上面的两个方法我们可以看出isValid方法是用于进行校验的,有时候我们在校验的过程中是需要取当前的限制类型的属性来进行校验的,比如我们在对@Min限制类型进行校验的时候我们是需要通过其value属性获取到当前校验类型定义的最小值的,我们可以看到isValid方法无法获取到当前的限制类型Money。这个时候initialize方法的作用就出来了。我们知道initialize方法是可以获取到当前的限制类型的,所以当我们在校验某种限制类型时需要获取当前限制类型的某种属性的时候,我们可以给当前的ConstraintValidator定义对应的属性,然后在initialize方法中给该属性赋值,接下来我们就可以在isValid方法中使用其对应的属性了。针对于这种情况我们来看一个代码示例,现在假设我要定义自己的@Min限制类型和对应的MinValidator校验器,那么我可以如下定义:
Min限制类型

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MinValidator.class)
public @interface Min {
 
    int value() default 0;
   
    String message();
   
    Class<?>[] groups() default {};
   
    Class<? extends Payload>[] payload() default {};
}

 
MinValidator校验器

public class MinValidator implements ConstraintValidator<Min, Integer> {
 
    private int minValue;
   
    public void initialize(Min min) {
       // TODO Auto-generated method stub
       //把Min限制类型的属性value赋值给当前ConstraintValidator的成员变量minValue
       minValue = min.value();
    }
 
    public boolean isValid(Integer value, ConstraintValidatorContext arg1) {
       // TODO Auto-generated method stub
       //在这里我们就可以通过当前ConstraintValidator的成员变量minValue访问到当前限制类型Min的value属性了
       return value >= minValue;
    }
 
}

 
继续来说一下ConstraintValidator泛型的第二个类型,我们已经知道它的第二个类型是对应的isValid的方法的第一个参数,从我给的参数名称value来看也可以知道isValid方法的第一个参数正是对应的当前需要校验的数据的值,而它的类型也正是对应的我们需要校验的数据的数据类型。这两者的数据类型必须保持一致,否则Spring会提示找不到对应数据类型的ConstraintValidator。建立了自己的限制类型及其对应的ConstraintValidator后,其用法跟标准的JSR-303限制类型是一样的。以下就是使用了上述自己定义的JSR-303限制类型——Money限制和Min限制的一个实体类:

public class User {
   
    private int age;
   
    private Double salary;
 
    @Min(value=8, message="年龄不能小于8岁")
    public int getAge() {
       return age;
    }
 
    public void setAge(int age) {
       this.age = age;
    }
 
    @Money(message="标准的金额形式为xxx.xx")
    public Double getSalary() {
       return salary;
    }
 
    public void setSalary(Double salary) {
       this.salary = salary;
    }
   
}

 
另外再讲一点Spring对自定义JSR-303限制类型支持的新特性,那就是Spring支持往ConstraintValidator里面注入bean对象。现在假设我们在MoneyValidator里面需要用到Spring ApplicationContext容器中的一个UserController bean对象,那么我们可以给ConstraintValidator定义一个UserController属性,并给定其set方法,在set方法上加注解@Resource@Autowired通过set方式来注入当前的ApplicationContext中拥有的UserController bean对象。关于@Resource@AutoWired的区别可以参考这篇博客。所以我们可以这样来定义我们的MoneyValidator

 
public class MoneyValidator implements ConstraintValidator<Money, Double> {
 
    private String moneyReg = "^\\d+(\\.\\d{1,2})?$";//表示金额的正则表达式
    private Pattern moneyPattern = Pattern.compile(moneyReg);
    private UserController controller;
   
    public void initialize(Money money) {
       // TODO Auto-generated method stub
      
    }
 
    public boolean isValid(Double value, ConstraintValidatorContext arg1) {
       // TODO Auto-generated method stub
       System.out.println("UserController: .............." + controller);
       if (value == null)
           returntrue;
       return moneyPattern.matcher(value.toString()).matches();
    }
 
    public UserController getController() {
       return controller;
    }
 
    @Resource
    public void setController(UserController controller) {
       this.controller = controller;
    }
 
}

 

分享到:
评论

相关推荐

    springmvc校验器validation的所有配套jar包

    这里提到的"springmvc校验器validation的所有配套jar包"是指用于实现Spring MVC中数据验证功能所需的一系列库文件。具体来说,这些jar包通常包括Hibernate Validation、Spring的验证支持以及可能的其他依赖。 ...

    springmvc数据验证jar包

    这个"springmvc数据验证jar包"正是为了实现这一功能而必备的组件。它包含了多个关键库,如Hibernate Validator、JBoss Logging和Validation API,这些库协同工作以确保输入数据的有效性,从而增强应用程序的安全性和...

    SpringMVC使用Validation验证表单

    Validation是Java世界中用于对象验证的标准API,通常与Hibernate Validator实现一起使用。本教程将深入探讨如何在Spring MVC项目中使用Validation进行表单验证。 首先,我们需要引入必要的依赖。在Spring MVC项目中...

    详解SpringMVC验证框架Validation特殊用法

    在SpringMVC中,Validation框架用于实现数据验证,它基于Java Bean Validation规范,能够帮助开发者确保输入的数据满足预设的规则。这篇文章将重点讲解Validation的两种特殊用法:分组验证和组序列验证。 1. 分组...

    SpringMVC入门很简单之数据验证

    在这个"SpringMVC入门很简单之数据验证"的主题中,我们将深入探讨如何在SpringMVC中实现数据验证。 在Web应用中,数据验证是必不可少的一环,它确保了用户提交的数据符合预设的规则和格式,防止非法或无效的数据...

    springmvc4与hibernate validation校验器完全兼容jar包

    而Hibernate Validation则是Java世界中用于数据验证的主流库,它基于JSR 303和JSR 349标准,提供了丰富的验证规则和易于使用的API。在Spring MVC中集成Hibernate Validation,可以实现对输入数据的有效性检查,从而...

    springmvc数据验证

    Spring MVC 提供了两种主要的数据验证方式:一种是基于JSR 303/349的Bean Validation,另一种是基于Validator接口的自定义验证。 1. **Bean Validation**:这是一个标准的Java Bean数据验证框架,它定义了一组注解...

    springmvc 使用validation使用的jar包!

    `validation-api-1.1.0.Final.jar`是Bean Validation的API定义,包含了验证注解和验证接口。这个库定义了验证的核心API,包括`Validator`接口和各种验证注解,如`@NotNull`, `@Min`, `@Max`等。这个API是独立于任何...

    springmvc注解式控制器的数据验证、类型转换及格式化 SpringMVC数据验证

    Spring MVC通过集成JSR 303/349(Java Bean Validation)规范,使得我们可以在模型属性上定义验证规则,如`@NotNull`、`@Size`、`@Pattern`等。当控制器接收到请求后,Spring会自动进行数据验证,并在验证失败时抛出...

    SpringMVC数据验证——注册用户格式的验证实例

    首先,我们需要理解Spring MVC的数据验证是基于JavaBeans规范中的Java Bean Validation(JSR 303/349)标准和Hibernate Validation实现的。这允许我们在模型类(通常是用户实体类)中添加注解,来定义验证规则。 ...

    《使用Validator做SpringMVC的验证框架》教程源码(完整版)

    《使用Validator做SpringMVC的验证框架》教程源码 教程地址: http://blog.csdn.net/devefx/article/details/51565139 http://blog.csdn.net/devefx/article/details/51567533 ...

    SpringMVC之DataBinding和Validation--Validator,PropertyEditor,Converter,Formatter

    在Java世界中,Bean Validation(JSR 303/349)提供了一种标准的方式来验证对象的属性。Spring MVC通过集成Hibernate Validator(Bean Validation的实现),使得我们可以方便地对请求数据进行验证。我们可以在模型类...

    SpringMVC实现Validation校验过程详解

    SpringMVC 提供了一个强大的 Validation 机制来实现数据验证本文将详细介绍 SpringMVC 实现 Validation 校验过程详解。 一、概述 在 Web 应用程序中,数据验证可以分为前端验证和后端验证。前端验证通常使用 ...

    Springboot SpringMVC thymeleaf页面提交Validation实现实例.pdf

    在Spring Boot应用中,结合Spring MVC和Thymeleaf,我们可以实现前端页面的数据验证功能,这就是所谓的Validation。这个实例展示了如何在用户提交表单时,通过后台验证确保数据的完整性和准确性。 首先,实例中使用...

    SpringMVC+jsp之表单验证登录

    在这个"SpringMVC+jsp之表单验证登录"的主题中,我们将探讨如何利用SpringMVC和JSP来实现用户登录功能,包括表单验证和交互流程。 首先,我们需要理解SpringMVC的核心组件。DispatcherServlet是入口点,负责接收...

    springmvc表单验证JSR-303验证框架jar包

    hibernate-validator-5.2.4.Final.jar hibernate-validator-annotation-processor...validation-api-1.1.0.Final.jar jboss-logging-3.2.1.Final.jar classmate-1.1.0.jar slf4j-api-1.6.1.jar slf4j-log4j12-1.6.1.jar

    SpringMVC PPT_springmvc_

    SpringMVC 提供了自动的数据绑定功能,可以从请求参数自动填充到 Java 对象,同时也支持基于 Bean Validation 的数据验证。 十、上传下载支持 SpringMVC 提供了对文件上传和下载的支持,可以方便地处理用户的文件...

    springMVC整合hibernate的校验Validation

    这主要是通过使用Hibernate Validator来实现数据的验证,它是一个遵循JSR 303(Java Bean Validation)和JSR 349(Java Bean Validation 1.1)标准的实现。本教程将详细介绍如何在Spring MVC中配置并使用Hibernate ...

    springmvc注解验证

    Bean Validation API定义了一套标准的验证注解,如`@NotNull`, `@Size`, `@Min`, `@Max`, `@Pattern`等,用于校验对象的属性。这些注解可以直接应用于Java Bean的字段上,也可以在Spring MVC的控制器方法参数上使用...

Global site tag (gtag.js) - Google Analytics