本文源码基于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
- 如果"detectAllViewResolvers"打开,则从IOC容器中获取所有类型为ViewResolver的实例;否则进入2
- 从IOC容器中获取name为"viewResolver"的实例;
- 如果步骤1、2之后已经有viewResolver则装配过程结束,否则进入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

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

被折叠的 条评论
为什么被折叠?



