springmvc jsr303校验源代码分析-12

使用这个方法处理器处理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;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值