JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。(详见Reference[1])
JSR-303 constraint,如: @Null/@NotNull/@Min/@Max,位于 package javax.validation.constraints;
Hibernate Validator 附加的 constraint,如@Email/@Length/@Range,位于
package org.hibernate.validator.constraints;
@Data
public class ValidParam {
@Length(max = 20,min = 2)
private String name;
@Range(max = 200)
private Integer age;
}
PostBody
// import ***;
@RestController
@RequestMapping("valid")
public class ValidTestController {
/**
* postBody
* @param param
* @return
*/
@PostMapping("postBody")
public Result postBody(@RequestBody @Valid ValidParam param) {
return new Result<>();
}
/**
* postBody
* @param param
* @return
*/
@PostMapping("postBodyValidated")
public Result postBodyValidated(@RequestBody @Validated ValidParam param) {
return new Result<>();
}
}
PostForm
// import ***;
@RestController
@RequestMapping("valid")
public class ValidTestController {
@PostMapping("postForm")
public Result postForm(@Validated ValidParam param) {
return new Result<>();
}
}
GetPostParam
注意 Controller上加注解@Validated
@Validated
@RestController
@RequestMapping("valid")
public class ValidTestController {
/**
* getParam valid
* @param name
* @param age
* @return
*/
@GetMapping("getParam")
public Result getParam(@Length(max = 20,min = 2) String name,
@Range(max = 200) Integer age) {
return new Result<>();
}
/**
* postParam valid
* @param name
* @param age
* @return
*/
@PostMapping("postParam")
public Result postParam(@Length(max = 20,min = 2) String name,
@Range(max = 200) Integer age) {
return new Result<>();
}
}
不同校验方式抛出的异常类不同
PostBody
org.springframework.web.bind.MethodArgumentNotValidException
PostForm
org.springframework.validation.BindException
GetPostParam
javax.validation.ConstraintViolationException
PostBody
由 RequestResponseBodyMethodProcessor 处理
实现了HandlerMethodArgumentResolver 接口,在参数解析后进行校验。
validateIfApplicable中实现
可以看到@Validated、@Valid两个注解为什么可以混用
protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
Annotation[] annotations = parameter.getParameterAnnotations();
for (Annotation ann : annotations) {
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
binder.validate(validationHints);
break;
}
}
}
PostForm
由 ModelAttributeMethodProcessor 处理
实现了HandlerMethodArgumentResolver 接口,在参数解析后进行校验,同上类似。
GetPostParam
工作都由MethodValidationPostProcessor完成。
@Override
public void afterPropertiesSet() {
// 根据@Validated注解是否开启代理
Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
this.advisor = new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator));
}
// Create AOP advice for method validation purposes
protected Advice createMethodValidationAdvice(@Nullable Validator validator) {
return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());
}
核心验证由 MethodValidationInterceptor 实现。
获取分组,进行校验,逻辑简单,不再赘述。
嵌套字段上标注@Valid注解
详见Reference[4]