View视图 其实就是对应MVC中的"V"

1.ViewResolver 结构图

2.BeanNameViewResolver

通过把返回的逻辑视图名称去匹配定义好的视图bean对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Test
public void testBeanNameViewResolver() throws ServletException {
    StaticWebApplicationContext wac = new StaticWebApplicationContext();
    wac.setServletContext(new MockServletContext());
    MutablePropertyValues pvs1 = new MutablePropertyValues();
    pvs1.addPropertyValue(new PropertyValue("url""/example1.jsp"));
    wac.registerSingleton("example1", InternalResourceView.class, pvs1);
    BeanNameViewResolver vr = new BeanNameViewResolver();
    vr.setApplicationContext(wac);
    wac.refresh();
     
    View view = vr.resolveViewName("example1", Locale.getDefault());
    assertEquals("Correct view class", InternalResourceView.class, view.getClass());
    assertEquals("Correct URL""/example1.jsp", ((InternalResourceView) view).getUrl());
}

3.XmlViewResolver
XmlViewResolver这个视图解析器跟 BeanNameViewResolver 有点类似,也是通过把返回的逻辑视图名称去匹配定义好的视图 bean 对象。

3.1 配置XML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
   <bean id="example1" class="org.springframework.web.servlet.view.ViewResolverTests$TestView">
      <property name="url"><value>/example1.jsp</value></property>
      <property name="attributesMap">
         <map>
            <entry key="test1"><value>testvalue1</value></entry>
            <entry key="test2"><ref bean="testBean"/></entry>
         </map>
      </property>
      <property name="location"><value>test</value></property>
   </bean>
</beans>

3.2 测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void testXmlViewResolver() throws Exception {
   StaticWebApplicationContext wac = new StaticWebApplicationContext();
   wac.registerSingleton("testBean", TestBean.class);
   wac.setServletContext(new MockServletContext());
   wac.refresh();
   TestBean testBean = (TestBean) wac.getBean("testBean");
   XmlViewResolver vr = new XmlViewResolver();
   vr.setLocation(new ClassPathResource("org/springframework/web/servlet/view/views.xml"));
   vr.setApplicationContext(wac);
   View view1 = vr.resolveViewName("example1", Locale.getDefault());
   assertTrue("Correct view class", TestView.class.equals(view1.getClass()));
   assertTrue("Correct URL""/example1.jsp".equals(((InternalResourceView) view1).getUrl()));

BeanNameViewResolver VS XmlViewResolver

1. BeanNameViewResolver 要求视图 bean 对象都定义在 Spring 的 application context 中,而 XmlViewResolver 是在指定的配置文件中寻找视图 bean 对象,

2. XmlViewResolver是 AbstractCachingViewResolver的子类,支持缓存;

BeanNameViewResolver 不会进行视图缓存。
4. ResourceBundleViewResolver 
和 XmlViewResolver 一样它也需要有一个配置文件来定义逻辑视图名称和真正的 View 对象的对应关系,不同的是 ResourceBundleViewResolver 的配置文件是一个属性文件,而且必须是放在 classpath 路径下面的,默认情况下这个配置文件是在 classpath 根目录下的 views.properties 文件,如果不使用默认值的话,则可以通过属性 baseName 或 baseNames 来指定。

4.1 配置文件testviews_fr.properties

1
2
3
debugView.(class)= org.springframework.web.servlet.view.InternalResourceView
debugView.url=jsp/debug/deboug.jsp
debugView.contentType=text/xml;charset=ISO-8859-1

4.2 测试用例

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
public class ResourceBundleViewResolverTests extends TestCase {
/** Comes from this package */
private static String PROPS_FILE = "org.springframework.web.servlet.view.testviews";
private ResourceBundleViewResolver rb;
private StaticWebApplicationContext wac;
    protected void setUp() throws Exception {
       rb = new ResourceBundleViewResolver();
       rb.setBasename(PROPS_FILE);
       rb.setCache(getCache());
       rb.setDefaultParentView("testParent");
     
       wac = new StaticWebApplicationContext();
       wac.setServletContext(new MockServletContext());
       wac.refresh();
     
       // This will be propagated to views, so we need it.
       rb.setApplicationContext(wac);
  }
   
  public void testDebugViewFrench() throws Exception {
   View v = rb.resolveViewName("debugView", Locale.FRENCH);
   assertTrue("French debugView must be of type InternalResourceView", v instanceof InternalResourceView);
   InternalResourceView jv = (InternalResourceView) v;
   assertTrue("French debugView must have correct URL""jsp/debug/deboug.jsp".equals(jv.getUrl()));
   assertTrue(
      "Correct overridden (XML) content type, not '" + jv.getContentType() + "'",
      jv.getContentType().equals("text/xml;charset=ISO-8859-1"));
}
}

在ResourceBundleViewResolver第一次进行视图解析的时候会先new一个BeanFactory对象,然后把properties文件中定义好的属性按照它自身的规则生成一个个的bean对象注册到该BeanFactory中,之后会把该BeanFactory对象保存起来,所以ResourceBundleViewResolver缓存的是BeanFactory,而不是直接的缓存从BeanFactory中取出的视图bean。然后会从bean工厂中取出名称为逻辑视图名称的视图bean进行返回。接下来就讲讲Spring通过properties文件生成bean的规则。它会把properties文件中定义的属性名称按最后一个点“.”进行分割,把点前面的内容当做是bean名称,点后面的内容当做是bean的属性。这其中有几个特别的属性,Spring把它们用小括号包起来了,这些特殊的属性一般是对应的attribute,但不是bean对象所有的attribute都可以这样用。其中(class)是一个,除了(class)之外,还有(scope)、(parent)、(abstract)、(lazy-init)。而除了这些特殊的属性之外的其他属性,Spring会把它们当做bean对象的一般属性进行处理,就是bean对象对应的property。所以根据上面的属性配置文件将生成如下两个bean对象:

from http://elim.iteye.com/blog/1770554

5.UrlBasedViewResolver

它是对ViewResolver的一种简单实现,而且继承了AbstractCachingViewResolver,主要就是提供的一种拼接URL的方式来解析视图,它可以让我们通过prefix属性指定一个指定的前缀,通过suffix属性指定一个指定的后缀,然后把返回的逻辑视图名称加上指定的前缀和后缀就是指定的视图URL了。

5.2 重要属性

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
public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered {
   /**
    * Prefix for special view names that specify a redirect URL (usually
    * to a controller after a form has been submitted and processed).
    * Such view names will not be resolved in the configured default
    * way but rather be treated as special shortcut.
    */
   public static final String REDIRECT_URL_PREFIX = "redirect:";
   /**
    * Prefix for special view names that specify a forward URL (usually
    * to a controller after a form has been submitted and processed).
    * Such view names will not be resolved in the configured default
    * way but rather be treated as special shortcut.
    */
   public static final String FORWARD_URL_PREFIX = "forward:";
   //Set the view class that should be used to create views.
   private Class viewClass;
// Set the prefix that gets prepended to view names when building a URL.
   private String prefix = "";
    //the suffix that gets appended to view names when building a URL.
   private String suffix = "";
    //view names; such that 'my*', '*Report' and '*Repo*' 
   private String[] viewNames = null;
    //content type for all views.
   private String contentType;
    //UrlBasedViewResolver 的 redirectContextRelative 的默认值为 true,
    //这意味着,只要重定向的资源以/开头,那么 spring 会帮你添加 contextPath
   private boolean redirectContextRelative = true;
//whether redirects should stay compatible with HTTP 1.0 clients
   private boolean redirectHttp10Compatible = true;
    //the name of the RequestContext attribute for all views
   private String requestContextAttribute;
   private int order = Integer.MAX_VALUE;
   /** Map of static attributes, keyed by attribute name (String) */
   private final Map<String, Object> staticAttributes = new HashMap<String, Object>();
   ...
   }

5.3  createView方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static final String REDIRECT_URL_PREFIX = "redirect:";
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);
}

