共计 3085 个字符,预计需要花费 8 分钟才能阅读完成。
前言
估计很多朋友都认为参数校验是客户端的职责,不关服务端的事。其实这是错误的,学过 Web 安全的都知道,客户端的验证只是第一道关卡。它的参数验证并不是安全的,一旦被有心人抓到可乘之机,他就可以有各种方法来摸拟系统的 Http 请求,访问数据库的关键数据。轻则导致服务器宕机,重则泄露数据。所以,这时就需要设置第二道关卡,服务端验证了。
老项目的服务端校验
@RestController
@RequestMapping(“/student”)
public class ValidateOneController {
@GetMapping(“/id”)
public Student findStudentById(Integer id){
if(id == null){
logger.error(“id 不能为空!”);
throw new NullPointerException(“id 不能为空 ”);
}
return studentService.findStudentById(id);
}
}
看以上代码,就一个的校验就如此麻烦。那我们是否有好的统一校验方法呢?鉴于 SpringBoot 无所不能。答案当然是有的。
其中,Bean Validator 和 Hibernate Validator 就是两套用于验证的框架,二者都遵循 JSR-303,可以混着用,鉴于二者的某些 Validator 注解有差别,例如 @Length 在 Bean Validator 中是没有的,所以这里我选择混合用。
JSR-303
JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现,Hibernate Validator 提供了 JSR 303 规范中所有内置 Constraint(约束) 的实现,除此之外还有一些附加的 Constraint。这些 Constraint (约束) 全都通过注解的方式实现,请看下面两个表。
Bean Validation 中内置的约束:
注解
作用
@Null
被注解参数必须为空
@NotNull
被注解参数不能为空
@AssertTrue
被注解参数必须为 True
@AssertFalse
被注解参数必须为 False
@Min(value)
被注解参数必须是数字,且其值必须大于等于 value
@Max(value)
被注解参数必须是数字,且其值必须小于等于 value
@DecimaMin(value)
被注解参数必须是数字,且其值必须大于等于 value
@DecimaMax(value)
被注解参数必须是数字,且其值必须小于等于 value
@Size(max, min)
被注解参数大小必须在指定范围内
@Past
被注解参数必须是一个过去的日期
@Future
被注解参数必须是一个将来的日期
@Pattern(value)
被注解参数必须符合指定的正则表达式
@Digits(integer, fraction)
被注解参数必须是数字,且其值必须在可接受范围内
@NotBlank
被注解参数的值不为空(不为 null、去除首位空格后长度为 0),不同于 @NotEmpty,@NotBlank 只应用于字符串且在比较时会去除字符串的空格
Hibernate Validator 附加的约束:
注解
作用
@NotEmpty
被注解参数的值不为 null 且不为空(字符串长度不为 0、集合大小不为 0)
@Email
被注解参数必须是电子邮箱地址
@Length
被注解的字符串长度必须在指定范围内
@Range
被注解的参数必须在指定范围内
准备工作
SpringBoot 2.1.3
IDEA
JDK8
Pom 文件依赖
<!– web 启动类 –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!– test 单元测试类 –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!– lombok 依赖用于简化 bean –>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
实体类
用于测试,加入了参数校验规则。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private Integer id;
@NotBlank(message = “ 学生名字不能为空 ”)
@Length(min = 2, max = 10, message = “name 长度必须在 {min} – {max} 之间 ”)
private String name;
@NotNull(message = “ 年龄不允许为空 ”)
@Min(value = 0, message = “ 年龄不能低于 {value} 岁 ”)
private Integer age;
}
Controller 层
写了两个方法,一个用于校验普通参数,一个用于校验对象
@Validated // 开启数据校验,添加在类上用于校验方法,添加在方法参数中用于校验参数对象。(添加在方法上无效)
@RestController
@RequestMapping(“/student”)
public class ValidateOneController {
/**
* 普通参数校验
* @param name
* @return
*/
@GetMapping(“/name”)
public String findStudentByName(@NotBlank(message = “ 学生名字不能为空 ”)
@Length(min = 2, max = 10, message = “name 长度必须在 {min} – {max} 之间 ”)String name){
return “success”;
}
/**
* 对象校验
* @param student
* @return
*/
@PostMapping(“/add”)
public String addStudent(@Validated @RequestBody Student student){
return “success”;
}
}
Postman 测试
校验普通参数测试结果:
下图可以看见,我没有在 http://localhost:8080/student/name 地址后添加 name 参数,传到后台马上就校验出异常了。而这个异常信息就是我定义的校验异常信息。
校验对象测试结果:
结果有点长:
下图可以看见,我访问 http://localhost:8080/student/add 传入了参数对象,但对象是不能通过校验规则的,比如 age 参数为负数,name 参数长度太大,传到后台马上就校验出异常了。而这个异常信息就是我定义的校验异常信息。
完整代码
https://github.com/turoDog/De…
如果觉得对你有帮助,请给个 Star 再走呗,非常感谢。
后语
如果本文对你哪怕有一丁点帮助,请帮忙点好看。你的好看是我坚持写作的动力。
另外,关注之后在发送 1024 可领取免费学习资料。
资料详情请看这篇旧文:Python、C++、Java、Linux、Go、前端、算法资料分享