在做web开发的时候,经常需要对客户端发送过来的数据进行一个验证,以防数据不合法。
而SpringMVC支持的数据校验是JSR303的标准,通过在bean的属性上打上annotation @NotNull @Max等注解进行验证。JSR303提供有很多annotation借口,而SpringMVC对于这些验证是使用hibernate的实现,所以我们需要添加hibernate的一个validator包:
在SpringMVC中引入
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.18.Final</version>
</dependency>
在Springboot中引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
hibernate除了JSR303的标准之外还额外提供了其他的验证注解。下表是JSR303支持的验证注解:
约束注解名称 | 约束注解说明 |
---|---|
@Null | 验证对象是否为空 |
@NotNull | 验证对象是否为非空 |
@AssertTrue | 验证Boolean对象是否为true |
@AssertFalse | 验证Boolean对象是否为false |
@Min | 验证Number和String对象是否大等于指定的值 |
@Max | 验证Number和String对象是否小等于指定的值 |
@DecimalMin | 验证Number和String对象是否大等于指定的值,小数存在精度 |
@DecimalMax | 验证Number和String对象是否小等于指定的值,小数存在精度 |
@Size | 验真对象(Array, Collection, Map, String)长度是否在给定范围之内 |
@Digits | 验证Number和String的构成是否合法 |
@Past | 验证Date和Calendar对象是否在当前时间之前 |
@Future | 验证Date和Calendar对象是否在当前时间之后 |
@Pattern | 验证String对象是否符合正则表达式的规则 |
Hibernate Validator 附加的注解:
注解 | 详细信息 |
---|---|
必须是电子邮箱地址 | |
@Length | 被注释的字符串的大小必须在指定范围之内 |
@NotEmpty | 被注释的字符串必须是非空 |
@Range | 被注释的元素必须在指定范围之内 |
下面我们来写个小demo,具体演示一下如何使用。例如,我要验证一些字段不能为空,那么就可以使用@NotNull
这个注解,如下示例:
package org.zero01.test;
import javax.validation.constraints.NotNull;
public class UserRegister {
@NotNull(message = "用户名不能为空")
private String userName;
@NotNull(message = "密码不能为空")
private String password;
@NotNull(message = "联系地址不能为空")
private String address;
@NotNull(message = "电话号码不能为空")
private String phone;
...getter and setter...
在控制器的方法参数中,需要通过声明BindingResult参数来获得验证出错的信息,然后使用@Valid
注解来配置哪个pojo对象需要校验,控制器代码如下:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.validation.Valid;
@Controller
public class Test {
@RequestMapping(value = "/test.do", method = RequestMethod.GET)
// 注意,@Valid和BindingResult是配对出现,并且形参顺序是固定的(一前一后),不然就会返回400状态码
public String test(@Valid UserRegister userRegister, BindingResult bindingResult, Model model) {
// 判断是否有异常
if (bindingResult.hasErrors()) {
System.out.println("客户端的请求数据异常,所有的异常如下:");
// 取出所有的异常对象
for (FieldError fieldError : bindingResult.getFieldErrors()) {
// 打印异常的字段以及异常信息
System.out.println(fieldError.getField() + " : " + fieldError.getDefaultMessage());
}
return "register";
}
return "index";
}
}
使用Postman进行访问,什么参数都不写
控制台输出结果如下:
客户端的请求数据异常,所有的异常如下:
address : 联系地址不能为空
userName : 用户名不能为空
password : 密码不能为空
phone : 电话号码不能为空
下面再来演示一下其他常用的注解:
package org.zero01.test;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
public class UserRegister {
@NotNull(message = "用户名不能为空")
private String userName;
@NotNull(message = "密码不能为空")
@Length(max = 12, min = 6, message = "密码长度需在6-12位之间")
private String password;
@NotNull(message = "联系地址不能为空")
private String address;
@NotNull(message = "电话号码不能为空")
// 指定正则表达式验证格式
@Pattern(regexp = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\\\d{8}$", message = "电话号码格式错误")
private String phone;
@Email(message = "邮箱格式错误")
private String email;
@Size(max = 10, min = 1, message = "成绩单列表长度需在1-10之间")
public List resultList;
...getter and setter...
控制器代码和之前一致,略。
使用Postman进行访问
控制台输出结果如下:
客户端的请求数据异常,所有的异常如下:
address : 联系地址不能为空
userName : 用户名不能为空
password : 密码长度需在6-12位之间
phone : 电话号码格式错误
email : 邮箱格式错误
resultList : 成绩单列表长度需在1-10之间
以上我们都是对所有的字段进行验证,如果我希望有些字段不被验证或者分开验证该怎么办呢?这时候我们就需要到分组验证了,首先编写一个接口:
package org.zero01.test;
public interface Group {
}
然后在需要分组的字段上的注解中加上groups属性,该属性的值为以上我们所定义的接口类,如下示例:
package org.zero01.test;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
public class UserRegister {
// groups 属性用于指定分组,值为一个接口类
@NotNull(message = "用户名不能为空", groups = Group.class)
private String userName;
@NotNull(message = "密码不能为空", groups = Group.class)
@Length(max = 12, min = 6, message = "密码长度需在6-12位之间", groups = Group.class)
private String password;
@NotNull(message = "联系地址不能为空")
private String address;
@NotNull(message = "电话号码不能为空")
@Pattern(regexp = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\\\d{8}$", message = "电话号码格式错误")
private String phone;
@Email(message = "邮箱格式错误")
private String email;
...getter and setter...
控制器代码如下:
package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.validation.Valid;
@Controller
public class Test {
@RequestMapping(value = "/test.do", method = RequestMethod.GET)
// 分组的情况下需要使用Validated注解来指定接口
public String test(@Validated(Group.class) UserRegister userRegister, BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
System.out.println("客户端的请求数据异常,所有的异常如下:");
for (FieldError fieldError : bindingResult.getFieldErrors()) {
System.out.println(fieldError.getField() + " : " + fieldError.getDefaultMessage());
}
return "register";
}
return "index";
}
}
访问方式和之前一致,略。
控制台输出结果如下:
客户端的请求数据异常,所有的异常如下:
password : 密码长度需在6-12位之间
userName : 用户名不能为空
如上,从控制台的打印结果中,可以看到只有password以及userName两个字段受到了验证,这是因为我们只在这两个字段上的注解中指定了groups 属性。所以分组验证就是只验证指定组的字段,而这个组的划分是以接口来划分的。
站在巨人的肩膀上摘苹果:
https://blog.51cto.com/zero01/2090999
原文地址:https://www.cnblogs.com/eternityz/p/12442673.html