当前位置:   article > 正文

SpringMVC源码学习(七)---解析ModelAndView_null modelandview returned to dispatcherservlet wi

null modelandview returned to dispatcherservlet with name 'dispatcherservlet

一. RequestMappingHandlerAdapter类invokeHandlerMethod()方法

在RequestMappingHandlerAdapter#invokeHandlerMethod()方法中

  1. 执行处理器方法(HandlerMethod)
  2. 封装并返回ModelAndView实例

在这里插入图片描述

	@Nullable
	protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
		//将Request和Response进行封装
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
			//WebDataBinderFactory --> 工厂类,为目标对象创建一个WebDataBinder实例
			// 1.WebDataBinder继承了DataBinder类,为web请求提供了参数绑定服务
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
			// 获取ModelFactory:
			// 2.ModelFactory可以协助控制器在调用方法之前初始化模型,并在调用之后更新模型
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
			//  创建InvocableHandlerMethod实例,以及各个组件的配置;
			//  后面通过调用invokeAndHandle()方法执行处理器
			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			// 4.尝试绑定参数、返回值解析器
			if (this.argumentResolvers != null) {
				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			}
			if (this.returnValueHandlers != null) {
				invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			}
			invocableMethod.setDataBinderFactory(binderFactory);
			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
			// 创建视图容器, 用于封装视图, 数据模型, 处理状态等信息
			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
			modelFactory.initModel(webRequest, mavContainer, invocableMethod);
			mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
			// 6.异步请求相关
			AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
			asyncWebRequest.setTimeout(this.asyncRequestTimeout);
			WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
			asyncManager.setTaskExecutor(this.taskExecutor);
			asyncManager.setAsyncWebRequest(asyncWebRequest);
			asyncManager.registerCallableInterceptors(this.callableInterceptors);
			asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
			if (asyncManager.hasConcurrentResult()) {
				Object result = asyncManager.getConcurrentResult();
				mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
				asyncManager.clearConcurrentResult();
				if (logger.isDebugEnabled()) {
					logger.debug("Found concurrent result value [" + result + "]");
				}
				invocableMethod = invocableMethod.wrapConcurrentResult(result);
			}
			// 7.调用Controller中的具体方法并处理返回值 执行处理器
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
				return null;
			}
			// 8.返回ModelAndView对象
			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			// 完成请求后续处理,并将当前请求置为未激活
			webRequest.requestCompleted();
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

二. invokeAndHandle() 方法

