SpringMVC那些事-视图渲染


上一个阶段返回了ModelAndView(这里假设返回了MAV,我们讨论的是有视图渲染的情况),接下来就是视图渲染阶段了.
MAV包含了可以确定视图的信息,和需要渲染的数据,也就是model.

视图渲染阶段包括两个子阶段
1.使用视图解析器ViewResolver生成实例View
2.View.render渲染视图

1.视图View生成的过程

遍历ViewResolver,和hm一样的策略,生成具体的View,注意ViewResolver使用Order接口,也就是根据这个决定优先级.
最终生成的view表示具体的不同视图,例如JstlVIew, PDFView等.
->dispatcherservlet.processDispatchResult//处理返回的视图模型,
->dispatcherservlet.render
->dispatcherservlet.resolveViewName//
->dispatcherservlet.resolveViewName
->AbstractCachingViewResolver.resolveViewName
->AbstractCachingViewResolver.createView
->UrlBasedViewResolver.loadView
->UrlBasedViewResolver.buildView//生成view实例
->UrlBasedViewResolver.applyLifecycleMethods


2.视图view渲染过程(以JstlView举例)
直接使用视图的render方法渲染视图.这个过程会包括把国际化资源文件和request绑定,把model的数据放到
request attribute中等.最终使用的是RequestDispatcher完成视图的渲染处理.
->JstlView.render//调用具体的视图类渲染视图
->AbstractView.render
->AbstractView.createMergedOutputModel
->AbstractView.prepareResponse
->InternalResourceView.renderMergedOutputModel
->AbstractView.exposeModelAsRequestAttributes//把model放入request attributes, 这样才能使用jstl标签解析数据
->InternalResourceView.exposeHelpers//Exposes a JSTL LocalizationContext for Spring's locale and MessageSource
->InternalResourceView.getRequestDispatcher//获取RequestDispatcher,原生servlet+jsp 开发的常用, 看上去很高大上的东东,其实底层的东西都是这些,所有打好基础!
->RequestDispatcher.include/RequestDispatcher.forward//渲染或者跳转

插播一些简单知识:
RequestDispatcher.include给客户端返回视图
RequestDispatcher.forward服务器端跳转(浏览器url还是当前url)
response.sendRedirect客户端跳转(浏览器重新发送请求的地址)

相关类

View 视图抽象接口,所有视图的最高抽象

InternalResourceView

JstlView JSTL视图
  MessageSource//locale and resource bundle for JSTL's formatting and message tags国际化
 
ModelAndView 视图和模型
  Object view
  ModelMap defaultModel
  ModelMap redirectModel

ResourceBundleMessageSource  国际资源绑定文件(在配置文件中配置,以后详细介绍))
  String defaultEncoding
  ClassLoader bundleClassLoader
  ClassLoader beanClassLoader

ViewResolver  视图解析器接口

AbstractCachingViewResolver 具有缓存功能吃视图解析器抽象类
  Map<Object, View> viewAccessCache//缓存访问过的视图
  Map<Object, View> viewCreationCache//缓存生成过的视图

InternalResourceViewResolver 使用RequestDispatcher返回jsp等web内部资源文件


部分源码

DispatcherServlet


/**
	 * Handle the result of handler selection and handler invocation, which is
	 * either a ModelAndView or an Exception to be resolved to a ModelAndView.
	 */
	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {

		boolean errorView = false;
		
		//把异常转换成视图处理,还是需要提醒的是,我们可以在自定义拦截异常的时候,返回json这样格式的错误信息
		//一般在统一异常处理的时候需要这么多.
		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?(判断处理器返回的是不是需要渲染的视图,假如使用@RequestBody就不需要渲染视图了)
		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 the given ModelAndView.
	 * <p>This is the last stage in handling a request. It may involve resolving the view by name.
	 * @param mv the ModelAndView to render
	 * @param request current HTTP servlet request
	 * @param response current HTTP servlet response
	 * @throws ServletException if view is missing or cannot be resolved
	 * @throws Exception if there's a problem rendering the view
	 */
	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.resolveLocale(request);
		response.setLocale(locale);

		View view;
		//判断是否需要解析视图(可以在处理器返回字符串和ModelAndView)
		if (mv.isReference()) {
			// We need to resolve the view name.
			//获取视图
			view = resolveViewName(mv.getViewName(), 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.
			//ModelAndView中已经存在了视图,(例如我们在处理器返回AbstractpdfView视图的时候,就已经指定好了视图了)
			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 {//渲染视图,从mv中取出model
			view.render(mv.getModelInternal(), request, response);
		}
		catch (Exception ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
						getServletName() + "'"
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值