请求处理——Map、Model类型参数处理原理
首先,先说结论,当我们给参数位置写 Map和Model 时,Map,Model 里边的数据会被放在 request 的请求域中,相当于我们调用了 request.setAttribute() ,接下来我们就来测试一下
//测试接口
@GetMapping("/params")
public String testParam(Map<String,Object> map,
Model model,
HttpServletRequest request,
HttpServletResponse response){
map.put("hello","world666");
model.addAttribute("world","hello666");
request.setAttribute("message","HelloWorld");
Cookie cookie = new Cookie("c1","v1");
response.addCookie(cookie);
return "forward:/success";
}
@ResponseBody
@GetMapping("/success")
public Map success(@RequestAttribute(value = "msg",required = false) String msg,
@RequestAttribute(value = "code",required = false) Integer code,
HttpServletRequest request){
Object msg1 = request.getAttribute("msg");
Map<String,Object> map = new HashMap<>();
Object hello = request.getAttribute("hello");
Object world = request.getAttribute("world");
Object message = request.getAttribute("message");
map.put("reqMethod_msg",msg1);
map.put("annotation_msg",msg);
map.put("hello",hello);
map.put("world",world);
map.put("message",message);
return map;
}
发送请求测试结果
验证了上边的结论:
参数Map、Model、request都是给request域中放数据
可以使用 request.getAttribute(); 进行获取,或者页面使用EL表达式获取
现在我们已经验证了结论是正确的,那里边的原理是什么呢?接下来就是debug环节
上一篇分析过的这里就不在重复了,我们直接来带真正执行目标方法的地方
进入该方法
首先,第一个参数是一个map,寻找解析它的解析器为 MapMethodProcessor
拿到解析器之后,我们来看它如何进行参数解析
往下到 InvocableHandlerMethod 类 的如下地方
来到 HandlerMethodArgumentResolverComposite 类的 resolveArgument 方法
来到了 MapMethodProcessor 类的 resolveArgument 方法
它里边会从 mavContainer 也就是 ModelAndViewContainer 中拿到并返回一个 BindingAwareModelMap 这就是第一个参数map,接下来看第二个参数 model ,经过和上边一样流程的调试,发现虽然它的解析器是 ModelMethodProcessor ,但是最后走的还是 mavContainer
所以得出结论:Map、Model类型的参数,会返回 mavContainer.getModel();返回BindingAwareModelMap 是Model 也是 Map
这样的方式拿到所有的参数,然后执行目标方法
执行完目标方法后,来到 ServletInvocableHandlerMethod 类的 invokeAndHandle,我们目标方法中给map和model中加的数据就保存到了 mavContainer
其实执行目标方法完成后,所有的数据都被放到了ModelAndViewContainer ,里边包含要去的地方 view 和 数据 model ,后边都是在处理它
然后继续下一步, ServletInvocableHandlerMethod 类 调用了 handleReturnValue ,传入了我们的 mavContainer
接下来一堆堆 mavContainer 的处理,处理完之后回到 DispatcherServlet 类,来到下边的 processDispatchResult 处理最终结果,处理完之后下边有一个 view.render(); 方法调用,还在 DispatcherServlet.class
进入这个方法,来到 AbstractView.class
我们也就验证了前边的结论:我们 Map 和 Model 类型的参数,其实本质上是一个东西,最终都被放入了 Request 请求域中。
到这里,Map、Model类型参数处理原理的原理我们就搞清楚了,下一篇再见!