【Spring】抽丝剥茧SpringMVC-视图解析及渲染ViewResolver&View

本文详细介绍了SpringMVC中的视图解析器和视图渲染机制,包括BeanNameViewResolver、XmlViewResolver、FreeMarkerViewResolver的工作原理,以及视图渲染过程中的模型合并和模板引擎应用。

本文源码基于SpringMVC 5.2.7    

视图渲染是SpringMVC框架的重要一环,基本也就是最后一环了。请求经过前面一系列的处理最终是返回ModelAndView对象给到视图渲染模块。视图渲染模块则将其转换为前端可识别的html文本并写入response。并不是所有请求最终都会走到视图渲染模块,如果请求在前面的处理中已经将数据写到response,其实就没有必要经过视图渲染模块处理。这时只需要返回的恶ModelAndView是空对象(null),DispatcherServlet就不会走视图渲染逻辑。例如,注解@Responsebody的方法就不会走视图渲染逻辑,这种方法在返回处理器中就已经将数据写到response中了。

   视图渲染模块包括两个部分:视图解析器和视图渲染。视图解析器用来将视图name转换为视图对象(org.springframework.web.servlet.View),很多请求处理完后返回的并使视图对象,而是字符串(代表视图name),所以首先需要将视图name转换为视图对象。视图渲染则是调用视图对象的render方法(View#render)。

视图解析器(ViewResolver)

视图解析器都是实现了接口ViewResolver,接口ViewResolver只定义了接口方法resolveViewName。

public interface ViewResolver {

	View resolveViewName(String viewName, Locale locale) throws Exception;

}

DispatcherServlet装配ViewResolver

跟HandlerMapping、HandlerAdapter这些组件一样,ViewResolver也是在系统初始化的时候装配到DispatcherServlet

  1. 如果"detectAllViewResolvers"打开,则从IOC容器中获取所有类型为ViewResolver的实例;否则进入2
  2. 从IOC容器中获取name为"viewResolver"的实例;
  3. 如果步骤1、2之后已经有viewResolver则装配过程结束,否则进入4;
  4. 通过DispatcherServlet默认装配策略中创建viewResolver实例,并装配给DispatcherServlet,装配过程结束。

默认情况“detectAllViewResolvers”是打开的,也就是说默认情况是从IOC容器中找到所有ViewResolver的Bean。

DispatcherServlet默认装配策略在《抽丝剥茧MVC之RequestMappingHandlerMapping》中有介绍,这里就不赘述。默认策略装配的视图处理器有1个

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

DispatcherServlet视图解析处理

DispatcherServlet初始化的视图解析可能有多个,在其解析视图的时候依次调用视图解析器的解析流程(ViewResolver#resolveViewName),如果返回的视图对象非空(null),则终止解析。

public class DispatcherServlet extends FrameworkServlet {
... ...    
   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;
	}
... ...
}

常见的视图解析器

BeanNameViewResolver

BeanNameViewResolver是将视图name当作Bean name判断Spring IOC容器是否包含对应name的Bean,且Bean对象是View类型则认为解析出视图对象。

    
public class BeanNameViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered {
... ...
    public View resolveViewName(String viewName, Locale locale) throws BeansException {
		ApplicationContext context = obtainApplicationContext();
        //笔者注:判断容器中是否有viewName对应的Bean
		if (!context.containsBean(viewName)) {
			return null;
		}
        //笔者注:判断viewName对应的Bean对象是否View类型
		if (!context.isTypeMatch(viewName, View.class)) {
			if (logger.isDebugEnabled()) {
				logger.debug("Found bean named '" + viewName + "' but it does not implement View");
			}
			return null;
		}
		return context.getBean(viewName, View.class);
	}
... ...

XmlViewResolver

XmlViewResolver主要用来从指定xml中加载View的Bean定义,再从中找到视图name对应的视图对象。所以XmlViewResolver先根据指定xml创建BeanFactory(默认的xml是"/WEB-INF/views.xml")然后从BeanFacotry中找到视图name对应的Bean对象。

public class XmlViewResolver extends AbstractCachingViewResolver
		implements Ordered, InitializingBean, DisposableBean {
... ...

    @Override
	protected View loadView(String viewName, Locale locale) throws BeansException {
		//笔者注:初始化BeanFactory
        BeanFactory factory = initFactory();
		try {
            //笔者注:从BeanFactory找到对应Bean对象
			return factory.getBean(viewName, View.class);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Allow for ViewResolv
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值