在Spring MVC中,ViewResolver 用来将用户控制器生成的返回结果解析成视图,View定义了不同的视图,并渲染给用户,但是Spring是怎样工作的呢?现在我们就分析下Spring如何解析返回的结果生成响应的视图。
一、概念
View ---View接口表示一个响应给用户的视图,例如jsp文件,pdf文件,html文件等,它的定义如下
public interface View {
//HttpServletRequest中的属性名,其值为响应状态码
String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
//HttpServletRequest中的属性名,它的对应值是请求路径中的变量,及@PathVariable
//注解的变量
String PATH_VARIABLES = View.class.getName() + ".pathVariables";
//该视图的ContentType
String getContentType();
//渲染该视图
void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response);
}
该接口只有两个方法定义,分别表明该视图的ContentType和如何被渲染。Spring中提供了丰富的视图支持,几乎包含所有你想得到的,并且Spring的视图拓展性很好,你可以轻松实现自己的视图。下面是View的一些实现类:
类结构图:
ViewResolver --- ViewResolver接口定义了如何通过view 名称来解析对应View实例的行为,它的定义相当简单:
public interface ViewResolver {
View resolveViewName(String viewName, Locale locale) throws Exception;
}
该接口只有一个方法,通过view name 解析出View。同样Spring提供了丰富的ViewResolver实现用来解析不同的View:
ViewResolver的类结构:
二、怎么获取ModelAndView
Spring是如何处理返回值并响应给客户呢?这就是这节要分析的,根据返回值解析出对应的视图。
private ModelAndView invokeHandleMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod requestMappingMethod =
createRequestMappingMethod(handlerMethod, binderFactory);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncExecutionChain chain = AsyncExecutionChain.getForCurrentRequest(request);
chain.addDelegatingCallable(getAsyncCallable(mavContainer, modelFactory, webRequest));
chain.setAsyncWebRequest(createAsyncWebRequest(request, response));
chain.setTaskExecutor(this.taskExecutor);
//调用了处理器方法并处理了返回值
requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
if (chain.isAsyncStarted()) {
return null;
}
//这里是根据返回值返回ModelAndView
return getModelAndView(mavContainer, modelFactory, webRequest);
}
invokeAndHandle方法调用了处理器方法,并处理了返回值,剩下的就是如何将返回值呈现给用户了,我们看getModelAndView的实现:
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
//主要是同步model属性,并且将BindingResult添加到model中来
modelFactory.updateModel(webRequest, mavContainer);
//是否直接处理请求,如@ResponseBody
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}//如果model是RedirectAttributes,进行flashAttributes的处理
//即将flashAttribute属性添加到request的Output FlashMap中,以被重定向后的request获取
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webReque