SpringBoot,SpringMVC中Validator中实现参数绑定的原理和总结

/**
 * <pre>
 *
 * 总结:
 *      1. 在SpringBoot中,参数为非复杂对象类型,默认情况下,在参数解析的时候不会进行参数校验,因为这这些简单类型不支持Bean Validation规范,而参数为复杂对象的时候,才会使用校验器对该对象进行字段校验
 *
 *
 *      简单参数如何进行校验呢? 除非手动调用Validator的API,否则就需要Spirng接入,Spring会提供一个{@link ValidationAutoConfiguration#methodValidationPostProcessor}后置处理器
 *      给类中添加了@Validated注解的类生成代理对象,并且在方法执行的过程中进行拦截{@link ValidationAutoConfiguration.MethodValidationInterceptor},对参数进行校验
 *      该代理对象还可以对返回值进行校验
 *
 *      在复杂对象参数解析的过程中,会自动对对象字段进行校验,校验出来的结果之后,如果对象参数后面紧挨的下一个参数为Error(BindingResult)类型,则不会抛出异常,则会把校验信息存入Error(BindingResult)中
 *      这是在springmvc源码中体现的
 *
 *      2. 在SpringMVC中,对于非复杂对象的类型参数,是不会进行参数校验的,即使添加了@Validated或者@Valid注解,因为这这些简单类型不支持Bean Validation规范
 *      但是,会对复杂的对象(JavaBean)进行参数校验,前提是参数中标记了@Validated或者@Valid注解,SpringMVC会自动对对象进行参数校验
 *      在复杂对象(JavaBean)参数解析的过程中,校验出来的结果之后,如果对象参数后面紧挨的下一个参数为Error(BindingResult)类型,如果校验失败也不会抛出异常,而是把校验信息存入Error(BindingResult)中
 *      默认不会给标注了@Validated的类生成代理对象,因为不会有自动配置,如果要完成简单参数的校验,我们有两种做法
 *         1. 使用SpringBoot类似的做法,给容器中注册MethodValidationPostProcessor后置处理器,该处理器会注册一个拦截器,拦截器用于校验参数的validation注解信息,既可以校验参数,也可以校验返回值
 *         2. 可以使用AOP切面,拦截方法参数,使用Validator进行校验
 *
 *          @Bean
 *          public static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment,@Lazy Validator validator) {
 *              // 或者直接创建MethodValidationPostProcessor对象
 * 		        MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
 * 		        boolean proxyTargetClass = environment.getProperty("spring.aop.proxy-target-class", Boolean.class, true);
 * 		        processor.setProxyTargetClass(proxyTargetClass);
 * 		        processor.setValidator(validator);
 * 		        return processor;
 *          }
 *
 *     3. 扩展,配置Validator
 *      @Configuration
 *      public class LuckConfig implements WebMvcConfigurer {
 *          // 手动配置Validator
 *          public LocalValidatorFactoryBean localValidatorFactoryBean() {
 *               return new LocalValidatorFactoryBean();
 *          }
 *          // 通过WebMvcConfigurer配置
 *          @Override
 *          public Validator getValidator() {
 *              return new LocalValidatorFactoryBean();
 *          }
 *     }
 *
 * <p>
 *      注意: 非JavaBean字段参数的下个参数为BindingResult的话,会抛出异常,因为只有在JavaBean对象校验的时候,会添加一个"BindingResult.对象名"的标记
 *           因此在参数解析的时候,解析到BindingResult,则会从Model对象中找以"BindingResult."开头的数据,如果没有保存"BindingResult."的标记,则会抛出异常
 *           {@link ErrorsMethodArgumentResolver}
 *           因此,只有在JavaBean参数校验的时候,才能使用BindingResult参数接收错误信息
 * </pre>
 */


// 参数解析器,用于解析参数为Errors(BindingResult参数)
public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        Class<?> paramType = parameter.getParameterType();
        return Errors.class.isAssignableFrom(paramType);
    }

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

        // 获取运行中的Model数据
        ModelMap model = mavContainer.getModel();
        // 获取model中存入的所有数据,是否存在"BindingResult.class.getName() + "."标记
        // 该key是标记该对象是JavaBean对象,进行了校验操作
        String lastKey = CollectionUtils.lastElement(model.keySet());
        if (lastKey != null && lastKey.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
            return model.get(lastKey);
        }
        // 如果不包含"BindingResult.class.getName() + "."标记,则抛出异常
        throw new IllegalStateException(
                "An Errors/BindingResult argument is expected to be declared immediately after " +
                        "the model attribute, the @RequestBody or the @RequestPart arguments " +
                        "to which they apply: " + parameter.getMethod());
    }

}

