设为首页 加入收藏

TOP

使用 SpringBoot 进行优雅的数据验证(七)
2023-08-26 21:11:14 】 浏览:109
Tags:使用 SpringBoot
g("/saveUser") @ResponseBody //注意:如果方法中的参数是对象类型,则必须要在参数对象前面添加 @Validated public R saveUser(@Validated @RequestBody UserDTO userDTO){ userDTO.setUserId(100); return R.SUCCESS.setData(userDTO); }

这种属于 DTO 级别的校验。在 spring-mvc 中,RequestResponseBodyMethodProcessor 是用于解析@RequestBody 标注的参数以及处理@ResponseBody 标注方法的返回值的。显然,执行参数校验的逻辑肯定就在解析参数的方法 resolveArgument()中。

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

        parameter = parameter.nestedIfOptional();
        //将请求数据封装到DTO对象中
        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);
    }

}

可以看到,resolveArgument()调用了 validateIfApplicable()进行参数校验。

protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
    // 获取参数注解,比如@RequestBody、@Valid、@Validated
    Annotation[] annotations = parameter.getParameterAnnotations();
    for (Annotation ann : annotations) {
        // 先尝试获取@Validated 注解
        Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
        //如果直接标注了@Validated,那么直接开启校验。
        //如果没有,那么判断参数前是否有 Valid 起头的注解。
        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;
        }
    }
}

看到这里,大家应该能明白为什么这种场景下@Validated、@Valid 两个注解可以混用。我们接下来继续看 WebDataBinder.validate()实现。

最终发现底层最终还是调用了 Hibernate Validator 进行真正的校验处理。

404 等错误的统一处理

参考博客

参考

Spring Validation 实现原理及如何运用

SpringBoot 参数校验和国际化使用

@Valid 和@Validated 区别
Spring Validation 最佳实践及其实现原理,参数校验没那么简单!

出处:https://www.cnblogs.com/54chensongxia/p/14016179.html

首页 上一页 4 5 6 7 下一页 尾页 7/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇记录一次解决数据库连接池连接泄.. 下一篇Tomcat+Eclipse乱码问题解决方法

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目