package com.gihon.config.web; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import org.hibernate.validator.internal.engine.ValidatorImpl; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.MethodIntrospector; import org.springframework.core.MethodParameter; import org.springframework.util.Assert; import org.springframework.validation.annotation.Validated; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.InvocableHandlerMethod; import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.servlet.mvc.method.annotation.ServletRequestDataBinderFactory; import org.springframework.web.servlet.support.RequestContextUtils; //注意:此处只支持@RequetMapping方式 public class ValidationInterceptor implements HandlerInterceptor, InitializingBean { @Autowired private LocalValidatorFactoryBean validatorFactoryBean; @Autowired private RequestMappingHandlerAdapter adapter; private List argumentResolvers; @Override public void afterPropertiesSet() throws Exception { argumentResolvers = adapter.getArgumentResolvers(); } private final Map argumentResolverCache = new ConcurrentHashMap<>(256); private final Map, Set> 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> 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 methods = this.initBinderCache.get(handlerType); if (methods == null) { // 支持到@InitBinder注解 methods = MethodIntrospector.selectMethods(handlerType, RequestMappingHandlerAdapter.INIT_BINDER_METHODS); this.initBinderCache.put(handlerType, methods); } List 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 { } }