// 参数解析器,用于解析JavaBean参数,或者标有@ModelAttribute注解的参数
public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {
    public boolean supportsParameter(MethodParameter parameter) {
        // 存在@ModelAttribute注解,或者参数指定了不是必须的,并且是JavaBean类型
        return (parameter.hasParameterAnnotation(ModelAttribute.class) || (this.annotationNotRequired && !BeanUtils.isSimpleProperty(parameter.getParameterType())));
    }

    @Nullable
    public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
        // 获取参数名称
        String name = ModelFactory.getNameForParameter(parameter);
        // 获取注解信息
        ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
        if (ann != null) {
            // 设置当前参数是否需要绑定
            mavContainer.setBinding(name, ann.binding());
        }

        // 参数对象
        Object attribute = null;
        // 异常结果对象
        BindingResult bindingResult = null;
        // 如果在Model中存在该参数值
        if (mavContainer.containsAttribute(name)) {
            // 直接从Model中获取数据
            attribute = mavContainer.getModel().get(name);
        } else {
            // 如果Model中没有存入该对象,则创建对象的实例
            try {
                attribute = createAttribute(name, parameter, binderFactory, webRequest);
            } catch (BindException ex) {
                // 创建对象失败,是否需要抛出绑定异常
                // 当参数校验失败,判断当前参数的下一个参数为BindingResult,如果不是,则抛出异常
                if (isBindExceptionRequired(parameter)) {
                    //无BindingResult参数,直接抛出异常
                    throw ex;
                }
                // 保存校验的结果对象
                bindingResult = ex.getBindingResult();
            }
        }
        // 如果创建对象成功
        if (bindingResult == null) {
            // 创建对象属性值绑定器
            WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
            // 如果存在绑定的对象
            if (binder.getTarget() != null) {
                // 如果没有禁用参数绑定
                if (!mavContainer.isBindingDisabled(name)) {
                    // 进行参数绑定,就是将参数从request中获取,进行类型转换,然后设置到对象中,都是由binder对象完成
                    this.bindRequestParameters(binder, webRequest);
                }
                // 参数校验@Validated和@Valid注解
                this.validateIfApplicable(binder, parameter);
                // 校验结果存在binder的bindingResult中,并且校验失败之后,是否必须抛出绑定异常
                if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                    throw new BindException(binder.getBindingResult());
                }
            }
            // 如果参数解析到的参数值和实际类型不一致,进行类型转换
            if (!parameter.getParameterType().isInstance(attribute)) {
                attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
            }
            // 获取数据绑定的结果
            bindingResult = binder.getBindingResult();
        }

        // 获取绑定结果中的数据
        Map<String, Object> bindingResultModel = bindingResult.getModel() {
            // 标记两个字段,一个是对象信息,一个是绑定信息
            Map<String, Object> model = new LinkedHashMap<>(2);
            // 从名称到目标对象的映射。
            model.put(getObjectName(), getTarget());
            // 错误实例,即使没有错误
            model.put(MODEL_KEY_PREFIX + getObjectName(), this);
            return model;
        }
        // 删除之前绑定的数据
        mavContainer.removeAttributes(bindingResultModel);
        // 将新数据重新保存
        mavContainer.addAllAttributes(bindingResultModel);
        // 返回绑定好的参数对象
        return attribute;
    }

    // 校验失败之后,是否必须抛出绑定异常
    protected boolean isBindExceptionRequired(MethodParameter parameter) {
        // 获取参数的位置
        int i = parameter.getParameterIndex();
        // 获取到参数的类型
        Class<?>[] paramTypes = parameter.getExecutable().getParameterTypes();
        // 如果当前参数的下一个参数为Errors(BindingResult),则不会抛出异常,否则抛出异常
        boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
        return !hasBindingResult;
    }

    // 参数校验,是否存在@Valid***注解信息
    protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
        // 获取参数的注解
        for (Annotation ann : parameter.getParameterAnnotations()) {
            // 校验@Valid***注解
            Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann) {
                Class<? extends Annotation> annotationType = ann.annotationType();
                String annotationName = annotationType.getName();
                // 如果注解为@Valid,没有需要校验的分组
                if ("javax.validation.Valid".equals(annotationName)) {
                    return EMPTY_OBJECT_ARRAY;
                }
                // 注解为Validated,获取注解的value值,获取校验的分组信息
                Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
                if (validatedAnn != null) {
                    Object hints = validatedAnn.value();
                    // 如果不为空,返回指定的分组,否则返回EMPTY_OBJECT_ARRAY
                    return this.convertValidationHints(hints);
                }
                // 如果都不是上面两者,如果注解类型为Valid开头的注解,或者对应的值
                if (annotationType.getSimpleName().startsWith("Valid")) {
                    Object hints = AnnotationUtils.getValue(ann);
                    // 如果不为空,返回指定的分组,否则返回EMPTY_OBJECT_ARRAY
                    return convertValidationHints(hints);
                }
                return null;
            }
            // 如果存在@Valid***注解,则不为null
            if (validationHints != null) {
                // 进行参数校验
                binder.validate(validationHints);
                break;
            }
        }
    }

    class WebDataBinder {
        // 进行分组校验,并将结果
        public void validate(Object... validationHints) {
            // 获取需要校验的对象
            Object target = this.getTarget();
            // 从Binder对象中获取BindingResult,如果没有,创建一个保存到当前Binder对象中,用于保存校验结果
            BindingResult bindingResult = this.getBindingResult();
            // 遍历所有的校验器,这个校验器是从@EnableMvc中,注入的RequestMappingHandlerAdapter设置的一个ConfigurableWebBindingInitializer对象
            // 该ConfigurableWebBindingInitializer对象中保存Spring中保存的类型转换器和参数转换器,也是通过@EnableMvc导入的WebMvcConfigurationSupport一起使用@Bean注入的
            // 然后在WebDataBinderFactory创建WebDataBinder对象的时候,指定ConfigurableWebBindingInitializer该对象的initBinder方法,然后将ConfigurableWebBindingInitializer的数据都设置导WebDataBinder对象中
            for (Validator validator : this.getValidators()) {
                // 如果需要进行分组校验
                if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) {
                    // 调用Validator校验器开始校验
                    /**
                     * {@link LocalValidatorFactoryBean#validate}
                     */
                    ((SmartValidator) validator).validate(target, bindingResult, validationHints);
                }
                // 普通的校验器
                else if (validator != null) {
                    /**
                     * {@link LocalValidatorFactoryBean#validate}
                     */
                    validator.validate(target, bindingResult);
                }
            }
        }
    }
}