URLBasedViewResolver发现返回的视图名称包含”redirect:”前缀,于是把返回的视图名称前缀”redirect:”去掉,取后面的test.do组成一个RedirectView,RedirectView中将把请求返回的模型属性组合成查询参数的形式组合到redirect的URL后面,然后调用HttpServletResponse对象的sendRedirect方法进行重定向。同样URLBasedViewResolver还支持forword:前缀,对于视图名称中包含forword:前缀的视图名称将会被封装成一个InternalResourceView对象,然后在服务器端利用RequestDispatcher的forword方式跳转到指定的地址。使用UrlBasedViewResolver的时候必须指定属性viewClass,表示解析成哪种视图,一般使用较多的就是InternalResourceView,利用它来展现jsp,但是当我们使用JSTL的时候我们必须使用JstlView。

5.4 一段UrlBasedViewResolver的定义

1
2
3
4
5
6
<bean  
   class="org.springframework.web.servlet.view.UrlBasedViewResolver">  
   <property name="prefix" value="/WEB-INF/" />  
   <property name="suffix" value=".jsp" />  
   <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/>  
</bean>

6.InternalResourceViewResolver 内部资源视图解析器

InternalResourceViewResolver会把返回的视图名称都解析为InternalResourceView对象,InternalResourceView会把Controller处理器方法返回的模型属性都存放到对应的request属性中,然后通过RequestDispatcher在服务器端把请求forword重定向到目标URL。

6.1最熟悉的一段配置

1
2
3
4
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
   <property name="prefix" value="/WEB-INF/"/>  
   <property name="suffix" value=".jsp"></property>  
</bean>

总结

