• 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

    
    
  • 相关阅读:
    获取mysql数据库中的表信息
    Django Rest Framework --- 分页器组件
    Django Rest Framework --- 频率组件
    Django Rest Framework --- 权限组件
    Django Rest Framework --- 认证组件
    Django Rest Framework --- 视图组件
    序列化组件
    restful规范,cbv源码执行流程,drf之APIView及Respons源码分析
    前后台分离式开发(文件的上传下载),cookie(存放在前台),session(存放在后台)
    ajax,分页器
  • 原文地址:https://www.cnblogs.com/newsea/p/6665525.html
Copyright © 2020-2023  润新知