今天就简要描述一下在日常的开发工作中,所需要用到的参数校验.
主要有2种,一个是@Valid,一个是@Validated

@Valid

java 注解 验证字符长度 java注解校验入参_数据校验


JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们JavaBean的属性上面.

从注解的定义上面也可可以看到,它可以适用于方法,成员变量,构造方法,参数等等.

范例如下:

java 注解 验证字符长度 java注解校验入参_java 注解 验证字符长度_02


在javax.validation包中可以看到更多功能的注解:

java 注解 验证字符长度 java注解校验入参_数据校验_03


大家可以针对不同的场景做对应的参数校验.

@Validated

java 注解 验证字符长度 java注解校验入参_java 注解 验证字符长度_04


@Validated注解是spring-context包下实现的参数校验注解.

从定义上看,它可以应用于方法,参数,类,接口,枚举

在使用上与@Valid并无差别

使用

参数校验我们一般都用在Controller层进行对入参的校验.

使用在Controller层参数校验

java 注解 验证字符长度 java注解校验入参_java_05


java 注解 验证字符长度 java注解校验入参_数据校验_06


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

java 注解 验证字符长度 java注解校验入参_java_07


如果对应的参数不符合我们设定的要求,都会提示对应的错误异常信息.

使用Service方法级别

java 注解 验证字符长度 java注解校验入参_Validated_08


java 注解 验证字符长度 java注解校验入参_java_09


如果在调用service方法的时候对应的参数不符合我们设定的要求就会提示异常

javax.validation.ConstraintViolationException: test.user.address: 不能为null.

大家可以注意到在类上我们使用了@Validated注解,这个是基于AOP的概念来实现的,后面我们在具体来讲解.

嵌套校验

java 注解 验证字符长度 java注解校验入参_java 注解 验证字符长度_10


java 注解 验证字符长度 java注解校验入参_Validated_11


User类中使用了Address类,如果要实现嵌套校验,就需要在address的变量上面添加@Valid注解,才能实现嵌套数据校验的功能.

自定义校验注解

java 注解 验证字符长度 java注解校验入参_数据校验_12


此处定义一个校验手机号码的自定义注解,具体场景具体定义.

注解使用于方法和成员变量,@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

java 注解 验证字符长度 java注解校验入参_数据校验_13


java 注解 验证字符长度 java注解校验入参_valid_14

原理

对于javaBean的数据校验,提供了JSR303的校验标准,在jdk8后提供了JSR308的标准,spring同时兼容了这2种校验标准.

最终的实现是Hibernate Validator,所以最终校验的地方都是它

所以在我们的项目中就需要引用hibernate-validator的jar包.

java 注解 验证字符长度 java注解校验入参_数据校验_15


springboot-web包中自动引入了hibernate-validator包.

Controller层入参校验

RequestBody参数校验

在使用@RequestBody的入参格式的时候,入参数据的校验是在RequestResponseBodyMethodProcessor类中发生的.

java 注解 验证字符长度 java注解校验入参_java_16


java 注解 验证字符长度 java注解校验入参_java 注解 验证字符长度_17


接着会走到DataBinder中的方法(关于DataBinder大家可以自行百度)

java 注解 验证字符长度 java注解校验入参_java 注解 验证字符长度_18


SpringValidatorAdapter

java 注解 验证字符长度 java注解校验入参_Validated_19


最终后面都是调用Hibernate-validator包中的bean数据校验.

PathVariable或者@RequestParam

在spring中基于上述2种方式处理入参的,需要在对应的controller添加@Validated,实现入参的数据校验,后面的逻辑请下方法层参数校验说明.

方法层参数校验

方法级别的参数校验其实是基于AOP的形式来实现的.

从MethodValidationPostProcessor类中我们可以看到具体的实现方式

在项目启动的时候我们跟踪到上述的类中

java 注解 验证字符长度 java注解校验入参_java 注解 验证字符长度_20


具体的业务逻辑是在MethodValidationInterceptor实现的

java 注解 验证字符长度 java注解校验入参_valid_21