使用这个方法处理器处理error:ErrorsMethodArgumentResolver,处理完后,会自动绑定到参数里面
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#resolveArgument
@Override public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { parameter = parameter.nestedIfOptional(); //dk 读取请求报文,将其转换为对象 Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType()); String name = Conventions.getVariableNameForParameter(parameter); if (binderFactory != null) { //dk 创建一个数据校验绑定器 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); }
开始校验逻辑
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver#validateIfApplicable
protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) { //dk 获取方法里面的注解: @Valid @RequestBody2个 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}); //dk 开始核心的校验逻辑 binder.validate(validationHints); break; } } }
org.springframework.validation.DataBinder#validate(java.lang.Object...)
public void validate(Object... validationHints) { //dk 获取目标对象,也就是User2 Object target = getTarget(); Assert.state(target != null, "No target to validate"); //dk 获取默认的绑定结果 BindingResult bindingResult = getBindingResult(); // Call each validator with the same binding result for (Validator validator : getValidators()) { if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) { //dk 开始核心的校验 ((SmartValidator) validator).validate(target, bindingResult, validationHints); } else if (validator != null) { validator.validate(target, bindingResult); } } }
org.springframework.validation.beanvalidation.SpringValidatorAdapter#processConstraintViolations
protected void processConstraintViolations(Set<ConstraintViolation<Object>> violations, Errors errors) { for (ConstraintViolation<Object> violation : violations) { String field = determineField(violation); FieldError fieldError = errors.getFieldError(field); if (fieldError == null || !fieldError.isBindingFailure()) { try { ConstraintDescriptor<?> cd = violation.getConstraintDescriptor(); //dk 获取字段上的注解Range String errorCode = determineErrorCode(cd); Object[] errorArgs = getArgumentsForConstraint(errors.getObjectName(), field, cd); if (errors instanceof BindingResult) { // Can do custom FieldError registration with invalid value from ConstraintViolation, // as necessary for Hibernate Validator compatibility (non-indexed set path in field) BindingResult bindingResult = (BindingResult) errors; String nestedField = bindingResult.getNestedPath() + field; if (nestedField.isEmpty()) { String[] errorCodes = bindingResult.resolveMessageCodes(errorCode); ObjectError error = new ViolationObjectError( errors.getObjectName(), errorCodes, errorArgs, violation, this); bindingResult.addError(error); } else { //dk 获取age注入的值 Object rejectedValue = getRejectedValue(field, violation, bindingResult); //dk 获取和range相关的属性 String[] errorCodes = bindingResult.resolveMessageCodes(errorCode, field); //获取和注解相关出错的属性 FieldError error = new ViolationFieldError(errors.getObjectName(), nestedField, rejectedValue, errorCodes, errorArgs, violation, this); //dk 把出错的属性放入集合中 bindingResult.addError(error); } } else { // got no BindingResult - can only do standard rejectValue call // with automatic extraction of the current field value errors.rejectValue(field, errorCode, errorArgs, violation.getMessage()); } } catch (NotReadablePropertyException ex) { throw new IllegalStateException("JSR-303 validated property '" + field + "' does not have a corresponding accessor for Spring data binding - " + "check your DataBinder's configuration (bean property versus direct field access)", ex); } } } }
protected String determineField(ConstraintViolation<Object> violation) { //dk 获取字段名称 Path path = violation.getPropertyPath(); StringBuilder sb = new StringBuilder(); boolean first = true; for (Path.Node node : path) { if (node.isInIterable()) { sb.append('['); Object index = node.getIndex(); if (index == null) { index = node.getKey(); } if (index != null) { sb.append(index); } sb.append(']'); } String name = node.getName(); if (name != null && node.getKind() == ElementKind.PROPERTY && !name.startsWith("<")) { if (!first) { sb.append('.'); } first = false; sb.append(name); } } return sb.toString(); }
public FieldError getFieldError(String field) { String fixedField = fixedField(field); for (ObjectError objectError : this.errors) { if (objectError instanceof FieldError) { FieldError fieldError = (FieldError) objectError; if (isMatchingFieldError(fixedField, fieldError)) { return fieldError; } } } return null; }