让Controller支持对平铺参数执行@Valid数据校验

  • 2019 年 10 月 3 日
  • 笔记

????

?????????????????????????????????????????????

????

???Java??????????Java Bean Validation 2.0?JSR303?JSR349?JSR380?Hibernate-Validation 6.x????
???Spring?@Validated?@Valid???????????Controller???????????????????
???Spring?Spring?????????@Validated + MethodValidationPostProcessor???????????


?Spring????????wx??`Java??????3?`????????


??

????Spring MVC????????Bean Validation????????????????????????????????????????????????????JavaBean??????????Controller?????????????

?????????Spring MVC??Controller??????????????????JavaBean?????????JavaBean???????????????????????case?????????????????Spring?@Validated?@Valid???????????Controller???????????????????

???????????????Controller?????????????????????????JavaBean?????????????????@Validated???JavaBean???????Spring MVC????????????????????????
??????????????????if else??????????????????????????????????????????~

Controller????????

??Spring MVC??????????????????????????case?????????????????????????????????????????????

??????Spring????????????

??????????????Spring???????web??Spring MVC?
Spring????????????????????Service??Dao??????????????????????????????Spring?Spring?????????@Validated + MethodValidationPostProcessor???????????

???????????????????????????????????????????

@Configuration  @EnableWebMvc  public class WebMvcConfig extends WebMvcConfigurerAdapter {      @Bean      public MethodValidationPostProcessor mvcMethodValidationPostProcessor() {          return new MethodValidationPostProcessor();      }  }

?Controller? ? ???@Validated????????????????????????

@RestController  @RequestMapping  @Validated  public class HelloController {      @PutMapping("/hello/id/{id}/status/{status}")      public Object helloGet(@Max(5) @PathVariable Integer id, @Min(5) @PathVariable Integer status) {          return "hello world";      }  }

???/hello/id/6/status/4 ???????
?????????

???????arg0 arg1?????????????????~~~

??????????????javax.validation.ConstraintViolationException???????????????????????????????????~

??????????????????????????????????????Controller??Bean?????????????MethodValidationPostProcessor????????????web??????????????MethodValidationPostProcessor??????~

??????????????????????MethodValidationPostProcessor?????? ????????????????SpringBoot?

????????????MethodValidationPostProcessor?case?????Bean?????????????????????Spring???Spring?bean???????name/id??????Spring????????BeanNameGenerator

???????????HandlerInterceptor?????????

?????????????????????????????????Controller??????????????????????????????????????HandlerInterceptor?????????????????????????~
?????Controller??? + @Validated?? + ???????????????????????????????????API?

1????????ValidationInterceptor?????????

// ????????@RequesrMapping??~~~~  public class ValidationInterceptor implements HandlerInterceptor, InitializingBean {        @Autowired      private LocalValidatorFactoryBean validatorFactoryBean;      @Autowired      private RequestMappingHandlerAdapter adapter;      private List<HandlerMethodArgumentResolver> argumentResolvers;        @Override      public void afterPropertiesSet() throws Exception {          argumentResolvers = adapter.getArgumentResolvers();      }        // ??      private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache = new ConcurrentHashMap<>(256);      private final Map<Class<?>, Set<Method>> initBinderCache = new ConcurrentHashMap<>(64);        @Override      public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {          // ???HandlerMethod??          if (handler instanceof HandlerMethod) {              HandlerMethod method = (HandlerMethod) handler;              Validated valid = method.getMethodAnnotation(Validated.class); //              if (valid != null) {                  // ????????????                  ValidatorImpl validatorImpl = (ValidatorImpl) validatorFactoryBean.getValidator();                    // ???????????~~~  org.springframework.core.MethodParameter                  MethodParameter[] parameters = method.getMethodParameters();                  Object[] parameterValues = new Object[parameters.length];                    //?????????????????????                  for (int i = 0; i < parameters.length; i++) {                      MethodParameter parameter = parameters[i];                      // ??????????????~                      HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);                      Assert.notNull(resolver, "Unknown parameter type [" + parameter.getParameterType().getName() + "]");                        ModelAndViewContainer mavContainer = new ModelAndViewContainer();                      mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));                        WebDataBinderFactory webDataBinderFactory = getDataBinderFactory(method);                      Object value = resolver.resolveArgument(parameter, mavContainer, new ServletWebRequest(request, response), webDataBinderFactory);                      parameterValues[i] = value; // ??                  }                    // ?????????                  Set<ConstraintViolation<Object>> violations = validatorImpl.validateParameters(method.getBean(), method.getMethod(), parameterValues, valid.value());                  // ?????????????????? javax.validation.ConstraintViolationException                  if (!violations.isEmpty()) {                      System.err.println("????????~~~~~~~");                      throw new ConstraintViolationException(violations);                  }              }            }            return true;      }        private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) {          Class<?> handlerType = handlerMethod.getBeanType();          Set<Method> methods = this.initBinderCache.get(handlerType);          if (methods == null) {              // ???@InitBinder??              methods = MethodIntrospector.selectMethods(handlerType, RequestMappingHandlerAdapter.INIT_BINDER_METHODS);              this.initBinderCache.put(handlerType, methods);          }          List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();          for (Method method : methods) {              Object bean = handlerMethod.getBean();              initBinderMethods.add(new InvocableHandlerMethod(bean, method));          }          return new ServletRequestDataBinderFactory(initBinderMethods, adapter.getWebBindingInitializer());      }        private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {          HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);          if (result == null) {              for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {                  if (methodArgumentResolver.supportsParameter(parameter)) {                      result = methodArgumentResolver;                      this.argumentResolverCache.put(parameter, result);                      break;                  }              }          }          return result;      }        @Override      public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {      }      @Override      public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {      }    }

2???????Web????????????????????LocalValidatorFactoryBean?

@Configuration  @EnableWebMvc  public class WebMvcConfig extends WebMvcConfigurerAdapter {        // ??????????  ????????~      @Bean      public LocalValidatorFactoryBean localValidatorFactoryBean() {          return new LocalValidatorFactoryBean();      }        // ??????????      @Bean      public ValidationInterceptor validationInterceptor() {          return new ValidationInterceptor();      }      @Override      public void addInterceptors(InterceptorRegistry registry) {          registry.addInterceptor(validationInterceptor()).addPathPatterns("/**");      }  }

3?Controller???????????????????@Validated???

    @Validated // ???????????? ????      @GetMapping("/hello/id/{id}/status/{status}")      public Object helloGet(@Max(5) @PathVariable("id") Integer id, @Min(5) @PathVariable("status") Integer status) {          return "hello world";      }

??/hello/id/6/status/4 ????????
?????????
????????????????????????????????????????????

  1. ???@PathVariable("id")????value????????@PathVariable??????????????????????????????value?????????????????????????
  2. ?????value??????????????????~
  3. ?Spring MVC???????????value??????????????????ok??????????????????????????????????????????????????~~~

    ??

    ??????????????????Controller????????????????????????????????????????????????????Spring MVC?????API????????

????????????????Java?????????Spring?????????????????Bean Validation???????????????????????????????????????????????????????????????????????????????????????~

????????????????????????????????????????????????????????????~

????

????????????????-????-????-????-????

==The last????????????????????????????????????????????????~==

?????????????wx????Java??????3??
??????????wx??fsx641385712???????wx??????????"java??" ??????????