SpringMVC源碼解析二:請求處理過程5

// 5.結果視圖對象的處理
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
applyDefaultViewName(processedRequest, mv);
	private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
		if (mv != null && !mv.hasView()) {
			String defaultViewName = getDefaultViewName(request);
			if (defaultViewName != null) {
				mv.setViewName(defaultViewName);
			}
		}
	}
	
	void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
			throws Exception {

		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = interceptors.length - 1; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				interceptor.postHandle(request, response, this.handler, mv);
			}
		}
	}

視圖渲染方法:

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {

		boolean errorView = false;

		if (exception != null) {
			if (exception instanceof ModelAndViewDefiningException) {
				logger.debug("ModelAndViewDefiningException encountered", exception);
				mv = ((ModelAndViewDefiningException) exception).getModelAndView();
			}
			else {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
				mv = processHandlerException(request, response, handler, exception);
				errorView = (mv != null);
			}
		}

		// Did the handler return a view to render?
		if (mv != null && !mv.wasCleared()) {
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
						"': assuming HandlerAdapter completed request handling");
			}
		}

		if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			// Concurrent handling started during a forward
			return;
		}

		if (mappedHandler != null) {
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}
	
	
	



render方法中實現:

render方法:
	protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// Determine locale for request and apply it to the response.
		Locale locale =
				(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
		response.setLocale(locale);

		//聲明一個view
		View view;
		//得到一個view名字
		String viewName = mv.getViewName();
		if (viewName != null) {
			// We need to resolve the view name.
			//創建對象
			view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
			if (view == null) {
				throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
						"' in servlet with name '" + getServletName() + "'");
			}
		}
		else {
			// No need to lookup: the ModelAndView object contains the actual View object.
			view = mv.getView();
			if (view == null) {
				throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
						"View object in servlet with name '" + getServletName() + "'");
			}
		}

		// Delegate to the View object for rendering.
		if (logger.isDebugEnabled()) {
			logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
		}
		try {
			if (mv.getStatus() != null) {
				response.setStatus(mv.getStatus().value());
			}
			//渲染view
			view.render(mv.getModelInternal(), request, response);
		}
		catch (Exception ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
						getServletName() + "'", ex);
			}
			throw ex;
		}
	}

    protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
			Locale locale, HttpServletRequest request) throws Exception {

		//遍歷本地所有的viewResolver,找到合適的視圖解析器創建視圖
		if (this.viewResolvers != null) {
			for (ViewResolver viewResolver : this.viewResolvers) {
				View view = viewResolver.resolveViewName(viewName, locale);
				if (view != null) {
					return view;
				}
			}
		}
		return null;
	}

view.render()
View接口中:
void render(@Nullable Map<String, ?> model,HttpServletRequest request, HttpServletResponse response) throws Exception;
	
AbstractView類實現:
	public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
			HttpServletResponse response) throws Exception {

		if (logger.isTraceEnabled()) {
			logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
				" and static attributes " + this.staticAttributes);
		}

		Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
		prepareResponse(request, response);
		//view視圖渲染與輸出數據
		renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
	}


AbstractView類:
	protected abstract void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception;







視圖解析器     

視圖解析器
視圖解析器      說明
AbstractCachingViewResolver 一個抽象視圖,繼承該類可以讓視圖解析器具有緩存功能
XmlViewResolver 接受XML文件的視圖解析器,默認配置文件在 /WEB-INF/views.xml
ResourceBundleViewResolver 使用properties配置文件的視圖解析器,默認配置文件是類路徑下的views.properties
UrlBasedViewResolver 一個簡單的視圖解析器,不做任何匹配,需要視圖名和實際視圖文件名相同
InternalResourceViewResolver UrlBasedViewResolver的一個子類,支持Servlet容器的內部類型(JSP、Servlet、以及JSTL等),可以使用setViewClass(..)指定具體的視圖類型
FreeMarkerViewResolver 也是UrlBasedViewResolver的子類,用於FreeMarker視圖技術

ContentNegotiatingViewResolver

用於解析基於請求文件名或Accept header的視圖
BeanNameViewResolver 將邏輯視圖名解析爲一個 Bean,Bean 的 id 等於邏輯視圖名

視圖:

視圖
視圖

 說明

InternalResourceView 將 JSP 或其他資源封裝成一個視圖,一般 JSP 頁面用該視圖類
JstlView 繼承自InternalResourceView,如果 JSP 頁面使用了 JSTL 標籤,則需要使用該視圖類
AbstractPdfView PDF視圖的抽象超類
AbstractXlsView 傳統XLS格式的Excel文檔視圖的便捷超類,與Apache POI 3.5及更高版本兼容。
AbstractXlsxView Office 2007 XLSX格式的Excel文檔視圖的便捷超類,兼容Apache POI 3.5及更高版本。
MappingJackson2JsonView 將模型數據 通過 Jackson 開源框架的 ObjectMapper 以 JSON 方式輸出

我們看下InternalResourceViewResolver裏面的renderMergedOutputModel()方法:

InternalResourceView下面的renderMergedOutputModel(...)方法:
	
	protected void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		// Expose the model object as request attributes.
		//model裏面的鍵值對數據寫入到RequestScope中
		exposeModelAsRequestAttributes(model, request);

		//請求轉發,頁面跳轉
		
		// Expose helpers as request attributes, if any.
		exposeHelpers(request);

		// Determine the path for the request dispatcher.
		String dispatcherPath = prepareForRendering(request, response);

		// Obtain a RequestDispatcher for the target resource (typically a JSP).
		RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
		if (rd == null) {
			throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
					"]: Check that the corresponding file exists within your web application archive!");
		}

		// If already included or response already committed, perform include, else forward.
		if (useInclude(request, response)) {
			response.setContentType(getContentType());
			if (logger.isDebugEnabled()) {
				logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}
			rd.include(request, response);
		}

		else {
			// Note: The forwarded resource is supposed to determine the content type itself.
			if (logger.isDebugEnabled()) {
				logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}
			rd.forward(request, response);
		}
	}

	
	
	AbstractView類中:
	protected void exposeModelAsRequestAttributes(Map<String, Object> model,
			HttpServletRequest request) throws Exception {

		//數據寫進request裏面
		model.forEach((modelName, modelValue) -> {
			if (modelValue != null) {
				request.setAttribute(modelName, modelValue);
				if (logger.isDebugEnabled()) {
					logger.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() +
							"] to request in view with name '" + getBeanName() + "'");
				}
			}
			else {
				request.removeAttribute(modelName);
				if (logger.isDebugEnabled()) {
					logger.debug("Removed model object '" + modelName +
							"' from request in view with name '" + getBeanName() + "'");
				}
			}
		});
	}

以上就是視圖渲染,返回頁面等操作。


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章