- 四、Spring请求参数校验(Hibernate Validator)
- 4.1 JSR-303规范
- 4.2 引入hibernate-validator
- 4.3 SpringMVC中使用hibernate-validator
- 4.3.1 配置LocalValidatorFactoryBean(非必选)
- 4.3.2 hibernate-validator常用注解
- 4.3.3 如何开启spring的参数校验
- 4.3.4 实体类参数校验(model/dto对象参数校验)
前端传入的请求参数往往是不可信的,因此对参数进行必要的校验可以有效防护CRLF攻击、SQL注入等。在参数校验方面,java也有一项规范为JSR-303 ,它是JAVA EE 6 中的一项子规范,叫做Bean Validation。JSR-303的规范api为validation-api,类似于servlet-api和annotation-api。而Hibernate Validator是JSR-303规范的一套具体实现。简单的说,validation-api是一套规范的接口,Hibernate Validator是其具体的实现。
4.2 引入hibernate-validatorhibernate-validator是validation-api的具体实现,所以我们需要引入validation-api和hibernate-validator两个依赖包。至于版本关系,由于需要集成在spring项目中,对依赖的版本由一定的约束,主要是javax与jakarta的区别参考链接。spring5.3.13引入validation-api2.0.2与hibernate-validator6.1.0.Final依赖可以
4.3 SpringMVC中使用hibernate-validator 4.3.1 配置LocalValidatorFactoryBean(非必选)2.0.2 6.0.17.Final jakarta.validation jakarta.validation-api ${validation-api.version} org.hibernate hibernate-validator ${hibernate-validator.version}
spring framework 提供了Bean Validation的功能,想要开启检验功能,需要定义一个验证器Bean——LocalValidatorFactoryBean。LocalValidatorFactoryBean中有一个属性providerClass,表明验证器的类。使用hibernate-validator的化需要指定providerClass的值为org.hibernate.validator.Hibernatevalidator。即spring会自动生成一个Hibernatevalidator对象,来实现具体的校验功能。
实际上,如果保证只引入了Hibernatevalidator一套校验的具体实现,上述配置也可以不需要,只需要引入4.2章节所需的依赖jar包即可,spring会在启动时默认寻找一套校验器的实现,在后面章节LocalValidatorFactoryBean的源码中会具体介绍。这里为了验证上述结论,在项目中实际并不配置LocalValidatorFactoryBean的bean。但是这里为明确项目中使用了校验功能,且指定Hibernate Validator实现,因此增加此项配置。
4.3.2 hibernate-validator常用注解hibernate-validator是基于注解式的实现,需要对某个参数进行校验,只需要在相应参数上添加注解即可。常用注解总结如下(加粗为常用):
- 非空校验
| 注解 | 支持的类型 | 校验功能 | 备注 |
|---|---|---|---|
| @Null | Object | 可以为null | |
| @NotNull | Object | 不能为null | 必选参数 |
| @NotEmpty | CharSequence、Collection、Map、Array | 不能为null,且不能为空,length/size必须>0 | 必选参数 |
| @NotBlank | CharSequence | 不能为null,且不能为空,且不能为空字符串 | 必选参数 |
注意:除上述注解外,下面的数值校验、正则校验等参数为null时,其校验结果为通过。
例如,一个Integer参数被@Max标注
@Max(max = 64) Integer num;
如果num=null时,@Max(max = 64)校验通过。
- 数值校验
| 注解 | 支持的类型 | 校验功能 (通过条件) |
|---|---|---|
| @Max | BigDecimal、BigInteger,byte、short、int、long以及包装类 | <=max |
| @Min | BigDecimal、BigInteger,byte、short、int、long以及包装类 | >=min |
| @Range | 数值类型和String | [min, max] |
| @DecimalMax | BigDecimal、BigInteger、CharSequence,byte、short、int、long以及包装类 | <=value |
| @DecimalMin | BigDecimal、BigInteger、CharSequence,byte、short、int、long以及包装类 | >=value |
| @Negative | BigDecimal、BigInteger,byte、short、int、long、float、double以及包装类 | <0 |
| @NegativeOrZero | BigDecimal、BigInteger,byte、short、int、long、float、double以及包装类 | <=0 |
| @Positive | BigDecimal、BigInteger,byte、short、int、long、float、double以及包装类 | >0 |
| @PositiveOrZero | BigDecimal、BigInteger,byte、short、int、long、float、double以及包装类 | >=0 |
| @Digits(integer = 4, fraction = 2) | BigDecimal、BigInteger、CharSequence,byte、short、int、long以及包装类 | 整数位数和小数位数上限 |
| @AssertTrue | boolean、Boolean | true |
| @AssertFalse | boolean、Boolean | false |
- 正则校验和长度、数量校验
| 注解 | 支持的类型 | 校验功能 |
|---|---|---|
| @Pattern | CharSequence | 匹配指定的正则表达式 |
| @Size | CharSequence、Collection、Map、Array | length/size必须在[min,max]之间 |
| @Length | String | 字符串长度范围 |
- 时间校验
| 注解 | 支持的类型 | 校验功能 |
|---|---|---|
| @Future | BigDecimal、BigInteger、CharSequence、byte, short, int, long及其包装类 | 验证日期为当前时间之后 |
| @FutureOrPresent | BigDecimal、BigInteger、CharSequence、byte, short, int, long及其包装类 | 验证日期为当前时间或之后 |
| @Past | BigDecimal、BigInteger、CharSequence、byte, short, int, long及其包装类 | 验证日期为当前时间之前 |
| @PastOrPresent | BigDecimal、BigInteger、CharSequence、byte, short, int, long及其包装类 | 验证日期为当前时间或之前 |
- 其他校验
| 注解 | 支持的类型 | 校验功能 |
|---|---|---|
| CharSequence | 邮箱地址,需regexp指定校验规则,默认为".*"。如"^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$" | |
| @URL | URL地址验证 |
由4.3.1和4.3.2章节可以看出,开启spring的参数校验前提条件
- 1、引入参数校验依赖,本文中使用Hibernate Validator;
- 2、配置LocalValidatorFactoryBean,指定校验的provider,此步非必选,spring mvc会默认配置。
但是这里还有第三个条件,就是在对需要的校验对象加上@Valid或@Validated注解。
- 3、使用@Valid或@Validated注解开启参数校验;
参数校验最常见场景时在post请求中对数据进行参数校验。例如为如下User实体类增加参数校验,校验id和name两个属性不能为空。
@Getter
@Setter
@ToString
public class User {
@NotBlank
private String id;
@NotBlank
private String name;
}
在对应的Controller方法上,对参数使用@Valid或@Validated注解开启参数校验
@RequestMapping(value = "/users", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@ResponseStatus(code = HttpStatus.ACCEPTED)
public String getUser(@RequestBody @Valid User users) {
System.out.println(users);
return "success";
}
验证:
可以看到name=" "时校验不通过,报400错误码。这里如果想定制化错误信息,可以参考下一篇【五、Spring国际化和全局异常处理】,处理异常并国际化错误信息,可以实现自定义参数校验错误信息。
假如参数校验规则修改为:
{
"id":"必选,最大64字符,只能为数字、字母、中划线(-)和下划线(_)",
"name":"非必选,最大64字符,只能为数字、字母、中划线(-)和下划线(_)",
}
则实体类校验规则如下
@Getter
@Setter
@ToString
public class User {
@NotBlank // 参数必选,如果前端不传id字段或为"",则序列化为null或"",校验失败
@Length(max = 64) // 最长64个字符
@Pattern(regexp = "^[a-z0-9A-Z_-]*$")
private String id; // 只能为数字、字母、中划线(-)和下划线(_)
@Length(max = 64) // 最长64个字符
@Pattern(regexp = "^[a-z0-9A-Z_-]*$") // 只能为数字、字母、中划线(-)和下划线(_)
private String name;
}
测试:



