在 Web 应用程序中,为了防止客户端传来的数据引发程序异常,常常需要对数据进行验证。
数据验证分为:
-
客户端验证
- 客户端验证主要通过 JavaScript 脚本进行。
-
服务端验证
- 服务端验证主要通过 Java 代码进行验证。
在Spring Boot 3中,参数校验是通过Bean Validation API实现的,这个API是JSR 380规范的一部分。Spring Boot集成了Hibernate Validator作为默认的校验器。
1、spring常用校验注解
a、JSR 303 的注解
注解 | 说明 |
---|---|
@Null | 被注解的元素必须为 null |
@NotNull | 被注解的元素必须不为 null |
@AssertTrue | 被注解的元素必须为 true |
@AssertFalse | 被注解的元素必须为 false |
@Min | 被注解的元素必须是一个数字,其值必须小于指定值。 |
@Max | 被注解的元素必须是一个数字,其值必须大于指定值。 |
@DecimalMin | 被注解的元素必须是一个数字,其值必须小于指定值。 |
@DecimalMax | 被注解的元素必须是一个数字,其值必须大于指定值。 |
@Size(min, max) | 被注解的数组和集合型元素的长度是必须给定的范围之内 |
@Digits(integer, fraction) | 要求字符串必须是数字型字符串,且整数部分有 interger 位,小数部分有 fraction 位。 |
@Past | 要求必须是一个过去日期。用于 Date 和 Calendar |
@Future | 要求必须是一个未来日期。用于 Date 和 Calendar |
@Pattern(regexp, flag) | 要求字符串内容必须符合正则表达式的规则 |
@Valid | 要求递归检查数组和容器中关联对象。 |
所有的这些注解都有 message 属性,用于设置错误提示信息(如果没有设置,则会有默认的错误提示信息)。
b、Hibernate Validator注解
Hibernate Validator 实现了 JSR 303,它除了支持所有标准的校验注解外,还支持一些『额外』的注解:
注解 | 说明 |
---|---|
@NotBlank | 要求字符串必须不为 NULL,且执行 trim() 后必须为非空字符串 |
@Null | 要求字符串必须为 NULL |
@AssertTrue | 注释的元素必须为 true |
@AssertFalse | 注释的元素必须为 false |
@Min(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@Max(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@DecimalMin(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@DecimalMax(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@Size(max, min) | 被注释的元素的大小必须在指定的范围内 |
@Digits (integer, fraction) | 被注释的元素必须是一个数字,其值必须在可接受的范围内 |
@Past | 被注释的元素必须是一个过去的日期 |
@Future | 被注释的元素必须是一个将来的日期 |
@Pattern(value) | 被注释的元素必须符合指定的正则表达式 |
要求字符串内容必须符合邮箱格式。但是 null 会放过 | |
@Length(min, max) | 要求字符串的长度必须在指定范围内 |
@NotEmpty | 备注解的字符串必须为非空 |
@Range(min, max) | 检查数字是否介于 min 和 max 之间 |
c、spring校验注解
注解 | 说明 |
---|---|
@NotNull | 注解的参数不能为 null |
@Size | 被注解的参数的大小必须在指定的范围内(包括最小值和最大值) |
@Min | 被注解的参数的最小值,适用于整数 |
@Max | 被注解的参数的最大值,适用于整数 |
@DecimalMin | 注解的参数的最小值,适用于浮点数、BigDecimal 或 BigInteger 类型的参数。 |
@DecimalMax | 注解的参数的最大值,适用于浮点数、BigDecimal 或 BigInteger 类型的参数。 |
@Digits | 被注解的参数必须是一个数字,并且整数位和小数位的位数不能超过指定的值(默认整数位 2 位,小数位 0 位)。 |
被注解的参数必须是一个合法的电子邮件地址。 | |
@Pattern | 注解的参数必须符合指定的正则表达式模式 @Pattern(regexp =“^lld{4}-\ld{1,2}-\df1,2}$”) |
2、入门案例
a、添加依赖
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>3.0.2</spring-boot.version>
</properties>
<dependencies>
<!--数据校验依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
b、创建vo实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserVo implements Serializable {
private String username;
private String sex;
private Integer age;
private String address;
@Override
public String toString() {
return "UserVo{" +
", username='" + username + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}'+"\n";
}
}
c、创建controller
@RestController
public class UserController {
/**
* 完成用户添加
*/
@PostMapping("user/add")
public String saveUser(@RequestBody UserVo userVo){
return "ok";
}
}
d、使用Spring校验注解对数据校验
-
在实体类中添加校验规则
@Data @NoArgsConstructor @AllArgsConstructor public class UserVo implements Serializable { @NotEmpty(message = "姓名不能为空") //用户名非空校验 @Length(min = 4,max = 6,message = "姓名必须在4-6个字符之间") //用户名长度必须在4-6位之间 private String username; @NotBlank(message = "性别不能为空") //性别非空校验 private String sex; @NotNull(message = "年龄不能为空") //年龄非空校验 @Range(min = 0,max = 100,message = "年龄必须在0-100岁之间") //年龄必须在0-100之间 private Integer age; @NotBlank(message = "请输入家庭住址") //地址非空校验 private String address; }
-
创建自定义异常类
/** * Validator自定义异常类 */ public class ValidatorException extends Exception{ //保存异常信息 private BindingResult result; public BindingResult getResult() { return result; } public ValidatorException(BindingResult result) { this.result = result; } }
-
在全局异常类中添加表单验证异常
/** * 全局异常处理类,检测controller中是否发生了异常,根据异常的类型输出不同的提示 */ @ControllerAdvice //将当前类,配置为controller的代码增强类 public class GlobalException { @ExceptionHandler(NumberFormatException.class) @ResponseBody public ResponseResult<Void> getNumberFormatException(NumberFormatException e){ return new ResponseResult<>(4003,"转换数值类型出错!"+e.getMessage()); } /** * 400 - Bad Request */ @ExceptionHandler(HttpMessageNotReadableException.class) @ResponseBody public ResponseResult<Void> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) { return new ResponseResult<>(400,"参数解析失败"+e.getMessage()); } /** * 405 - Method Not Allowed */ @ExceptionHandler(HttpRequestMethodNotSupportedException.class) @ResponseBody public ResponseResult<Void> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) { return new ResponseResult<>(405,"不支持当前请求的方法"+e.getMessage()); } /** * 415 - Unsupported Media Type */ @ExceptionHandler(HttpMediaTypeNotSupportedException.class) @ResponseBody public ResponseResult<Void> handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) { return new ResponseResult<>(415,"不支持当前媒体类型"+e.getMessage()); } /** * 500 - Internal Server Error */ @ExceptionHandler(HttpServerErrorException.class) @ResponseBody public ResponseResult<Void> handleServerErrorException(HttpServerErrorException e) { return new ResponseResult<>(500,"服务器异常"+e.getMessage()); } /** * 表单验证异常 */ @ExceptionHandler(ValidatorException.class) @ResponseBody public ResponseResult<Object> handleValidatorException(ValidatorException e) { //取出BindingResult中的异常信息并保存到错误对象中返回给页面 Map<String,String> beanError=new HashMap<String,String>(); List<FieldError> list = e.getResult().getFieldErrors(); for (FieldError error : list) { beanError.put(error.getField(),error.getDefaultMessage()); } //将错误对象发送到页面 return new ResponseResult<>(416,"表单不符合验证规则",beanError); } }
-
在Controller中开启验证
提示:使用验证框架时,controller中法的参数对象必须用
@Valid
注解修饰,并且处理方法要多出一个BindingResult
参数对象。@RestController public class UserController { /** * 完成用户添加 * 提示:BindingResult对象只能放在形参的最后一位 */ @PostMapping("user/add") public UserVo saveUser(@Validated @RequestBody UserVo userVo,BindingResult result) throws ValidatorException { // 如果User对象校验失败,将抛出MethodArgumentNotValidException异常 if(result.hasErrors()){ //表单不符合验证规则时抛出自定义异常 throw new ValidatorException(result); } return userVo; } }