javascript
SpringMVC源码分析(8)剖析ViewResolver
View視圖 其實就是對應(yīng)MVC中的"V"
1.ViewResolver 結(jié)構(gòu)圖
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())); |
1. BeanNameViewResolver 要求視圖 bean 對象都定義在 Spring 的 application context 中,而 XmlViewResolver 是在指定的配置文件中尋找視圖 bean 對象,
2. XmlViewResolver是 AbstractCachingViewResolver的子類,支持緩存;
BeanNameViewResolver 不會進行視圖緩存。
4.?ResourceBundleViewResolver?
和 XmlViewResolver 一樣它也需要有一個配置文件來定義邏輯視圖名稱和真正的 View 對象的對應(yīng)關(guān)系,不同的是 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文件中定義好的屬性按照它自身的規(guī)則生成一個個的bean對象注冊到該BeanFactory中,之后會把該BeanFactory對象保存起來,所以ResourceBundleViewResolver緩存的是BeanFactory,而不是直接的緩存從BeanFactory中取出的視圖bean。然后會從bean工廠中取出名稱為邏輯視圖名稱的視圖bean進行返回。接下來就講講Spring通過properties文件生成bean的規(guī)則。它會把properties文件中定義的屬性名稱按最后一個點“.”進行分割,把點前面的內(nèi)容當(dāng)做是bean名稱,點后面的內(nèi)容當(dāng)做是bean的屬性。這其中有幾個特別的屬性,Spring把它們用小括號包起來了,這些特殊的屬性一般是對應(yīng)的attribute,但不是bean對象所有的attribute都可以這樣用。其中(class)是一個,除了(class)之外,還有(scope)、(parent)、(abstract)、(lazy-init)。而除了這些特殊的屬性之外的其他屬性,Spring會把它們當(dāng)做bean對象的一般屬性進行處理,就是bean對象對應(yīng)的property。所以根據(jù)上面的屬性配置文件將生成如下兩個bean對象:
from http://elim.iteye.com/blog/1770554
5.UrlBasedViewResolver
它是對ViewResolver的一種簡單實現(xiàn),而且繼承了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發(fā)現(xiàn)返回的視圖名稱包含”redirect:”前綴,于是把返回的視圖名稱前綴”redirect:”去掉,取后面的test.do組成一個RedirectView,RedirectView中將把請求返回的模型屬性組合成查詢參數(shù)的形式組合到redirect的URL后面,然后調(diào)用HttpServletResponse對象的sendRedirect方法進行重定向。同樣URLBasedViewResolver還支持forword:前綴,對于視圖名稱中包含forword:前綴的視圖名稱將會被封裝成一個InternalResourceView對象,然后在服務(wù)器端利用RequestDispatcher的forword方式跳轉(zhuǎn)到指定的地址。使用UrlBasedViewResolver的時候必須指定屬性viewClass,表示解析成哪種視圖,一般使用較多的就是InternalResourceView,利用它來展現(xiàn)jsp,但是當(dāng)我們使用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?內(nèi)部資源視圖解析器
InternalResourceViewResolver會把返回的視圖名稱都解析為InternalResourceView對象,InternalResourceView會把Controller處理器方法返回的模型屬性都存放到對應(yīng)的request屬性中,然后通過RequestDispatcher在服務(wù)器端把請求forword重定向到目標(biāo)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> |
總結(jié)
ViewResolver解決的事情很單一
通過配置,根據(jù)不同策略,找出匹配的JSP(也可以是其他)。
適當(dāng)添加緩存處理
根據(jù)策略不同,返回不同的VIEW,降低耦合度。
本文轉(zhuǎn)自 randy_shandong 51CTO博客,原文鏈接:http://blog.51cto.com/dba10g/1880178,如需轉(zhuǎn)載請自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的SpringMVC源码分析(8)剖析ViewResolver的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Unable to open file
- 下一篇: java-vector hashtabl