在这里插入图片描述

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		// 1.调用Controller中的具体方法
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
		// 2.设置返回状态码
		setResponseStatus(webRequest);
		// 3.当前请求无返回值或者返回值中包含错误,则将请求完成标识设置为true并返回
		if (returnValue == null) {
			if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
				mavContainer.setRequestHandled(true);
				return;
			}
		}
		else if (StringUtils.hasText(getResponseStatusReason())) {
			mavContainer.setRequestHandled(true);
			return;
		}
		// 4.当前请求有返回值且无错误信息,则将请求完成标识设置为false,并继续处理当前请求
		mavContainer.setRequestHandled(false);
		Assert.state(this.returnValueHandlers != null, "No return value handlers");
		try {
			// 选取合适的HandlerMethodReturnValueHandler,并处理返回值
			this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		}
		catch (Exception ex) {
			if (logger.isTraceEnabled()) {
				logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
			}
			throw ex;
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

三. handleReturnValue()方法

在这里插入图片描述

	@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
		//根据返回值以及返回类型选择合适的返回值处理器, 对返回值进行解析
		HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
		if (handler == null) {
			throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
		}
		//解析结果
		handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

四. ModelAndViewMethodReturnValueHandler类中的handleReturnValue() 方法

在这里插入图片描述

在这里插入图片描述

	@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
		// 当前请求返回值为null,无需处理,并且要将当前请求标记已处理
		if (returnValue == null) {
			mavContainer.setRequestHandled(true);
			return;
		}
		// 处理引用视图
		ModelAndView mav = (ModelAndView) returnValue;
		if (mav.isReference()) {
			String viewName = mav.getViewName();
			mavContainer.setViewName(viewName);
			if (viewName != null && isRedirectViewName(viewName)) {
				mavContainer.setRedirectModelScenario(true);
			}
		}
		// 处理普通视图(即我们已经制定了具体的View视图,而无需通过视图解析器再次解析)
		else {
			View view = mav.getView();
			mavContainer.setView(view);
			if (view instanceof SmartView && ((SmartView) view).isRedirectView()) {
				mavContainer.setRedirectModelScenario(true);
			}
		}
		// 设置返回状态
		mavContainer.setStatus(mav.getStatus());
		//设置数据Model
		mavContainer.addAllAttributes(mav.getModel());
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

五. RequestMappingHandlerAdapter类中的getModelAndView()方法

从ModelAndViewContainer容器中获取ModeAndView实例

在这里插入图片描述

	@Nullable
	private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
			ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
		// 1.更新模型
		modelFactory.updateModel(webRequest, mavContainer);
		if (mavContainer.isRequestHandled()) {
			return null;
		}
		// 2.获取ModelMap并创建ModelAndView
		ModelMap model = mavContainer.getModel();
		ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
		// 3.处理引用类型视图和转发类型视图
		if (!mavContainer.isViewReference()) {
			mav.setView((View) mavContainer.getView());
		}
		if (model instanceof RedirectAttributes) {
			Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
			if (request != null) {
				RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
			}
		}
		return mav;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

六. DispatcherServlet类中的processDispatchResult()方法

解析ModelAndView

在这里插入图片描述

	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);
			}
		}
		// 尝试解析视图和模型;
		// wasCleared:判断当前模型和视图是否已经被标识为清空,且当前视图和模型是否同时为空
		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()) {
			return;
		}
		// 处理注册的后置完成拦截器
		if (mappedHandler != null) {
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

processDispatchResult() 方法

  1. 如果出现异常,则解析异常视图
  2. 解析ModelAndView

七. DispatcherServlet类中的processHandlerException()方法

在这里插入图片描述

	@Nullable
	protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
			@Nullable Object handler, Exception ex) throws Exception {
		ModelAndView exMv = null;
		if (this.handlerExceptionResolvers != null) {
			//遍历所有的异常解析器, 尝试对异常进行解析, 如果解析成功,跳出循焕
			for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
				exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
				if (exMv != null) {
					break;
				}
			}
		}
		if (exMv != null) {
			if (exMv.isEmpty()) {
				request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
				return null;
			}
			//对于简单的错误模型,我们可能仍需要视图名称转换
			if (!exMv.hasView()) {
				String defaultViewName = getDefaultViewName(request);
				if (defaultViewName != null) {
					exMv.setViewName(defaultViewName);
				}
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
			}
			//设置错误请求的相关属性
			WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
			return exMv;
		}
		throw ex;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

八. DispatcherServlet类中的render()方法

