SpringMvc执行过程

 

--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


posted @ 2017-04-04 17:20  NewSea  阅读(1097)  评论(0编辑  收藏  举报