--Test过程:
1. 先执行各种 Filter
2. HttpServlet.service(ServletRequest req, ServletResponse res)
3. HttpServlet.service(HttpServletRequest req, HttpServletResponse resp) 根据 Method做分发。以下是POST流程
4. FrameworkServlet.doPost(HttpServletRequest request, HttpServletResponse response) -> processRequest -> doService -> doDispatch
5. org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handle -> handlerInternal -> invokeHandlerMethod -> invokeHandle -> invokeForRequest ->
6. InvocableHandlerMethod.doInvoke
7. 到了Action方法
--Post 带参数 详细过程
http://blog.csdn.net/fytain/article/details/43918609
问题:
像普通函数那样定义action。 从 request.body 里的 JSON 串中取出某个属性值。
先解析!
1. 各种Filter
2. /org/apache/catalina/core/ApplicationFilterChain.java 中 internalDoFilter ,servlet.service
3. /javax/servlet/http/HttpServlet.java . service
4. HttpServlet.service(HttpServletRequest req, HttpServletResponse resp) 根据 Method做分发。以下是POST流程
5. FrameworkServlet.doPost(HttpServletRequest request, HttpServletResponse response) -> processRequest -> doService -> doDispatch
6.org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handle -> handlerInternal -> invokeHandlerMethod -> invokeHandle -> invokeForRequest
7. 在 /org/springframework/web/method/support/InvocableHandlerMethod.java 的 invokeForRequest 方法中:
getMethodArgumentValues(request, mavContainer , 变参 provideArgs) 获取参数
之后调用 doInvoke(args)
getMethodArgumentValue方法:
/** * Get the method argument values for the current request. */ private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { MethodParameter[] parameters = getMethodParameters(); Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { MethodParameter parameter = parameters[i]; parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); args[i] = resolveProvidedArgument(parameter, providedArgs); if (args[i] != null) { continue; } if (this.argumentResolvers.supportsParameter(parameter)) { try { args[i] = this.argumentResolvers.resolveArgument( parameter, mavContainer, request, this.dataBinderFactory); continue; } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex); } throw ex; } } if (args[i] == null) { throw new IllegalStateException("Could not resolve method parameter at index " + parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() + ": " + getArgumentResolutionErrorMessage("No suitable resolver for", i)); } } return args; }
重点:
1. this.argumentResolvers.supportsParameter
2. this.argumentResolvers.resolveArgument ,如下:
@Override public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { NamedValueInfo namedValueInfo = getNamedValueInfo(parameter); MethodParameter nestedParameter = parameter.nestedIfOptional(); Object resolvedName = resolveStringValue(namedValueInfo.name); if (resolvedName == null) { throw new IllegalArgumentException( "Specified name must not resolve to null: [" + namedValueInfo.name + "]"); } Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest); if (arg == null) { if (namedValueInfo.defaultValue != null) { arg = resolveStringValue(namedValueInfo.defaultValue); } else if (namedValueInfo.required && !nestedParameter.isOptional()) { handleMissingValue(namedValueInfo.name, nestedParameter, webRequest); } arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType()); } else if ("".equals(arg) && namedValueInfo.defaultValue != null) { arg = resolveStringValue(namedValueInfo.defaultValue); } if (binderFactory != null) { WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name); try { arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter); } catch (ConversionNotSupportedException ex) { throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(), namedValueInfo.name, parameter, ex.getCause()); } catch (TypeMismatchException ex) { throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(), namedValueInfo.name, parameter, ex.getCause()); } } handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest); return arg; }
在 resolveArgument 方法过程中,先执行 resolveName,再执行 handleResolvedValue
@Override protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception { HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class); MultipartHttpServletRequest multipartRequest = WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class); Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest); if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) { return mpArg; } Object arg = null; if (multipartRequest != null) { List<MultipartFile> files = multipartRequest.getFiles(name); if (!files.isEmpty()) { arg = (files.size() == 1 ? files.get(0) : files); } } if (arg == null) { String[] paramValues = request.getParameterValues(name); if (paramValues != null) { arg = (paramValues.length == 1 ? paramValues[0] : paramValues); } } return arg; }
解决方式:
package pzx.base.config import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.web.servlet.HandlerInterceptor import org.springframework.web.servlet.config.annotation.InterceptorRegistry import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter import java.util.ArrayList import org.springframework.boot.web.servlet.FilterRegistrationBean import org.springframework.boot.web.servlet.ServletRegistrationBean import pzx.web.sys.AuthImageServlet import javax.servlet.MultipartConfigElement import org.springframework.beans.factory.annotation.Autowired import org.springframework.core.MethodParameter import org.springframework.core.env.Environment import org.springframework.http.HttpInputMessage import org.springframework.http.HttpOutputMessage import org.springframework.http.MediaType import org.springframework.http.converter.HttpMessageConverter import org.springframework.web.bind.support.WebDataBinderFactory import org.springframework.web.context.request.NativeWebRequest import org.springframework.web.method.support.HandlerMethodArgumentResolver import org.springframework.web.method.support.HandlerMethodReturnValueHandler import org.springframework.web.method.support.ModelAndViewContainer import pzx.base.comm.JsonMap import pzx.base.extend.FromJson import pzx.base.extend.ToJson import java.nio.charset.Charset import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletRequestWrapper /** * Created by udi on 2017.3.11. */ @Configuration open class MyWebMvcConfig : WebMvcConfigurerAdapter() { @Bean open fun filterRegistrationBean(): FilterRegistrationBean { val registrationBean = FilterRegistrationBean() val httpBasicFilter = MyAllFilter() registrationBean.filter = httpBasicFilter val urlPatterns = ArrayList<String>() urlPatterns.add("/*") urlPatterns.add("/**") registrationBean.urlPatterns = urlPatterns return registrationBean } override fun addInterceptors(registry: InterceptorRegistry?) { if (registry == null) return registry.addInterceptor(MySessionFilter()) .addPathPatterns("/*") .addPathPatterns("/**") .excludePathPatterns("/hi") .excludePathPatterns("/open/**") .excludePathPatterns("/oh") .excludePathPatterns("/doc") .excludePathPatterns("/error") .excludePathPatterns("/login") .excludePathPatterns("/registe") .excludePathPatterns("/swagger-resources/**") .excludePathPatterns("/v2/**") } @Bean fun RegisteAuthImageServlet(): ServletRegistrationBean { var registration = ServletRegistrationBean(AuthImageServlet()) registration.isEnabled = true registration.addUrlMappings("/open/getValidateCodeImage") return registration } class RequestJsonResolver : HandlerMethodArgumentResolver { //只认是否包含。 override fun supportsParameter(parameter: MethodParameter?): Boolean { if (parameter!!.parameterName == null) return false; if (HttpContext.request is MyHttpRequestWrapper) return false; return (HttpContext.request as MyHttpRequestWrapper).json.containsKey(parameter.parameterName) } override fun resolveArgument(parameter: MethodParameter?, mavContainer: ModelAndViewContainer?, webRequest: NativeWebRequest?, binderFactory: WebDataBinderFactory?): Any { var request = webRequest!!.nativeRequest as MyHttpRequestWrapper; if (parameter!!.parameterName == null) { throw Error("${request.requestURI} 找不到 ${parameter!!.parameterName}"); } var map = request.json;//String(request!!.inputStream.readBytes(), Charset.defaultCharset()).FromJson<JsonMap>(); if (map.containsKey(parameter!!.parameterName)) { return map.get(parameter!!.parameterName)!!; } return parameter!!.parameterType.newInstance(); } } override fun addArgumentResolvers(argumentResolvers: MutableList<HandlerMethodArgumentResolver>?) { argumentResolvers?.add(RequestJsonResolver()) super.addArgumentResolvers(argumentResolvers) } }
如何接收Map数据:
http://www.codes51.com/article/detail_114729.html
调试发现: SpringMvc可以接收 LinkedHashMap<String, String> , Map<String,String> , 但不能接收继承 LinkedHashMap 的数据类型。 也不能接收 HashMap 。
估计是这帮SB把代码又写死了。
Model绑定
http://stackoverflow.com/questions/12893566/passing-multiple-variables-in-requestbody-to-a-spring-mvc-controller-using-ajax
https://www.oschina.net/question/227902_162591
<mvc:annotation-driven>
<mvc:argument-resolvers>
<beans:bean class="com.redcollar.bl.commons.extension.JsonArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
对应的SpringBoot,就是
@Configuration
+
WebMvcConfigurerAdapter
教程:http://starscream.iteye.com/blog/1098880