public class LocalValidatorFactoryBean extends SpringValidatorAdapter implements SmartValidator, Validator {
    // 代理的Validator
    private Validator targetValidator;

    // 内置的属性名
    static {
        internalAnnotationAttributes.add("message");
        internalAnnotationAttributes.add("groups");
        internalAnnotationAttributes.add("payload");
    }

    // 设置需要代理的Validator
    public void setTargetValidator(Validator targetValidator) {
        this.targetValidator = targetValidator;
    }

    // 初始化操作
    public void afterPropertiesSet() {
        // 获取对Validator工厂的配置对象
        Configuration<?> configuration = Validation.byDefaultProvider().configure();
        ConstraintValidatorFactory targetConstraintValidatorFactory = this.constraintValidatorFactory;
        // 对Validator工厂进行配置
        if (targetConstraintValidatorFactory == null && this.applicationContext != null) {
            targetConstraintValidatorFactory = new SpringConstraintValidatorFactory(this.applicationContext.getAutowireCapableBeanFactory());
        }
        if (targetConstraintValidatorFactory != null) {
            configuration.constraintValidatorFactory(targetConstraintValidatorFactory);
        }
        if (this.parameterNameDiscoverer != null) {
            configureParameterNameProvider(this.parameterNameDiscoverer, configuration);
        }
        // 构建Validator工厂
        this.validatorFactory = configuration.buildValidatorFactory();
        // 创建Validator,并保存
        this.setTargetValidator(((ValidatorFactoryImpl) this.validatorFactory).getValidator());
    }

