第一节我们看到了ViewResolver对ModelAndView中属性Oject view为String时,将调用方法:
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
HttpServletRequest request) throws Exception {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
return null;
}
所以这一节就来了解下resolveViewName的机制。
来看看我们第一眼能懂的,Internal产生的是JstlView,Freemarker不用说,Velocity不用说,那就从这三个类来入手。
还是过程式的代码阅读,我们去找resovlveViewName
这个方法。
在AbstractCachingViewResolver类中:
public View resolveViewName(String viewName, Locale locale) throws Exception {
if (!isCache()) {
return createView(viewName, locale);
}
else {
Object cacheKey = getCacheKey(viewName, locale);
synchronized (this.viewCache) {
View view = this.viewCache.get(cacheKey);
if (view == null) {
// Ask the subclass to create the View object.
view = createView(viewName, locale);
this.viewCache.put(cacheKey, view);
if (logger.isTraceEnabled()) {
logger.trace("Cached view [" + cacheKey + "]");
}
}
return view;
}
}
}
protected View createView(String viewName, Locale locale) throws Exception {
return loadView(viewName, locale);
}
protected abstract View loadView(String viewName, Locale locale) throws Exception;//子类必须实现这个方法
loadView方法又将我们带入了AbstractCachingViewResolver的子类UrlBasedViewResolver类中,可以发现UrlBasedViewResolver类中:
/**
* Overridden to implement check for "redirect:" prefix.
* <p>Not possible in <code>loadView</code>, since overridden
* <code>loadView</code> versions in subclasses might rely on the
* superclass always creating instances of the required view class.
* @see #loadView
* @see #requiredViewClass
*/
@Override
protected View createView(String viewName, Locale locale) throws Exception {
// If this resolver is not supposed to handle the given view,
// return null to pass on to the next resolver in the chain.
if (!canHandle(viewName, locale)) {
return null;
}
// Check for special "redirect:" prefix.
if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
return new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
}
// Check for special "forward:" prefix.
if (viewName.startsWith(FORWARD_URL_PREFIX)) {
String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
return new InternalResourceView(forwardUrl);
}
// Else fall back to superclass implementation: calling loadView.
return super.createView(viewName, locale);
}
这里千万别糊涂哦,这可是java基础知识多态哦。。。。
因为在DispatcherServlet中的viewResolvers保存的都是ViewResolver的实现类的对象,那么调用接口的resolveViewName方法后,就得一层层来看这个方法了,从代码中我们看到的是只有AbstractCachingViewResolver有这个方法,那肯定调用的是它的。但是在resolveViewName中又调用了createView,那么这里调用的就是UrlBasedViewResolver的方法了。
所以在该方法前面的if都没得到满足时,才去显示的调用父类的createView方法。
// Else fall back to superclass implementation: calling loadView.
return super.createView(viewName, locale);
这时父类的createView调用了loadView方法,而UrlBasedViewResolver又实现了这一方法,自然而然是调用它的loadView方法,而Internal暴露了buildView方法,则loadView执行时首先调用Internal的buildView。
@Override
protected View loadView(String viewName, Locale locale) throws Exception {
AbstractUrlBasedView view = buildView(viewName);
View result = (View) getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, viewName);
return (view.checkResource(locale) ? result : null);
}
UrlBasedViewResolver类中的buildView方法
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass());
view.setUrl(getPrefix() + viewName + getSuffix());
String contentType = getContentType();
if (contentType != null) {
view.setContentType(contentType);
}
view.setRequestContextAttribute(getRequestContextAttribute());
view.setAttributesMap(getAttributesMap());
return view;
}
InternalResourceViewResolver的buildView方法,忽然看到这个viewClass让我眼前一亮,终于知道Freemarker去生成静态页面是怎么做到的了,用自己实现的类配置在Resolver的属性中,这样等于是做了一次拦截。
<bean id="freemarkerViewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="contentType" value="text/html;charset=gbk" />
<property name="viewClass" value="com.sha0k.util.MyFreeMarkerView">
</property>
<property name="exposeRequestAttributes">
<value>true</value>
</property>
<property name="exposeSessionAttributes">
<value>true</value>
</property>
<property name="order">
<value>1</value>
</property>
<property name="suffix" value=".ftl" />
</bean>
@Override
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
InternalResourceView view = (InternalResourceView) super.buildView(viewName);
if (this.alwaysInclude != null) {
view.setAlwaysInclude(this.alwaysInclude);
}
if (this.exposeContextBeansAsAttributes != null) {
view.setExposeContextBeansAsAttributes(this.exposeContextBeansAsAttributes);
}
if (this.exposedContextBeanNames != null) {
view.setExposedContextBeanNames(this.exposedContextBeanNames);
}
view.setPreventDispatchLoop(true);
return view;
}
分享到:
相关推荐
在Spring MVC框架中,View和ViewResolver是两个关键的概念,它们负责将处理后的模型数据转换为用户可感知的视图,比如HTML页面。本文将深入解读这两个组件的工作原理及其重要性。 **一、View(视图)** 视图是...
【Spring5MVC源码分析】 Spring MVC 是一个基于Java的、用于构建Web应用程序的、高度可插拔的MVC框架,它是Spring Framework的重要组成部分。Spring MVC的核心目标是简化前端控制器的开发,使得开发者可以专注于...
在本源码分析中,我们将探讨Spring MVC的工作原理、主要组件及其交互方式。 1. **DispatcherServlet**: 作为Spring MVC的前端控制器,DispatcherServlet是所有请求的入口点。它负责拦截请求,根据请求信息(如URL、...
- Spring MVC是基于Model-View-Controller(MVC)设计模式的Web应用框架,提供了一种组织和处理请求的机制。 - 它的核心组件包括DispatcherServlet、HandlerMapping、HandlerAdapter、ModelAndView和ViewResolver...
首先,Spring MVC的核心设计理念是模型-视图-控制器(Model-View-Controller)架构模式。在该模式中,模型负责业务逻辑处理,视图负责展示数据,而控制器则作为模型和视图之间的桥梁,接收用户请求并调用相应的服务...
在Spring MVC中,Model代表业务对象,View负责展示,Controller处理用户请求并协调Model和View。 2. **DispatcherServlet**:Spring MVC的入口点,它是一个前端控制器,接收所有HTTP请求,并根据配置的...
Spring MVC 是一个基于Java的轻量级Web应用框架,它为开发者提供了模型-视图-控制器(MVC)架构,使开发人员能够更好地组织和分离应用程序的业务逻辑、数据处理和用户界面。Spring MVC是Spring框架的一个核心组件,...
### Spring MVC 学习指南详解 #### 一、Spring MVC 概述 Spring MVC 是 Spring 框架的一部分,主要用于构建基于 Model-View-Controller (MVC) 设计模式的 Web 应用程序。它提供了丰富的功能来简化 Web 开发过程,...
通过深入学习Spring MVC的源码,开发者不仅可以更好地理解其内部机制,还能优化自己的代码,提升应用程序的性能和可维护性。这本扫描版书籍的源码分析部分,无疑会帮助读者在实践中应用这些知识,解决实际问题。
通过深入学习这个 Spring MVC 项目源码,你可以掌握 MVC 设计模式的运用,了解 Spring 框架的组件协同工作方式,以及在实际项目中的最佳实践。这将有助于提升你的 Java Web 开发技能,更好地理解和使用 Spring MVC。
Spring MVC 是一个广泛使用的 Java Web 开发框架,它实现了MVC(Model-View-Controller)设计模式,使得开发者可以更高效地构建可维护且松耦合的Web应用程序。在这个学习记录总结中,我们将深入理解Spring MVC的核心...
Spring MVC 是一款强大的Java Web开发框架,用于构建高效、可维护和模块化的Web应用程序。它作为Spring框架的一...通过学习这个教程,你可以提高你的Web开发技能,更好地利用Spring MVC来构建高质量的Java Web应用。
DispatcherServlet 是 Spring MVC 框架的核心组件,它负责转发每一个 Request 请求给相应的 Handler,Handler 处理以后再返回相应的视图(View)和模型(Model)。DispatcherServlet 是继承自 HttpServlet 的,既然 ...
这个源码实例应该是为了帮助开发者深入理解Spring MVC的工作原理和实现机制。下面,我们将详细探讨Spring MVC的关键知识点。 1. **DispatcherServlet**: 作为Spring MVC的核心组件,DispatcherServlet负责接收HTTP...
二、Spring MVC核心类与接口:Spring MVC架构中包含许多核心组件,如DispatcherServlet、HandlerMapping、Controller、ViewResolver等。这些组件协同工作,处理用户的请求并返回相应的响应。 三、Spring MVC核心...
- 视图(View):负责渲染模型数据,Spring MVC支持多种视图技术如JSP、FreeMarker、Thymeleaf等。 5. **数据绑定与验证**: - 数据绑定:Spring MVC可以自动将请求参数绑定到Controller方法的参数上。 - 数据...
这份“Spring.MVC学习指南.pdf”很可能是为了帮助开发者深入理解和掌握Spring MVC的核心概念、工作原理以及实践技巧。下面将详细阐述Spring MVC的相关知识点。 1. **核心组件**: - **DispatcherServlet**:Spring...
源码调试是学习Spring MVC的一个重要环节,它能帮助开发者理解框架内部的执行流程。通过设置断点,查看变量状态,跟踪方法调用,可以深入理解Spring MVC如何处理请求、如何进行依赖注入以及如何与视图交互。这种能力...
Spring MVC 是一个基于Java的轻量级Web应用框架,它是Spring框架的重要组成部分,主要用于构建Web应用程序的后端控制器。在本实例中,我们将探讨如何利用Spring MVC的注解来简化前后台交互,以及如何实现简单视图...