对于任何一个应用而言,客户端做的数据有效性验证都不是安全有效的,而数据验证又是一个企业级项目架构上最为基础的功能模块,这时候就要求我们在服务端接收到数据的时候也对数据的有效性进行验证。为什么这么说呢?往往我们在编写程序的时候都会感觉后台的验证无关紧要,毕竟客户端已经做过验证了,后端没必要在浪费资源对数据进行验证了,但恰恰是这种思维最为容易被别人钻空子。毕竟只要有点开发经验的都知道,我们完全可以模拟 HTTP
请求到后台地址,模拟请求过程中发送一些涉及系统安全的数据到后台,后果可想而知…. 接下来下文会记录 Java后端 如何做数据验证…
—— 摘自唐亚峰前辈的描述
就一句话,前后端都得校验
[TOC]
JSR-303 注释介绍
JSR-303 是JAVA EE 6 中的一项子规范,叫做 Bean Validation
,Hibernate Validator
是 Bean Validation
的参考实现 . Hibernate Validator
提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。Java 后台数据验证
就是基本它实现的。
这里只列举了 javax.validation
包下的注解,同理在 spring-boot-starter-web
包中也存在 hibernate-validator
验证包,里面包含了一些 javax.validation
没有的注解,有兴趣的可以看看
注解 | 说明 |
---|---|
@NotNull |
限制 必须 不为null |
@NotEmpty |
验证注解的元素值 不为 null 且不为空(这里的空指:字符串长度不为0、集合size() 大小不为0) |
@NotBlank |
验证注解的元素值 不为空(不为null、去除首位空格 后长度不为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格 |
@Pattern(value) |
限制 必须符合 指定的正则表达式 |
@Size(max,min) |
限制字符长度必须在 min 到 max 之间(也可以用在集合上) |
@Email |
验证注解的元素值是Email,也可以通过正则表达式和 flag 指定自定义的email格式 |
@Max(value) |
限制必须为一个不大于指定值的数字 |
@Min(value) |
限制必须为一个不小于指定值的数字 |
@DecimalMax(value) |
限制必须为一个不大于指定值的数字 |
@DecimalMin(value) |
限制必须为一个不小于指定值的数字 |
@Null |
限制只能为null(很少用) |
@AssertFalse |
限制必须为false (很少用) |
@AssertTrue |
限制必须为true (很少用) |
@Past |
限制必须是一个 过去 的日期 |
@Future |
限制必须是一个 将来 的日期 |
@Digits(integer,fraction) |
限制必须为一个小数,且整数部分的位数不能超过 integer,小数部分的位数不能超过 fraction (很少用) |
@Size(max, min) |
带注释的元素(Collection、Map等等)的长度必须在指定的范围内 |
@Range(max, min) |
带注释的元素的大小必须在指定的范围内 |
@Positive |
带注释的元素必须是一个严格的正数(即0被视为无效值) |
@PositiveOrZero |
带注释的元素必须为一个正数或者0 |
环境/版本一览:
- 开发工具:Intellij IDEA 2018.2.2
- springboot: 2.1.0.RELEASE
- jdk:1.8.0_171
- maven:3.3.9
1、pom.xml
1 | <dependencies> |
2、application.yml
1 | server: |
3、entity
Book.java
1 | package com.fatal.entity; |
Reader.java
1 | package com.fatal.entity; |
注解介绍
- @Validated: 开启数据有效性校验,添加在类上即为验证方法,添加在方法参数中即为验证参数对象。(添加在方法上无效)
- @NotBlank: 被注释的字符串不允许为空(
value.trim() > 0 ? true : false
) - @Length: 被注释的字符串的大小必须在指定的范围内
- @NotNull: 被注释的字段不允许为空(
value != null ? true : false
) - @DecimalMin: 被注释的字段必须大于或等于指定的数值
上面的条件运算符
取自注解校验器的方法实现
4、controller
此处只是为了图方便只写在了 Controller 层,同理你可以将它作用在 Service 层)
1 | package com.fatal.controller; |
显示
启动项目
可以使用 IDEA 自带的 RestClient
测试,也可以使用 Postman
测试
访问
http://localhost:8088/test1
IDEA 自带的 Rest Client(name长度为1)
Postman(name长度为1)
访问
http://localhost:8088/test2
- IDEA 自带的 Rest Client(
readerName
长度为1)
- Postman(readerName长度为1)
- IDEA 自带的 Rest Client(
笔记
1、@Valid 和 @Validated
javax提供了@Valid(标准JSR-303规范),Spring Validation 验证框架对参数的验证机制提供了@Validated(Spring’s JSR-303规范,是标准JSR-303的一个变种)。@Validated 或者 @Valid 在基本验证功能上没有太多区别,但是在分组、注解地方、嵌套验证等功能上两个有所不同:
- 分组
@Validated:提供了一个 分组 功能,可以在入参验证时,根据不同的分组采用不同的验证机制,第三篇探究。
@Valid:不提供分组功能。 - 注解地方
@Validated:可以用在类型、方法和方法参数上,不能 用在成员属性(字段)上
@Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上
注:两者是否能用于成员属性(字段)上直接影响能否提供嵌套验证的功能。 - 嵌套验证
嵌套的属性需要验证时,在该属性上标注开启嵌套验证的注解
@Validated:不可以(因为它标注在成员属性上不起作用)
@Valid:可以
2、嵌套验证格式总结
在方法上我们用 @Validated + BindingResult
1 | "/test2", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) (value = |
在实体类中,对 entity
和 List<entity>
等等的与 entity
类型相关的成员属性,需要在这些属性上添加 @Valid
注解
1 |
|
1 |
|
3、@Validated校验参数的问题
3.1、获取异常信息
当 @Validated 放在类上,结合 JSR 注解 校验参数的时候,不能与 BindingResult 或者 Errors 一起使用,所有我们要是想取校验信息,可以采取别的方式。这里的方式是我在最近一个项目中用的,很简单,就是全局异常处理器获取异常信息并返回。
这里列举一个异常处理方法
1 | package com.gzxant.exception; |
由方法实现中知,校验出现的异常信息封装在 Set<ConstraintViolation<?>>
中,我们只想取出即可。已测试能用
3.2、@RequestParam
+ @NotBlank
不起作用
必须使用 @RequestParam(value="",defaultValue="")
来接受单参,注意,必须要有默认值空串,否则 @NotBlank
不起作用
1 |
|
4、BindingResult
起不了作用
问题描述:
刚开始我这样写。在校验的实体和 BindingResult
之间隔了个 Model
。
然后 BindingResult
就不起作用。
解决:
校验的实体和 BindingResult
紧挨一起
BindingResult
就能正常使用了。
结论:
BindingResult
必须紧跟在校验实体后面
参考资料
一起来学SpringBoot | 第十九篇:轻松搞定数据验证(一)
@Validated和@Valid区别:Spring validation验证框架对入参实体进行嵌套验证必须在相应属性(字段)加上@Valid而不是@Validated
总结
SpringBoot
的知识已经有前辈在我们之前探索了。比较喜欢的博主有:唐亚峰 | Battcn、方志朋的专栏、程序猿DD、纯洁的微笑。对这门技术感兴趣的可以去他们的博客逛逛。谢谢他们的分享~~
以上文章是我用来学习的Demo
,都是基于 SpringBoot2.x
版本。
源码地址: https://github.com/ynfatal/springboot2-learning/tree/master/chapter26_1