ViewResolver解决的事情很单一

  1. 通过配置,根据不同策略,找出匹配的JSP(也可以是其他)。

  2. 适当添加缓存处理

  3. 根据策略不同,返回不同的VIEW,降低耦合度。

本文转自 randy_shandong 51CTO博客,原文链接:http://blog.51cto.com/dba10g/1880178,如需转载请自行联系原作者

SpringMVC源码分析(8)剖析ViewResolver相关推荐

  1. SpringMVC源码分析(4)剖析DispatcherServlet重要组件

    简单介绍了一个请求的处理过程, 简略描述了调用过程,并没有涉及过多细节,如url匹配,报文解析转换等. <SpringMVC源码分析(2)DispatcherServlet的初始化>:介绍 ...

  2. 简单直接让你也读懂springmvc源码分析(3.1)-- HandlerMethodReturnValueHandler

    该源码分析系列文章分如下章节: springmvc源码分析(1)-- DispatcherServlet springmvc源码分析(2)-- HandlerMapping springmvc源码分析 ...

  3. SpringMVC源码分析_1 SpringMVC容器启动和加载原理

                                                                    SpringMVC源码分析_1 SpringMVC启动和加载原理     ...

  4. springMVC源码分析--访问请求执行ServletInvocableHandlerMethod和InvocableHandlerMethod

    在之前一篇博客中 springMVC源码分析--RequestMappingHandlerAdapter(五)我们已经简单的介绍到具体请求访问的执行某个Controller中的方法是在RequestM ...

  5. SpringMVC源码分析_框架原理图

                                                                                 SpringMVC源码分析_框架原理图     ...

  6. SpringMVC源码分析系列[转]

    说到java的mvc框架,struts2和springmvc想必大家都知道,struts2的设计基本上完全脱离了Servlet容器,而springmvc是依托着Servlet容器元素来设计的,同时sp ...

  7. SpringMVC源码分析系列

    说到java的mvc框架,struts2和springmvc想必大家都知道,struts2的设计基本上完全脱离了Servlet容器,而springmvc是依托着Servlet容器元素来设计的,同时sp ...

  8. Springmvc源码分析、底层原理

    1.Springmvc是如何找到Controller的? 首先在请求过来时,会先进入DispatcherServlet进行请求分发,执行DispatcherServlet类中的doDispatch() ...

  9. SpringMVC源码分析(二)

    1.DispatcherServlet源码分析 1.@InitBinder(续) 1.DataBinder概述 package org.springframework.validation; 此类所在 ...

  10. ZooKeeper面试题(2020最新版,springmvc源码分析pdf百度云

    10. ACL 权限控制机制 UGO(User/Group/Others) 目前在 Linux/Unix 文件系统中使用,也是使用最广泛的权限控制方式.是一种粗粒度的文件系统权限控制模式. ACL(A ...

最新文章

  1. rfc6455 WebSockets
  2. 这次是真的!波士顿动力Atlas机器人又进化了,自主导航get新技能
  3. 失败 安装scikit_scikit-learn0.22版本最新发布
  4. 通过PEB获取模块基址
  5. mrc20温控f1什么意思_温控器的“总、高、低”是什么意思?不知道?民熔老电工告诉你...
  6. 使用RemObjects Pascal Script
  7. ASP.NET与MVC架构区别总结
  8. 计算机桌面组成部分教案,三年级信息技术第五课设置个性桌面教学设计
  9. Linux宝库快讯 | OpenInfra中国日正式确定会议合作方
  10. SQL语句优化常见方法
  11. 大学生创新创业计划-2019
  12. 设计一个巴特沃斯低通滤波器
  13. vue的事件修饰符之.prevent
  14. 新站长建设网站需要学习知识
  15. 百面机器学习 之 集成学习
  16. 织梦联动枚举字段添加一级分类如果超过132个自动变成二级解决方法
  17. 编程计算2×3阶矩阵A和3×2阶矩阵B之积C。矩阵相乘的基本方法是:矩阵A的第i行的所有元素同矩阵B第j列的所有元素对应相乘,并把相乘的结果相加,最终得到的值就是矩阵C的第i行第j列的值。
  18. ttkefu怎么取消英文版?显示中文版
  19. 复杂网络实验报告2019210025曾培圣
  20. python中定义变量有引号和单引号_说说Python 单引号、双引号、三引号的区别?...

热门文章

  1. webApp开发-功能模块开发流程
  2. 使用渲染纹理的制作摄像头
  3. linux下踢出已登录用户
  4. mex+matlab2013b+vs2012安装
  5. Asp.net内置对象之Cookies
  6. JBoss下布署Spring2.5和Struts2系统
  7. Docker 集群 图形化显示 Visualizer
  8. hdu5033 最大仰望角
  9. 计算机网络第五章:运输层
  10. 【Groovy】MOP 元对象协议与元编程 ( 使用 Groovy 元编程进行函数拦截 | 重写 MetaClass#invokeMethod 方法拦截 JDK 中已经定义的函数 )