目录
参数校验(校验失败不会进入controller,可以直接返回)
简单介绍
数据校验很重要,在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些 HTTP 工具直接向后端请求一些违法数据。
本文在vue+springboot的基础上校验请求数据
准备工作
springboot2.3 版本之前无需导入此jar包, spring-boot-starter-web中自带了
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
常用注解说明
注意:下列注解可同时使用多个
注解 | 校验功能 |
@Null | 必须为null |
@NotNull | 不能为null,可以是空 |
@NotBlank | 只能作用在String上,字符串不能为null,字符串trim()后也不能等于“” |
@NotEmpty | 不能为null,集合、数组、map等size()不能为0;字符串trim()后可以等于“” |
@Length(min = 6, max = 16) | 指定传入的字符串长度 |
@Size(max, min) | 检测容器元素个数 |
@Pattern | 必须满足指定的正则表达式 |
@Max | 最大值 |
@Min | 最小值 |
@DecimalMax | 设置不能超过最大值 |
@DecimalMin | 设置不能超过最小值 |
@Range | 设置最大和最小值 |
@Negative | 负数不包括0 |
@NegativeOrZero | 负数或0 |
@PositiveOrZero | 正数或0 |
@Digits(integer, fraction) | 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction |
@AssertFalse | 限制必须为false |
@AssertTrue | 限制必须为true |
@Past | 被注释的元素必须是一个过去的日期 |
@PastOrPresent | 被注释的元素必须是一个过去或当前的日期 |
@Future | 被注释的元素必须是一个将来的日期 |
@FutureOrPresent | 被注释的元素必须是一个将来或当前的日期 |
被注释的元素必须是电子邮件地址 |
参数校验(校验失败不会进入controller,可以直接返回)
普通实体类
- 在实体类字段上添加注解校验
- 在@RequestBody后添加@Validated注解
- 编写异常控制器统一收集异常
实体类
import lombok.Data;
import lombok.ToString;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.*;
import java.util.List;
@Data
@ToString
public class Student {
//姓名不可为空
@NotBlank(message = "姓名不可为空")
private String name;
//年龄不可为空且必须在0-200之间
@NotNull(message = "年龄不可为空")
@Max(value = 200,message = "年龄不可大于200")
@Min(value = 0,message = "年龄不可小于0")
private Integer age;
//时间传入格式为yyyyMMddHHmmss
@Pattern(regexp = "^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})(((0[13578]|1[02])(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)(0[1-9]|[12][0-9]|30))|(02(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))0229))([0-1]?[0-9]|2[0-3])([0-5][0-9])([0-5][0-9])$",message = "时间格式有误")
@Length(min = 14, max = 14,message = "时间格式有误")
@NotBlank(message = "时间不可为空")
private String time;
//邮箱不可为空且格式正确
@NotBlank(message = "邮箱不可为空")
@Email(message = "邮箱格式有误")
private String email;
//爱好不可为空
@Size(min = 1,message = "爱好不可为空")
@NotNull(message = "爱好不可为空")
private List<String> likeList;
}
controller
@RestController
@RequestMapping("student")
public class StudentController {
@PostMapping("add")
public Result add(@RequestBody @Validated Student student){
System.out.println("student = " + student);
return new Result("0000","添加成功");
}
}
统一异常处理
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import java.util.*;
@RestControllerAdvice
public class GlobalControllerAdvice {
/**
* 校验@RequestBody异常处理
* @param e
* @return
*/
@ExceptionHandler(BindException.class)
public Result bindExceptionHandler(BindException e) {
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
Map map = new HashMap();
for(FieldError fieldError:fieldErrors){
//字段名
String field = fieldError.getField();
//字段传值错误信息
String message = fieldError.getDefaultMessage();
map.put(field,message);
}
return new Result("400","输入参数有误", map);
}
/**
* 校验@PathVariable异常处理
* @param e
* @return
*/
@ExceptionHandler(ConstraintViolationException.class)
public Result handleConstraintViolationException(ConstraintViolationException e) {
Map map = new HashMap();
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
Iterator<ConstraintViolation<?>> iterator = violations.iterator();
while(iterator.hasNext()){
ConstraintViolation<?> violation = iterator.next();
//resultful路径
Path path = violation.getPropertyPath();
//字段传值错误信息
String message = violation.getMessage();
String p = "resultful-"+path;
map.put(p,message);
}
return new Result("400","输入参数有误", map);
}
}
测试结果
实体类嵌套
假设一个学生有多本书,要求前台同时传入学生与图书信息
- 在引用实体类变量上添加@Valid注解即可
图书实体类
import lombok.Data;
import lombok.ToString;
import javax.validation.constraints.DecimalMax;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@Data
@ToString
public class Book {
@NotBlank(message = "图书名称不可为空")
private String name;
@DecimalMin(value = "0.00",message = "图书价格不小于0")
@DecimalMax(value = "300.00",message = "图书价格不大于300")
@NotNull
private BigDecimal price;
}
学生实体类
测试结果
resultful风格校验
- 直接在@PathVariable添加规则校验
- 在controller层添加@Validated注解
测试结果
总结
使用流程
- 导入jar包
- 在实体类上添加规则校验注解
- 在controller参数上添加@Validated注解
- 编写统一校验异常处理
注意事项
- 上面提供的统一异常处理类已经同时处理了@RequestBody和@PathVariable参数的处理
- 处理@RequestBody参数校验在@RequestBody后添加@Validated注解
- 处理@PathVariable参数校验在controller添加@Validated注解
Result实体类
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class Result {
private String code;
private String message;
private Object data;
public Result(String code, String message, Object data) {
this.code = code;
this.message = message;
this.data = data;
}
public Result(String code, String message) {
this.code = code;
this.message = message;
}
public Result() {
}
}