JSR303验证
转自:http://blog.csdn.net/lu930124/article/details/52587135
JSR-303是一个数据验证的规范,这里我不会讲这个规范是怎么回事,只会讲一下JSR-303在SpringMVC中的应用。JSR-303只是一个规范,而Spring也没有对这一规范进行实现,那么当我们在SpringMVC中需要使用到JSR-303的时候就需要我们提供一个对JSR-303规范的实现,Hibernate Validator是实现了这一规范的,这里我将以它作为JSR-303的实现来讲解SpringMVC对JSR-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;
- }
- }
我们可以看到我们在username、password和age对应的get方法上都加上了一个注解,这些注解就是JSR-303里面定义的限制,其中@NotBlank是Hibernate 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的支持,把对应的校验错误信息放到Spring的Errors对象中。这时候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原生支持的限制有如下几种:
限制
除了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。另外需要注意的是我们在定义自己的限制类型的注解时有三个属性是必须定义的,如上面代码所示的message、groups和payload属性。
在定义了限制类型Money之后,接下来就是定义我们的限制类型校验类MoneyValidator了。限制类型校验类必须实现接口javax.validation.ConstraintValidator,并实现它的initialize和isValid方法。我们先来看一下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;
- }
- }
JSR303验证的更多相关文章
- SpringBoot-服务端参数验证-JSR-303验证框架
1. springboot 默认集成了 hibernate-validator,它默认是生效的,可以直接使用. 比如: @RestController @RequestMapping("/h ...
- springMVC中使用 JSR-303验证器( Validation 接口 )
在pom.xml,添加validator验证器的依赖 <dependency> <groupId>org.hibernate</groupId> <artif ...
- spring mvc 使用jsr-303进行表单验证的方法介绍
源代码来源:http://howtodoinjava.com/spring/spring-mvc/spring-bean-validation-example-with-jsr-303-annotat ...
- SpringMVC学习系列(6) 之 数据验证
在系列(4).(5)中我们展示了如何绑定数据,绑定完数据之后如何确保我们得到的数据的正确性?这就是我们本篇要说的内容 —> 数据验证. 这里我们采用Hibernate-validator来进行验 ...
- SpringMVC数据验证
SpringMVC数据验证——第七章 注解式控制器的数据验证.类型转换及格式化——跟着开涛学SpringMVC 资源来自:http://jinnianshilongnian.iteye.com/blo ...
- SpringMVC 服务器端验证
1.导入JSR303验证类库Jar包2.在MVC的配置文件中添加<mvc:annotation-driven/>的配置3.在MVC的配置文件中添加验证器的配置4.在接收表单数据的类中添加验 ...
- springMVC 验证器
采用Hibernate-validator来进行验证,Hibernate-validator实现了JSR-303验证框架支持注解风格的验证.首先我们要到http://hibernate.org/val ...
- spring(7)--注解式控制器的数据验证、类型转换及格式化
7.1.简介 在编写可视化界面项目时,我们通常需要对数据进行类型转换.验证及格式化. 一.在Spring3之前,我们使用如下架构进行类型转换.验证及格式化: 流程: ①:类型转换:首先调用Proper ...
- spring mvc 建立下拉框并进行验证demo
原文出处:http://howtodoinjava.com/spring/spring-mvc/spring-mvc-populate-and-validate-dropdown-example/ 该 ...
随机推荐
- VBA 获得绝对地址控制焦点的设置
先上代码,有时间再补上说明. Dim Mefoucs As String MsgBox "你选定的当前单元格是:" & Selection.Address Mefoucs ...
- ar命令学习
之前,学习Linux下使用静态库的时候涉及到了这三个命令: gcc -c my_strcpy.c my_strcmp.car rcs libmylib.a *.ogcc -o main main.c ...
- 16C554在LINUX上的移植(AT91)
16C554在LINUX上的移植(AT91) linux版本:3.14.17 AT91SAMa5d36 EINTA_0 ARM-IO5 PA14 14 EINTA ...
- list中存放map实例
list中存放map实例 2016年08月08日 18:46:14 阅读数:22279 List中存放Map遍历输出的实例 import java.util.ArrayList; import ...
- python手册
https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/
- DP - 字符混编
字符混编 Problem's Link ---------------------------------------------------------------------------- Mea ...
- C++ 构造中调用构造
//构造中调用构造 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; class Point{ ...
- linux改动登陆主机提示信息
寻常管理着130多台Linux物理主机.真正搞清楚每一台主机的IP信息.应用部署比較麻烦! 所以在部署之初,必须规划好: 写一个脚本.把主机IP.管理员联系方法,应用部署等主机信息放在.sh里面 sh ...
- hrbustoj 1306:再遇攻击(计算几何,判断点是否在多边形内,水题)
再遇攻击 Time Limit: 1000 MS Memory Limit: 65536 K Total Submit: 253(37 users) Total Accepted: 56(2 ...
- jQuery 插件开发指南
jQuery凭借其简洁的API,对DOM强大的操控性,易扩展性越来越受到web开发人员的喜爱,经常有人询问一些技巧,因此干脆写这么一篇文章给各位jQuery爱好者,算是抛砖引玉吧. 那么首先我们来简单 ...