在这里插入图片描述

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 确定请求的区域设置并将其应用于响应。
		Locale locale =
				(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
		response.setLocale(locale);

		View view;
		// 获取视图名
		String viewName = mv.getViewName();
		if (viewName != null) {
			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() + "'");
			}
		}
		// 获取到视图名,再次判断当前ModelAndView对象中是否包含真正的View对象,
		// 因为接下来需要调用View对象的render方法
		else {
			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对象的render方法完成视图解析
			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;
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

ModelAndView视图解析可以分为两个重要步骤:

  1. 根据视图名称创建View实例
  2. 根据View实例渲染视图

九. ViewResolver和View接口

在这里插入图片描述

public interface ViewResolver {

	// 通过逻辑视图名和用户地区信息生成View对象
	@Nullable
	View resolveViewName(String viewName, Locale locale) throws Exception;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

public interface View {

	String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";

	String PATH_VARIABLES = View.class.getName() + ".pathVariables";

	String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType";

	//获取返回值的contentType
	@Nullable
	default String getContentType() {
		return null;
	}


	//通过用户提供的模型数据与视图信息渲染视图
	void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
			throws Exception;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

十. DispatcherServlet类中的resolveViewName()方法

	//根据视图名称创建View实例
	@Nullable
	protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
			Locale locale, HttpServletRequest request) throws Exception {

		if (this.viewResolvers != null) {
			for (ViewResolver viewResolver : this.viewResolvers) {
				//这里的视图解析器就是我们在配置文件中配置的那个
				View view = viewResolver.resolveViewName(viewName, locale);
				if (view != null) {
					return view;
				}
			}
		}
		return null;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在这里插入图片描述

十一. AbstractCachingViewResolver类中的resolveViewName()方法

在这里插入图片描述

在这里插入图片描述

public View resolveViewName(String viewName, Locale locale) throws Exception {
		//判断缓存是否可用
		if (!isCache()) {
			//如果缓存不可用, 则直接创建视图
			return createView(viewName, locale);
		}
		else {
			//如果缓存可用, 则先尝试从缓存中获取
			//生成缓存Key
			Object cacheKey = getCacheKey(viewName, locale);
			//尝试从缓存中获取视图
			View view = this.viewAccessCache.get(cacheKey);
			if (view == null) {
				//如果从缓存中获取视图失败, 则尝试从viewCreationCache缓存中获取
				synchronized (this.viewCreationCache) {
					//让子类创建View对象, 留给子类扩展[扩展开放,修改关闭原则]
					view = this.viewCreationCache.get(cacheKey);
					if (view == null) {
						// 这里cacheUnresolved指的是是否缓存默认的空视图,UNRESOLVED_VIEW是
						// 一个没有任何内容的View
						view = createView(viewName, locale);
						if (view == null && this.cacheUnresolved) {
							view = UNRESOLVED_VIEW;
						}
						if (view != null) {
							//将创建的view视图加入缓存
							this.viewAccessCache.put(cacheKey, view);
							this.viewCreationCache.put(cacheKey, view);
							if (logger.isTraceEnabled()) {
								logger.trace("Cached view [" + cacheKey + "]");
							}
						}
					}
				}
			}
			return (view != UNRESOLVED_VIEW ? view : null);
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

十二. UrlBasedViewResolver类中的createView()方法

在这里插入图片描述

	@Override
	protected View createView(String viewName, Locale locale) throws Exception {
		if (!canHandle(viewName, locale)) {
			return null;
		}
		 // 检查特殊的"redirect:"前缀 REDIRECT_URL_PREFIX = "redirect:"
		 // 如果是以"redirect:" 开头, 说明该视图是重定向
		if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
			String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
			RedirectView view = new RedirectView(redirectUrl,
					isRedirectContextRelative(), isRedirectHttp10Compatible());
			String[] hosts = getRedirectHosts();
			if (hosts != null) {
				view.setHosts(hosts);
			}
			return applyLifecycleMethods(REDIRECT_URL_PREFIX, view);
		}
		// 检查特殊的"forward:"前缀 FORWARD_URL_PREFIX = "forward:"
		// 如果是以"forward:" 开头, 说明该视图是请求转发
		if (viewName.startsWith(FORWARD_URL_PREFIX)) {
			String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
			return new InternalResourceView(forwardUrl);
		}
		//如果是普通视图, 创建该视图视图
		return super.createView(viewName, locale);
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

十三. UrlBasedViewResolver类中的loadView()方法

在这里插入图片描述
在这里插入图片描述

	@Override
	protected View loadView(String viewName, Locale locale) throws Exception {
		// 使用逻辑视图名按照指定规则生成View对象
		AbstractUrlBasedView view = buildView(viewName);
		// 应用声明周期函数,也就是调用View对象的初始化函数和Spring用于切入bean创建的
		View result = applyLifecycleMethods(viewName, view);
		// 检查view的准确性,这里默认始终返回true
		return (view.checkResource(locale) ? result : null);
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

十四. UrlBasedViewResolver类中的buildView()方法

在这里插入图片描述

	protected AbstractUrlBasedView buildView(String viewName) throws Exception {
		//对于InternalResourceViewResolver而言,其返回的View对象的具体类型是InternalResourceView
		Class<?> viewClass = getViewClass();
		Assert.state(viewClass != null, "No view class");
		// 使用反射生成InternalResourceView对象实例
		AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(viewClass);
		//根据前缀和后缀拼接视图路径信息
		view.setUrl(getPrefix() + viewName + getSuffix());
		// 设置View的contentType属性
		String contentType = getContentType();
		if (contentType != null) {
			view.setContentType(contentType);
		}
		// 设置contextAttribute和attributeMap等属性
		view.setRequestContextAttribute(getRequestContextAttribute());
		view.setAttributesMap(getAttributesMap());
		// pathVariables表示request请求url中的属性,这里主要是设置是否将这些属性暴露到视图中
		Boolean exposePathVariables = getExposePathVariables();
		if (exposePathVariables != null) {
			view.setExposePathVariables(exposePathVariables);
		}
		// 这里设置的是是否将Spring的bean暴露在视图中,以供给前端调用
		Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes();
		if (exposeContextBeansAsAttributes != null) {
			view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes);
		}
		// 设置需要暴露给前端页面的bean名称
		String[] exposedContextBeanNames = getExposedContextBeanNames();
		if (exposedContextBeanNames != null) {
			view.setExposedContextBeanNames(exposedContextBeanNames);
		}
		return view;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

十五. UrlBasedViewResolver类中的applyLifecycleMethods()方法

在这里插入图片描述

十六. AbstractView类中的render()方法

	protected View applyLifecycleMethods(String viewName, AbstractUrlBasedView view) {
		ApplicationContext context = getApplicationContext();
		if (context != null) {
			// 对生成的View对象应用初始化方法,主要包括InitializingBean.afterProperties()和一些
			// Processor,Aware方法
			Object initialized = context.getAutowireCapableBeanFactory().initializeBean(view, viewName);
			if (initialized instanceof View) {
				return (View) initialized;
			}
		}
		return view;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述

	@Override
	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对象,以供给后面对视图的渲染使用
		Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
		// 判断当前View对象的类型是否为文件下载类型,如果是文件下载类型,则设置response的
		prepareResponse(request, response);
		// 开始view视图渲染以及数据输出整理 
		renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

十七. InternalResourceView类中的renderMergedOutputModel()方法

在这里插入图片描述

在这里插入图片描述

	@Override
	protected void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 将Model中的键值对数据全部写进RequestScope中
		exposeModelAsRequestAttributes(model, request);
		// 提供的一个hook方法,默认是空实现,用于用户进行request属性的自定义使用
		exposeHelpers(request);
		//确定请求分配器的路径
		String dispatcherPath = prepareForRendering(request, response);
		// 获取可应用于 forward/include 的RequestDispatcher
		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!");
		}
		// 判断当前是否为include请求,如果是,则调用RequestDispatcher.include()方法进行文件引入
		if (useInclude(request, response)) {
			response.setContentType(getContentType());
			if (logger.isDebugEnabled()) {
				logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}
			rd.include(request, response);
		}
		// 请求转发
		//使用forward跳转则后面的response输出则不会执行,而用include来跳转,
		//则include的servlet执行完后,再返回到原来的servlet执行response的输出(如果有)
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}
			//如果当前不是include()请求,则直接使用forward请求将当前请求转发到目标文件路径中,从而渲染该视图
			rd.forward(request, response);
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

视图解析分析完成

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/66265
推荐阅读
相关标签
  

闽ICP备14008679号