SpringMVC之JSP界面渲染

接上一篇文章 说明了url和具体controller方法的缓存和处理请求时的执行逻辑,这里我们跟一下执行完成后页面渲染的逻辑,代码接着上一篇(调用栈):

org.springframework.web.servlet.DispatcherServlet#doDispatch
|
org.springframework.web.servlet.DispatcherServlet#processDispatchResult
|
org.springframework.web.servlet.DispatcherServlet#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;
		String viewName = mv.getViewName();
//@A
		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());
			}
//@B
			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;
		}
	}
  • @A:获得一个view,这个view就是我们在mvc配置文件里配置的 viewResolver 解析来的view,是一个 InternalResourceView 对象
  • @B:调用view的render方法,实则会执行 org.springframework.web.servlet.view.AbstractView#render方法,然后调用子类的方法
    org.springframework.web.servlet.view.InternalResourceView#renderMergedOutputModel
@Override
	protected void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
    
    

//@C
		// Expose the model object as request attributes.
		exposeModelAsRequestAttributes(model, request);

		// Expose helpers as request attributes, if any.
		exposeHelpers(request);

		// Determine the path for the request dispatcher.
		String dispatcherPath = prepareForRendering(request, response);
//@D
		// 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() + "'");
			}
//@E
			rd.forward(request, response);
		}
	}
  • @C:调用 request.setAttribute(modelName, modelValue);方法将model里的存放的key,value值全部放到request中
  • @D:通过jsp路径获得RequestDispatcher 对象
  • @E:调用RequestDispatcher的forward转向到对应的输出(这个是不是很熟悉)

猜你喜欢

转载自blog.csdn.net/Aqu415/article/details/116198097