    // 分组验证整个对象
    @Override
    public void validate(Object target, Errors errors, Object... validationHints) {
        // 如果存在代理的Validator,在上面LocalValidatorFactoryBean创建过,通过ValidatorFactoryImpl创建的
        if (this.targetValidator != null) {
            // 将提供的信息进行过滤,只过滤Class类型指定的分组
            Class<?>[] groups = asValidationGroups(validationHints);
            // 调用Hibernate提供的validator校验
            Set<ConstraintViolation<Object>> violations = this.targetValidator.validate(target, groups);
            // 处理校验结果,将Validator校验的结果保存到Errors(BindingResult)对象中
            processConstraintViolations(violations, errors);
        }
    }

    // 验证对象的某个字段的值
    @Override
    public void validateValue(Class<?> targetType, String fieldName, @Nullable Object value, Errors errors, Object... validationHints) {
        // 和validate方法,这个事调用验证某个字段的api
        if (this.targetValidator != null) {
            // 处理校验结果,将Validator校验的结果保存到Errors(BindingResult)对象中
            processConstraintViolations(this.targetValidator.validateValue((Class) targetType, fieldName, value, asValidationGroups(validationHints)), errors);
        }
    }
}


// 在spring.factories中,配置了org.springframework.context.ApplicationListener = org.springframework.boot.autoconfigure.BackgroundPreinitializer
// 该类是一个监听器,处理ApplicationEnvironmentPreparedEvent事件,环境预处理完成的回调事件
@Order(LoggingApplicationListener.DEFAULT_ORDER + 1)
public class BackgroundPreinitializer implements ApplicationListener<SpringApplicationEvent> {
    public void onApplicationEvent(SpringApplicationEvent event) {
        // 确定是第一次被初始化
        if (event instanceof ApplicationEnvironmentPreparedEvent && preinitializationStarted.compareAndSet(false, true)) {
            // 初始化一些配置信息
            this.performPreinitialization();
        }
    }

    private void performPreinitialization() {
        // 启动新线程,执行下面这些初始化器的run方法
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                // 初始化类型转换器
                runSafely(new ConversionServiceInitializer());
                // 初始化Validator校验器
                runSafely(new ValidationInitializer());
                // 注册各种各样的消息转换器
                runSafely(new MessageConverterInitializer());
                // 注册ObjectMapper
                runSafely(new JacksonInitializer());
                // 初始化字符集
                runSafely(new CharsetInitializer());
            }

            public void runSafely(Runnable runnable) {
                runnable.run();
            }

        }, "background-preinit");
        thread.start();
    }

    class ValidationInitializer implements Runnable {
        // 这里只是为了初始化,触发类加载等等配置,并没有做什么实际性的东西
        @Override
        public void run() {
            // 调用javax.validation.Validation的创建工厂的方法
            // 下面两行代码与 Validation.buildDefaultValidatorFactory()方法完全一样
            Configuration<?> configuration = Validation.byDefaultProvider().configure();
            ValidatorFactory factory = configuration.buildValidatorFactory();
            // 通过工厂获取
            Validator validator = factory.getValidator();
        }
    }


}

// Hibernate实现了javax.validator.ValidatorFactory,class org.hibernate.validator.internal.engine.ValidatorFactoryImpl
public class ValidatorFactoryImpl implements ValidatorFactory {
    @Override
    public Validator getValidator() {
        ConstraintValidatorFactory validatorFactory = constraintCreationContext.getConstraintValidatorManager().getDefaultConstraintValidatorFactory();
        // 创建校验器
        return this.createValidator(validatorFactory, constraintCreationContext, validatorFactoryScopedContext, methodValidationConfiguration);
    }

    // 创建校验器
    public Validator createValidator(ConstraintValidatorFactory constraintValidatorFactory, ConstraintCreationContext constraintCreationContext, ValidatorFactoryScopedContext validatorFactoryScopedContext, MethodValidationConfiguration methodValidationConfiguration) {
        // 获取到校验对象的元数据管理器
        BeanMetaDataManager beanMetaDataManager = beanMetaDataManagers.computeIfAbsent(
                new BeanMetaDataManagerKey(validatorFactoryScopedContext.getParameterNameProvider(),
                        constraintCreationContext.getValueExtractorManager(), methodValidationConfiguration),
                key -> new BeanMetaDataManagerImpl(constraintCreationContext, executableHelper,
                        validatorFactoryScopedContext.getParameterNameProvider(), javaBeanHelper,
                        beanMetadataClassNormalizer, validationOrderGenerator, buildMetaDataProviders(),
                        methodValidationConfiguration)

        );
        // 返回Validator的实现类ValidatorImpl
        return new ValidatorImpl(constraintValidatorFactory, beanMetaDataManager, constraintCreationContext.getValueExtractorManager(), constraintCreationContext.getConstraintValidatorManager(), validationOrderGenerator, validatorFactoryScopedContext);
    }
}

