一般情况下,用户的输入是随意的,为了保证数据的合法性,数据验证是所有 Web 应用必须处理的问题。
Spring MVC 有以下两种方法可以验证输入:
-
1.利用 Spring 自带的验证框架(复杂,推荐spring-boot-starter-validation)
- 2.利用 JSR 303 实现
数据验证分为客户端验证和服务器端验证,
客户端验证主要是过滤正常用户的误操作,通过 JavaScript 代码完成。
服务器端验证是整个应用阻止非法数据的最后防线,通过在应用中编程实现。
本节使用 JSR 303 实现服务器端的数据验证
JSRJSR
是Java Specification Requests的缩写,意思是Java 规范提案,
是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。
任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。关于 JSR-303JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现,Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint
JSR 303 是 Java 为 Bean 数据合法性校验所提供的标准框架。JSR 303 通过在 Bean 属性上标注类似于 @NotNull、@Max 等标准的注解指定校验规则,并通过标准的验证接口对 Bean 进行验证。可以通过 The Java Community Process(SM) Program - JSRs: Java Specification Requests - detail JSR# 303 查看详细内容并下载 JSR 303 Bean Validation。
JSR 303 不需要编写验证器,它定义了一套可标注在成员变量、属性方法上的校验注解,如下表所示。只针对对象属性的校验
注解 | 含义 |
---|---|
@Null | 被注释的元素必须为 null |
@NotNull | 被注释的元素必须不为 null |
@AssertTrue | 被注释的元素必须为 true |
@AssertFalse | 被注释的元素必须为false |
@Min(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@Max(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@DecimalMin(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@DecimalMax(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@Size(max=, min=) | 被注释的元素的字符串长度大小必须在指定的范围内 |
@Digits (integer,fraction) | 被注释的元素必须是一个数字,其值必须在可接受的范围内 |
@Past | 被注释的元素必须是一个过去的日期 |
@Future | 被注释的元素必须是一个将来的日期 |
@Pattern(regex=,flag=) | 被注释的元素必须符合指定的正则表达式 Hibernate Validator附加的constraint |
@NotBlank(message =) | 验证字符串非null,且长度必须大于0 |
被注释的元素必须是电子邮箱地址 | |
@Length(min=,max=) | 被注释的字符串的大小必须在指定的范围内 |
@NotEmpty | 被注释的字符串的必须非空 |
@Range(min=,max=,message=) | 被注释的元素必须在合适的数字范围内 |
Spring MVC 支持 JSR 303 标准的校验框架,Spring 的 DataBinder 在进行数据绑定时,可同时调用校验框架来完成数据校验工作,(当发生错误时候触发BindException)非常简单方便。在 Spring MVC 中,可以直接通过注解驱动的方式来进行数据校验。
Spring 本身没有提供 JSR 303 的实现,Hibernate Validator 实现了 JSR 303,所以必须在项目中加入来自 Hibernate Validator 库的 jar 文件,下载地址为 The Bean Validation reference implementation. - Hibernate Validator
maven依赖
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.2.3.Final</version>
</dependency>
效验:在product类中对实体进行效验
private Integer id;
@NotEmpty(message = "name不能为空")
private String name;
private BigDecimal price;
//第一种方式:
//@Min(value=5,message="数量最小为5")
//@MAx(value=100,message="数量最大为100")
//第二种方式
@Range(min = 5,max = 10,message = "大小必须在这个范围内")
private Integer qty;
private List<String> address;
private String email;
private String idCard;
在TeacherController中编辑controller:
@RestController
@RequestMapping("/api/teacher")
public class TeacherController {
// 做数据效验 必须加上这个 @Valid注解 不然不显示结果
@PostMapping
public Integer insert(@RequestBody @Valid Product product){
return 1;
}
}
运行测试:
把拦截器给注释掉:运行测试一下:
如果想在控制台显示异常信息,可以debug一下看看是什么异常
异常配置:第一种方式:统一的处理
@ExceptionHandler(BindException.class)
public String processException(BindException e){
BindingResult result = e.getBindingResult();
StringBuilder sb=new StringBuilder();
List<ObjectError> allError=result.getAllErrors();
for (ObjectError error : allError) {
sb.append(error.getDefaultMessage());
}
return sb.toString();
}
测试运行:
第二种方式:使用自己的异常处理类 让异常信息返回json类型:
@ExceptionHandler(Exception.class)
public Object error( Exception e){
int code=666;
if(e instanceof BizException){
BizException biz= (BizException) e;
code=biz.getCode();
}
// 使用自己的异常处理
if(e instanceof MethodArgumentNotValidException){
StringBuilder sb = new StringBuilder();
List<ObjectError> allErrors = ( (MethodArgumentNotValidException) e).getBindingResult().getAllErrors();
for(ObjectError error : allErrors){
sb.append(error.getDefaultMessage());
}
return ResponseDTO.error(888,sb.toString());
}
return ResponseDTO.error(code,e.getMessage());
}
测试访问:
正则表达式在线工具:正则表达式在线测试 | 菜鸟工具
max,min的用法
@Min(value = 5,message = "数量最小为5")
@Max(value = 100,message = "数量最大为100")
private Integer qty;
测试:
邮箱验证: 必须结合非空约束
@Email
@NotEmpty
private String email;
测试
身份证:正则表达式验证
@Pattern(regexp = "(^\\d{15}$)|(^\\d{18}$)|(^\\d{17}(\\d|X|x)$)", message = "身份号不合法请输入18位数字")
private String idCard;