今天就简要描述一下在日常的开发工作中,所需要用到的参数校验.
主要有2种,一个是@Valid,一个是@Validated
@Valid
JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们JavaBean的属性上面.
从注解的定义上面也可可以看到,它可以适用于方法,成员变量,构造方法,参数等等.
范例如下:
在javax.validation包中可以看到更多功能的注解:
大家可以针对不同的场景做对应的参数校验.
@Validated
@Validated注解是spring-context包下实现的参数校验注解.
从定义上看,它可以应用于方法,参数,类,接口,枚举
在使用上与@Valid并无差别
使用
参数校验我们一般都用在Controller层进行对入参的校验.
使用在Controller层参数校验
demo写完之后,大家可以自行校验,如果3个参数有任何一个为空都是提示error,如下错误:
[Field error in object ‘user’ on field ‘address’: rejected value [null]; codes [NotNull.user.address,NotNull.address,NotNull.java.lang.String,NotNull];
在入参的前面我们使用的@Valid注解进行的校验.
也可以使用@Validated
如果对应的参数不符合我们设定的要求,都会提示对应的错误异常信息.
使用Service方法级别
如果在调用service方法的时候对应的参数不符合我们设定的要求就会提示异常
javax.validation.ConstraintViolationException: test.user.address: 不能为null.
大家可以注意到在类上我们使用了@Validated注解,这个是基于AOP的概念来实现的,后面我们在具体来讲解.
嵌套校验
User类中使用了Address类,如果要实现嵌套校验,就需要在address的变量上面添加@Valid注解,才能实现嵌套数据校验的功能.
自定义校验注解
此处定义一个校验手机号码的自定义注解,具体场景具体定义.
注解使用于方法和成员变量,@Target({ElementType.FIELD, ElementType.PARAMETER})
@Constraint(validatedBy = PhoneNumValidator.class),这个注解就是真正要校验手机号码的实现,PhoneNumValidator实现了具体校验手机号码的逻辑.
这里有个逻辑需要注意一下,在自定义的注解里面需要添加
String message() default "手机号码格式不正确";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
如果不添加对应方法,就会提示
contains Constraint annotation, but does not contain a groups parameter
下面我们看下真正校验此注解的validator
原理
对于javaBean的数据校验,提供了JSR303的校验标准,在jdk8后提供了JSR308的标准,spring同时兼容了这2种校验标准.
最终的实现是Hibernate Validator,所以最终校验的地方都是它
所以在我们的项目中就需要引用hibernate-validator的jar包.
springboot-web包中自动引入了hibernate-validator包.
Controller层入参校验
RequestBody参数校验
在使用@RequestBody的入参格式的时候,入参数据的校验是在RequestResponseBodyMethodProcessor类中发生的.
接着会走到DataBinder中的方法(关于DataBinder大家可以自行百度)
SpringValidatorAdapter
最终后面都是调用Hibernate-validator包中的bean数据校验.
PathVariable或者@RequestParam
在spring中基于上述2种方式处理入参的,需要在对应的controller添加@Validated,实现入参的数据校验,后面的逻辑请下方法层参数校验说明.
方法层参数校验
方法级别的参数校验其实是基于AOP的形式来实现的.
从MethodValidationPostProcessor类中我们可以看到具体的实现方式
在项目启动的时候我们跟踪到上述的类中
具体的业务逻辑是在MethodValidationInterceptor实现的