(二)是有关以下一些复杂参数类型的处理:
(二)通过下面这个方法展示Model、Map等类型参数的源码分析:
在success方法中通过request获得“msg”的值这句,打断点。
其实就是testParam方法请求的这几个对象需要我们留意分析:
而Map、Model、request都可以向request域中放数据。然后在sucess方法中通过request.getAttribute得到放在request域中的Map、Model等类型的数据。
依旧debug进入循环判断resolver的方法,查看parameter可以发现对应的方法及其参数类型:
依旧是逐个判断,按顺序得到对应我们三种参数的resolver匹配(三种supportsParameter方法):
(Map)在类中的该方法:
(Model)在类中的该方法:
(request)(response)在类中的该方法略。
(印证了(二)中发现的处理多种不同的参数时采用不同的methodProcessor(不同的resolver)。)按照这个顺序解析参数——返回一个获得的resolver后(结束执行supportsParameter段逻辑),退回到原来的两个if判断处,再进入resolveArgument段逻辑:
下面按照方法的参数顺序,依次匹配到Map类型(参数[0])、Model类型(参数[1])、Request和Response类型(参数[3]、参数[4]):
(1)首先是Map类型(参数[0]):
进入resolveArgument段逻辑:
获得resolver不为null后调用对应resolver(这里是针对Map类型的)的resolveArgument方法:
注意查看ModelAndViewContainer类型:
进入ModelAndViewContainer类,针对Map类型的参数,mavContainer.getModel得到的是:
因此一般使用defaultModel,对象是BindingAwareModelMap。而他们的关系是:
一方面得到这个BindingAwareModelMap不仅是Model,也是Map:
(2)接着判断第二个参数(parameter[1])——Model类型:
然后发现跟Map类型调用的resolveArgument方法都是一样的:
也是通过mavContainer.getModel取得model对象的值。
现在args数组的值从 变成了:
惊喜地发现两者是同一个对象(BindingAwareModelMap)。
(3)Request、Response对象(参数[3]、参数[4]):过程略。
在return args;处打断点,直接放行到此处。args数组的值如下:
得到args包含四个参数后doInvoke就是执行目标controller的方法了,回到controller种的断点处:
执行完controller后会返回到invokeAndHandle方法处的断点:
返回值returnValue的值为:就要进行页面的转发处理。
且此时mavController已经存入Map和Model类型的两个参数:
(但是需要注意的是此时的view为null:,后文会再提到)
(无论怎样变换mavController都还是前文提到的同一个@7028的ModelAndViewContainer对象,而defaultModel是同一个@7232的BindingModelMap对象)
获得返回值后,returnValueHandler(返回值处理器)可以开始处理返回值:
*同理,returnValueHandler(返回值处理器)也有15种类型:
这个处理返回值的方法传入了返回值,返回值的类型,mavContainer(包含参数的值、信息)、我们的原生请求webRequest:
进入handleReturnValue方法:
继续进入handle.handleReturnValue方法:
就是将返回值(字符串)存成viewName(视图名),将其存入mavContainer中。
现在可以更深刻地理解到ModelAndViewContainer(mavContainer)的含义——Model和View对象的容器。View是要返回的地址(——视图),Model就是我们到这个地址携带的数据。
最后view的值也被添加到mavContainer中:(前文为null)
此时mavContainer包含我们请求所有的数据。
modelFactory可以帮助getModelAndView。进入getModelAndView方法:
getModelAndView方法告诉我们,执行完目标方法后由他来处理mavContainer(的内容):
①先进入updateModel方法,看他是如何更新mavContainer的:
更新model的绑定结果,就是得到ModelAndMap对象model中的数据(这里包含了前文的Model、Map对象)——遍历得到对应的key和value:
“绑定”这部分留到(三)自定义对象 那部分再详解。
回到getModelAndView方法中下部分,返回ModelAndView对象(mav):
完成ModelAndView对象的获取,完成请求处理。
A:一路回退到DispatcherServlet的doDispatch起始方法:,才真正完成ha.handle方法。
到这里我的mv为null。(需要重新debug,不知道哪里出了问题。。。)
B:请求处理完后执行applyPostHandle方法,进行拦截器(interceptors)的postHandle处理:
C:还需要处理派发结果(processDispatchResult方法):
可以进入 processDispatchResult方法看一下是如何处理分发结果的:
此时的mv对象中的model是重新封装过的(@后数字不一样,不同对象):
在processDispatchResult方法中继续向下执行,mv不为null,故进入render方法:
![render方法-部分代码1](https://i-blog.csdnimg.cn/blog_migrate/e87bd88c9b28cb5ddee5a78711501c7e.png)
render一般是“渲染”的意思。
mv.getViewName得到视图名viewName后,resolveViewName方法解析视图名,得到视图view。
第二个参数model是Map类型的:,所以调用该方法得到view时需要先将mv(ModelAndView)中的model通过mv.getModelInternal得到:
evaluate mv.getModelInternal的值,发现model就是我们的数据:
getModelInternal方法:
进入resolveViewName方法,其中的viewResolver(视图解析器)解析viewName。
再进入viewResolver的resolveViewName方法:
这里返回的bestView就是目标取得的view。
![](https://i-blog.csdnimg.cn/blog_migrate/e0448a71380d327bc83d0cdb02319f65.png)
进入render方法的核心方法:
mergedModel是合并(merge)后的model。
得到mergedModel后返回render方法中:
进行②准备响应(prepareResponse)和③渲染合并后输出的model(renderMergedOutputModel)。
renderMergedOutputModel是我们render渲染方法中的核心方法:
新版的getRequestToExpose方法:
旧版的getRequestToExpose方法:
返回一个原始的暴露请求(original)还是新的类型的。
故进入renderMergedOutputModel方法(InternalResourceView中):
关注到exposeModelAsRequestAttributes(核心方法)将model的数据(前面已提到过)暴露出来作为请求域的参数(attributes),(即在请求域中存取较容易??)。。。其实这是后面的视图解析器InternalResourceView的内容,这里不详述。
进入exposeModelAsRequestAttributes方法:
因此我们可以知道:
我们加在方法上的参数Model和Map都是一个东西,因为数据都放到model中,然后最后都会被加到请求域中(request.addAttribute)——>>看源码这么久的意义。
注意:这里有一个自学的思路,就是找实现方法时,如果只找到接口的抽象方法,可以ctrl+h(idea中快捷键)查看他与子类的继承or接口的实现关系,找到接口方法的实现类,就可以找到目标实现方法。比如在寻找render方法时(指不走debug时),返回的是View接口,就可以找它的实现类AbstractView,找renderMergedOutputModel具体方法时可以找他的子类InternalResourceView(具体如下图):