github原文链接 https://github.com/DespairYoke/java-advance。创作不易,请给个免费的star,已表支持。
示例
@GetMapping(value = "hello")
public MyModelAndView index(String name, ModelAndView modelAndView) {
modelAndView.addObject("message",name);
modelAndView.setViewName("index");
return modelAndView;
}
返回值的处理
由于返回值类型是ModelAndView,不是简单的字符串。这时返回值的处理不再使用ViewNameMethodReturnValueHandler
,而是使用了ModelAndViewMethodReturnValueHandler
处理的方式来处理。具体处理方法是
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
ModelAndView mav = (ModelAndView) returnValue;
String viewName = mav.getViewName();
mavContainer.setViewName(viewName);
mavContainer.setStatus(mav.getStatus());
mavContainer.addAllAttributes(mav.getModel());
}
这里只是简单的把视图名(示例中的index)和mav中的model
(示例中的message)放入mavContainer
。那我们接着看下这个mavContainer
后续是如何处理。
由执行顺序可以在RequestMappingHandlerAdapter
的invokeHandlerMethod
方法看到,下一个对mavcontainer做处理的是getModelAndView
方法。
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
return mav;
}
可见mavContainer好像一个容器,把ModelAndView从返回值放入进去,现在又取出来生成新的ModelAndView
。跟踪代码,看下新的ModelAndView
又被何时处理。发现是在DispatcherServlet
的doDispatch
方法中的processDispatchResult
方法中进行处理。
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable MyHandlerExecutionChain mappedHandler, @Nullable MyModelAndView mv,Exception exception) throws Exception {
// 获取视图view
render(mv, request, response);
}
此时就调用了一个render
方法。
protected void render(MyModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
//获取适合的view
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
view.render(mv.getModelInternal(), request, response);
}
-
resolveViewName
获取适合的view
-
render
视图渲染页面。
public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
Map mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(request, response);
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
-
createMergedOutputModel
创建了一个Map对象mergedModel
,把model中的信息放入新对map对象mergedModel
中。 -
renderMergedOutputModel
是对新mapmergedModel
处理。
protected void renderMergedOutputModel(
Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
exposeModelAsRequestAttributes(model, request);
String dispatcherPath = prepareForRendering(request, response);
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
rd.forward(request, response);
}
- exposeModelAsRequestAttributes 是把model中的信息放入request中
protected void exposeModelAsRequestAttributes(Map model, HttpServletRequest request) throws Exception {
model.forEach((modelName, modelValue) -> {
request.setAttribute(modelName, modelValue);
});
}
- prepareForRendering 根据示例中的
index
值,找到对应的jsp路径。 - rd.forward 只是对request的转发。
总结:spring只是把ModelandView
中的信息经过一系列处理,最终放入了request
中,交给Servlet去处理。