class ValidatorImpl implements Validator, ExecutableValidator {

}

// 在springboot的自动配置中
@AutoConfiguration
@ConditionalOnClass(ExecutableValidator.class)
@ConditionalOnResource(resources = "classpath:META-INF/services/javax.validation.spi.ValidationProvider")
@Import(PrimaryDefaultValidatorPostProcessor.class)
public class ValidationAutoConfiguration {

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @ConditionalOnMissingBean(Validator.class)
    public static LocalValidatorFactoryBean defaultValidator(ApplicationContext applicationContext) {
        // 会注册一个LocalValidatorFactoryBean,它本身是一个Validator
        LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
        return factoryBean;
    }

    @Bean
    @ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
    public static FilteredMethodValidationPostProcessor methodValidationPostProcessor(Environment environment, @Lazy Validator validator, ObjectProvider<MethodValidationExcludeFilter> excludeFilters) {
        // 拦截@Validated方法的后置处理器
        FilteredMethodValidationPostProcessor processor = new FilteredMethodValidationPostProcessor(excludeFilters.orderedStream());
        // 获取生成代理对象的类型,CGLIB还是JDK
        boolean proxyTargetClass = environment.getProperty("spring.aop.proxy-target-class", Boolean.class, true);
        processor.setProxyTargetClass(proxyTargetClass);
        // 设置校验器
        processor.setValidator(validator);
        return processor;
    }


    public static class FilteredMethodValidationPostProcessor extends MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor {
        // 校验的注解类型
        private Class<? extends Annotation> validatedAnnotationType = Validated.class;
        // 校验器
        private Validator validator;
        // 要生成代理对象的拦截器
        protected Advisor advisor;

        @Override
        public void afterPropertiesSet() {
            // 创建一个切面,因为存在Validated注解的类或者方法,需要生成代理对象
            Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
            // 创建一个通知,拦截器
            Advice advice = createMethodValidationAdvice(this.validator);
            this.advisor = new DefaultPointcutAdvisor(pointcut, advice);
        }

        protected Advice createMethodValidationAdvice(@Nullable Validator validator) {
            return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());
        }


        // 预处理代理工厂
        @Override
        protected ProxyFactory prepareProxyFactory(Object bean, String beanName) {
            if (this.beanFactory != null) {
                // 暴露目标对象,将目标对象按照指定的key保存到BeanDefinition中
                AutoProxyUtils.exposeTargetClass(this.beanFactory, beanName, bean.getClass());
            }
            // 创建代理工厂
            ProxyFactory proxyFactory = super.prepareProxyFactory(bean, beanName) {
                ProxyFactory proxyFactory = new ProxyFactory();
                proxyFactory.copyFrom(this);
                // 设置需要代理的对象
                proxyFactory.setTarget(bean);
                return proxyFactory;
            }
            // 是否使用CBlib代理
            if (!proxyFactory.isProxyTargetClass() && this.beanFactory != null && AutoProxyUtils.shouldProxyTargetClass(this.beanFactory, beanName)) {
                proxyFactory.setProxyTargetClass(true);
            }
            return proxyFactory;
        }

