让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 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
????????
????????????????????????????????????????????
- ???
@PathVariable("id")
????value
????????@PathVariable
??????????????????????????????value????????????????????????? - ?????
value
??????????????????~ -
?
Spring MVC
???????????value
??????????????????ok
??????????????????????????????????????????????????~~~??
??????????????????
Controller
????????????????????????????????????????????????????Spring MVC
?????API
????????
????????????????Java
?????????Spring
?????????????????Bean Validation
???????????????????????????????????????????????????????????????????????????????????????~
????????????????????????????????????????????????????????????~
????
???????????
?????-????-????-????-????
==The last????????????????????????????????????????????????~
==
?????????????wx????Java??????3?
?
??????????wx??fsx641385712
???????wx??????????"java??"
??????????