Springboot2.x中的hibernate-validator(2)POST请求

1、ConstraintViolationException与MethodArgumentNotValidException

一般情况下我们会发现对GET请求的入参做参数校验时抛出ConstraintViolationException异常,而对POST请求的RequestBody做参数校验时会抛出MethodArgumentNotValidException异常。这与Spring中绑定GET参数和POST参数的方式不同有关。

2、MethodArgumentNotValidException异常的来源

Post绑定参数依靠WebDataBinder来实现将参数绑定到JavaBean对象上。
RequestResponseBodyMethodProcessor中的resolveArgument会将MethodParameter转换为controller中定义的JavaBean。

	@Override
	public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

		parameter = parameter.nestedIfOptional();
		Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
		String name = Conventions.getVariableNameForParameter(parameter);

		if (binderFactory != null) {
			WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
			if (arg != null) {
				validateIfApplicable(binder, parameter);
				if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
					throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
				}
			}
			if (mavContainer != null) {
				mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
			}
		}

		return adaptArgumentIfNecessary(arg, parameter);
	}

其中validateIfApplicable在对parameter进行校验,若binder绑定的结果中有错误,则会抛出MethodArgumentNotValidException异常。

	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;
			}
		}
	}

从validateIfApplicable中可以发现参数校验生效的条件是能找到@Validated注解或者其他以Valid开头的注解。这与Springboot2.x中的hibernate-validator(1)GET请求中以@Validated注解为切点的方式不一样。
binder.validate

	public void validate(Object... validationHints) {
		Object target = getTarget();
		Assert.state(target != null, "No target to validate");
		BindingResult bindingResult = getBindingResult();
		// Call each validator with the same binding result
		for (Validator validator : getValidators()) {
			if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) {
				((SmartValidator) validator).validate(target, bindingResult, validationHints);
			}
			else if (validator != null) {
				validator.validate(target, bindingResult);
			}
		}
	}

进入ValidatorImpl之后就与Springboot2.x中的hibernate-validator(1)GET请求类似了。
剩下需要探讨的问题就是这两个所使用的validator是同一个吗?

你可能感兴趣的:(Java)