        // 当前类MethodValidationPostProcessor就是为了
        public Object postProcessAfterInitialization(Object bean, String beanName) {
            // 如果当前没有拦截器,或者该bean本身是一个特殊的接口AopInfrastructureBean(标记该类为AOP的Bean)
            if (this.advisor == null || bean instanceof AopInfrastructureBean) {
                return bean;
            }
            // 该Bean是一个代理工厂,创建代理对象的工厂类
            if (bean instanceof Advised) {
                Advised advised = (Advised) bean;
                if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
                    // 将我们的当前类需要应用的切面添加到现有代理的Advisor链中
                    if (this.beforeExistingAdvisors) {
                        advised.addAdvisor(0, this.advisor);
                    } else {
                        advised.addAdvisor(this.advisor);
                    }
                    return bean;
                }
            }
            // 该bean是否可以应用上当前类需要应用的切面
            if (this.isEligible(bean, beanName)) {
                // 当前切面可以作用于该Bean对象,创建代理对象
                ProxyFactory proxyFactory = this.prepareProxyFactory(bean, beanName);
                // 没有设置使用CGLIB
                if (!proxyFactory.isProxyTargetClass()) {
                    // 计算需要代理的接口
                    this.evaluateProxyInterfaces(bean.getClass(), proxyFactory);
                }
                // 添加切面
                proxyFactory.addAdvisor(this.advisor);
                // 自定义代理工厂
                this.customizeProxyFactory(proxyFactory);
                // 创建代理对象
                return proxyFactory.getProxy(classLoader);
            }
            // 不需要代理直接返回
            return bean;
        }

    }

    public static class MethodValidationInterceptor implements MethodInterceptor {
        // 校验器
        private final Validator validator;

        public Object invoke(MethodInvocation invocation) throws Throwable {
            // 避免在FactoryBean.getObjectType/isSingleton上调用验证器
            if (this.isFactoryBeanMetadataMethod(invocation.getMethod())) {
                return invocation.proceed();
            }
            // 确定校验对象需要校验的分组
            Class<?>[] groups = this.determineValidationGroups(invocation);

            // 标准Bean验证1.1 API
            // Validator本身只提供对象或者对象属性的校验,对于校验方法,它并没有提供API
            // 而是提供了一个ExecutableValidator对于方法的校验器,该对象可以校验方法参数,方法返回值,构造参数
            ExecutableValidator execVal = this.validator.forExecutables();
            // 获取到需要校验的方法
            Method methodToValidate = invocation.getMethod();
            // 校验的结果
            Set<ConstraintViolation<Object>> result;
            // 校验的对象
            Object target = invocation.getThis();

            // 校验方法参数
            result = execVal.validateParameters(target, methodToValidate, invocation.getArguments(), groups);
            // 如果参数校验不同过,抛出异常
            if (!result.isEmpty()) {
                throw new ConstraintViolationException(result);
            }
            // 执行目标方法
            Object returnValue = invocation.proceed();
            // 再校验返回值
            result = execVal.validateReturnValue(target, methodToValidate, returnValue, groups);
            // 如果返回值校验失败,抛出异常
            if (!result.isEmpty()) {
                throw new ConstraintViolationException(result);
            }
            return returnValue;
        }

        // 确定校验对象需要校验的分组
        protected Class<?>[] determineValidationGroups(MethodInvocation invocation) {
            // 找方法中的Validated注解
            Validated validatedAnn = AnnotationUtils.findAnnotation(invocation.getMethod(), Validated.class);
            // 如果方法中不存在
            if (validatedAnn == null) {
                // 找类中的注解
                Object target = invocation.getThis();
                validatedAnn = AnnotationUtils.findAnnotation(target.getClass(), Validated.class);
            }
            // 返回注解中的分组的值
            return (validatedAnn != null ? validatedAnn.value() : new Class<?>[0]);
        }
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot是一个用于简化Spring应用程序开发的框架。它并没有官方实现Mybatis的启动器,但是Mybatis官方自己实现了一个启动器,可以在pom.xml文件引入依赖来使用。\[1\]为了开发web工程,需要在pom.xml引入spring-boot-starter-web依赖,这个依赖包含了Spring WebMVC和Tomcat等web开发的特性。\[2\]在使用SpringBoot快速入门时,需要进行以下步骤:添加依赖spring-boot-starter-web和spring-boot-starter-parent,创建控制器Controller和DispatcherServlet前端控制器,然后启动SpringBoot项目。\[3\]在控制器类上使用注解来标识该类是一个业务控制器,比如使用@SpringBootApplication注解来标识启动类,@Controller注解来标识控制器类。\[3\]至于整合SpringBootSpringMVC和Mybatis框架,可以通过配置文件和注解来实现。具体的整合方式可以根据项目需求和实际情况进行选择和配置。 #### 引用[.reference_title] - *1* *3* [springboot整合mybatis等框架](https://blog.csdn.net/qq_42652006/article/details/126833620)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [springboot整合mybatis,springmvc](https://blog.csdn.net/sunhongbing1024/article/details/83186783)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值