频道栏目
首页 > 资讯 > 其他 > 正文

SpringMVC源码分析(8)剖析ViewResolver

16-12-10        来源:[db:作者]  
收藏   我要投稿

ViewResolver很简单,通过名称(name),获取View视图的。

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

1.ViewResolver 结构图

wKioL1hGvzHwOJ6pAABL6CTjprE928.png

2.BeanNameViewResolver

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

@Test
publicvoidtestBeanNameViewResolver()throwsServletException{
StaticWebApplicationContextwac=newStaticWebApplicationContext();
wac.setServletContext(newMockServletContext());
MutablePropertyValuespvs1=newMutablePropertyValues();
pvs1.addPropertyValue(newPropertyValue("url","/example1.jsp"));
wac.registerSingleton("example1",InternalResourceView.class,pvs1);
BeanNameViewResolvervr=newBeanNameViewResolver();
vr.setApplicationContext(wac);
wac.refresh();

Viewview=vr.resolveViewName("example1",Locale.getDefault());
assertEquals("Correctviewclass",InternalResourceView.class,view.getClass());
assertEquals("CorrectURL","/example1.jsp",((InternalResourceView)view).getUrl());
}

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

3.1 配置XML






/example1.jsp
testvalue1

test

3.2 测试用例

@Test
publicvoidtestXmlViewResolver()throwsException{
StaticWebApplicationContextwac=newStaticWebApplicationContext();
wac.registerSingleton("testBean",TestBean.class);
wac.setServletContext(newMockServletContext());
wac.refresh();
TestBeantestBean=(TestBean)wac.getBean("testBean");
XmlViewResolvervr=newXmlViewResolver();
vr.setLocation(newClassPathResource("org/springframework/web/servlet/view/views.xml"));
vr.setApplicationContext(wac);

Viewview1=vr.resolveViewName("example1",Locale.getDefault());
assertTrue("Correctviewclass",TestView.class.equals(view1.getClass()));
assertTrue("CorrectURL","/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

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

4.2 测试用例

publicclassResourceBundleViewResolverTestsextendsTestCase{
/**Comesfromthispackage*/
privatestaticStringPROPS_FILE="org.springframework.web.servlet.view.testviews";

privateResourceBundleViewResolverrb;

privateStaticWebApplicationContextwac;
protectedvoidsetUp()throwsException{
rb=newResourceBundleViewResolver();
rb.setBasename(PROPS_FILE);
rb.setCache(getCache());
rb.setDefaultParentView("testParent");

wac=newStaticWebApplicationContext();
wac.setServletContext(newMockServletContext());
wac.refresh();

//Thiswillbepropagatedtoviews,soweneedit.
rb.setApplicationContext(wac);
}

publicvoidtestDebugViewFrench()throwsException{
Viewv=rb.resolveViewName("debugView",Locale.FRENCH);
assertTrue("FrenchdebugViewmustbeoftypeInternalResourceView",vinstanceofInternalResourceView);
InternalResourceViewjv=(InternalResourceView)v;
assertTrue("FrenchdebugViewmusthavecorrectURL","jsp/debug/deboug.jsp".equals(jv.getUrl()));
assertTrue(
"Correctoverridden(XML)contenttype,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了。

wKioL1hGxViDg90pAAAhdL5WGMg834.png

5.2 重要属性

publicclassUrlBasedViewResolverextendsAbstractCachingViewResolverimplementsOrdered{

/**
*PrefixforspecialviewnamesthatspecifyaredirectURL(usually
*toacontrollerafteraformhasbeensubmittedandprocessed).
*Suchviewnameswillnotberesolvedintheconfigureddefault
*waybutratherbetreatedasspecialshortcut.
*/
publicstaticfinalStringREDIRECT_URL_PREFIX="redirect:";

/**
*PrefixforspecialviewnamesthatspecifyaforwardURL(usually
*toacontrollerafteraformhasbeensubmittedandprocessed).
*Suchviewnameswillnotberesolvedintheconfigureddefault
*waybutratherbetreatedasspecialshortcut.
*/
publicstaticfinalStringFORWARD_URL_PREFIX="forward:";

//Settheviewclassthatshouldbeusedtocreateviews.
privateClassviewClass;
//SettheprefixthatgetsprependedtoviewnameswhenbuildingaURL.
privateStringprefix="";
//thesuffixthatgetsappendedtoviewnameswhenbuildingaURL.
privateStringsuffix="";
//viewnames;suchthat'my*','*Report'and'*Repo*'
privateString[]viewNames=null;
//contenttypeforallviews.
privateStringcontentType;
//UrlBasedViewResolver的redirectContextRelative的默认值为true,
//这意味着,只要重定向的资源以/开头,那么spring会帮你添加contextPath
privatebooleanredirectContextRelative=true;
//whetherredirectsshouldstaycompatiblewithHTTP1.0clients
privatebooleanredirectHttp10Compatible=true;
//thenameoftheRequestContextattributeforallviews
privateStringrequestContextAttribute;

privateintorder=Integer.MAX_VALUE;

/**Mapofstaticattributes,keyedbyattributename(String)*/
privatefinalMapstaticAttributes=newHashMap();
...
}

5.3 createView方法

publicstaticfinalStringREDIRECT_URL_PREFIX="redirect:";
protectedViewcreateView(StringviewName,Localelocale)throwsException{
//Ifthisresolverisnotsupposedtohandlethegivenview,
//returnnulltopassontothenextresolverinthechain.
if(!canHandle(viewName,locale)){
returnnull;
}
//Checkforspecial"redirect:"prefix.
if(viewName.startsWith(REDIRECT_URL_PREFIX)){
StringredirectUrl=viewName.substring(REDIRECT_URL_PREFIX.length());
returnnewRedirectView(redirectUrl,isRedirectContextRelative(),isRedirectHttp10Compatible());
}
//Checkforspecial"forward:"prefix.
if(viewName.startsWith(FORWARD_URL_PREFIX)){
StringforwardUrl=viewName.substring(FORWARD_URL_PREFIX.length());
returnnewInternalResourceView(forwardUrl);
}
//Elsefallbacktosuperclassimplementation:callingloadView.
returnsuper.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的定义


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

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

6.1最熟悉的一段配置


总结

ViewResolver解决的事情很单一

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

适当添加缓存处理

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

    相关TAG标签
    上一篇:HUE安装及问题
    下一篇:Mysql-索引-BTree类型【精简版】
    相关文章
    图文推荐

    关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

    版权所有: 红黑联盟--致力于做实用的IT技术学习网站