22_2 Spring MVC - ViewResolver系列 - UrlBasedViewResolver

22_2 Spring MVC - ViewResolver系列 - UrlBasedViewResolver

一、简介

UrlBasedViewResolver是对ViewResolver的一种简单实现,而且继承了AbstractCachingViewResolver,主要提供一种拼接URL的方式来解析视图,它可以通过prefix属性指定一个前缀,通过suffix属性指定一个后缀,然后把返回的逻辑视图名称加上指定的前缀和后缀就是视图的URL了。如prefix=/WEB-INF/jsps/,suffix=.jsp,返回的视图名称viewName=test/indx,则UrlBasedViewResolver解析出来的视图URL就是/WEB-INF/jsps/test/index.jsp。默认的prefix和suffix都是空串。

1.1 支持 redirect

UrlBasedViewResolver支持返回的视图名称中包含redirect:前缀,这样就可以支持URL在客户端的跳转,如当返回的视图名称是"redirect:test.do"的时候,UrlBasedViewResolver发现返回的视图名称包含redirect:前缀,于是把返回的视图名称前缀redirect:去掉,取后面的test.do组成一个RedirectView。RedirectView中将把请求返回的模型属性组合称查询参数的形式组合到redirect的URL后面,然后调用HttpServletResponse对象的sendRedirect方法进行重定向。

1.2 支持 forword

UrlBasedViewResolver还支持forword:前缀,对于视图名称中包含forword:前缀的视图名称将会被封装称一个InternalResourceView对象,然后在服务器端利用RequestDispatcher的forword:方式跳转到指定的地址。使用UrlBasedViewResolver的时候必须指定属性viewClass,表示解析成哪种视图,一般使用较多的就是InternalResourceView,利用它来展现jsp。

二、源码解析

2.1 createView(String viewName, Locale locale)

createView是创建View的方法,UrlBasedViewResolver类重写了该方法,用来提供对 redirect:forword: 形式的支持。

	@Override
	protected View createView(String viewName, Locale locale) throws Exception {
		// 先判断 是否支持 该视图名的处理
		if (!canHandle(viewName, locale)) {
			return null;
		}

		// 如果是以redirect: 开头,返回RedirectView
		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);
		}

		// 如果是以forword:开头,返回InternalResourceView
		if (viewName.startsWith(FORWARD_URL_PREFIX)) {
			String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
			return new InternalResourceView(forwardUrl);
		}

		// 其他情况 调用父类的 createView方法
		return super.createView(viewName, locale);
	}
  • 先判断 UrlBasedViewResolver 解析器是否支持当前视图名的解析
  • 判断 视图名称是否 以redirect:开头,如果是则构建返回RedirectView
  • 判断 视图名称是否 以forword:开头,如果是则返回一个InternalResourceView
  • 都不是的情况下调用父类的 createView方法

2.2 loadView(String viewName, Locale locale)

在AbstractCachingViewResolver类中 createView方法最后是通过调用 protected abstract View ``loadView``(``String viewName``, ``Locale locale``) ``throws Exception 方法创建。这个方法是一个抽象方法,具体的实现是通过子类来实现的。

	@Override
	protected View loadView(String viewName, Locale locale) throws Exception {
		AbstractUrlBasedView view = buildView(viewName);
		View result = applyLifecycleMethods(viewName, view);
		return (view.checkResource(locale) ? result : null);
	}


  • 通过 buildView方法创建一个 AbstractUrlBasedView 对象
  • 通过 applyLifecycleMethods 方法将创建的 View对象交给 Spring容器管理

2.3 buildView(viewName)

	protected AbstractUrlBasedView buildView(String viewName) throws Exception {
		Class<?> viewClass = getViewClass();
		Assert.state(viewClass != null, "No view class");

		AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(viewClass);
		view.setUrl(getPrefix() + viewName + getSuffix());

		String contentType = getContentType();
		if (contentType != null) {
			view.setContentType(contentType);
		}

		view.setRequestContextAttribute(getRequestContextAttribute());
		view.setAttributesMap(getAttributesMap());

		Boolean exposePathVariables = getExposePathVariables();
		if (exposePathVariables != null) {
			view.setExposePathVariables(exposePathVariables);
		}
		Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes();
		if (exposeContextBeansAsAttributes != null) {
			view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes);
		}
		String[] exposedContextBeanNames = getExposedContextBeanNames();
		if (exposedContextBeanNames != null) {
			view.setExposedContextBeanNames(exposedContextBeanNames);
		}

		return view;
	}
posted @ 2020-09-13 15:37  在线打工者  阅读(218)  评论(0编辑  收藏  举报