前言
估计很多朋友都认为参数校验是客户端的职责, 不关服务端的事. 其实这是错误的, 学过 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) |
被注解参数必须是电子邮箱地址 | |
@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/Demo/tree/master/springboot_validateone_demo
如果觉得对你有帮助, 请给个 Star 再走呗, 非常感谢.
后语
如果本文对你哪怕有一丁点帮助, 请帮忙点好看. 你的好看是我坚持写作的动力.
另外, 关注之后在发送 1024 可领取免费学习资料.
资料详情请看这篇旧文: Python,C++,Java,Linux,Go, 前端, 算法资料分享 https://www.jianshu.com/p/ed43dc8aa11e
来源: https://juejin.im/post/5c7be2596fb9a049fe35de38