spring篇:【RequestToViewNameTranslator】

RequestToViewNameTranslator這個類,出現在springMVC的DispatcherServlet類中,作爲DispatcherServlet的initStrategies方法中的9大init方法之一的initRequestToViewNameTranslator方法中,就會初始化一個RequestToViewNameTranslator。

那麼下面我們就來看看這到底是是個什麼東東,它是做什麼的?怎麼用?什麼時候被調用?讓我們一起玩轉RequestToViewNameTranslator。

一.來看一下這個類的出處
 


當用tomact啓動你的程序時,便會進入到DispatcherServlet來初始化一些內容。自然就包括了我們今天的豬腳。如圖中的源碼所示,首先從容器中找對應的名爲viewNameTranslator的RequestToViewNameTranslator實現類,如果找不到,就用DispatcherServlet.properties中指定的translator來生成一個(爲什麼從這個文件,可參其他文章【DispatcherServlet篇】)。

二. 這個類主要作用是什麼以及從在哪裏被調用?
在網上看過很多關於這個類的說明,基本都是講的源碼的執行過程,這對於初學者也許有點抽象,下面我通過一個例子,來說明它的作用。
相信看這個文章的人應該明白springmvc的作用,說白了就是,我發起一個請求,然後controller中的方法來處理這個請求,然後通過return "jsp頁面的路徑" 來顯示我們的jsp頁面(此處不考慮返回json等其他情況,只考慮最簡單的返回jsp頁面)。例如下面代碼,當我們瀏覽器訪問http://localhost:8088/view/hellojsp時,便會將hello.jsp的內容顯示在瀏覽器上, 如下:

@Controller
@RequestMapping("/view")
public class ViewController {
	@RequestMapping("/hellojsp")
	public String toHelloJsp(){
        // 跳轉到hello.jsp
		return "hello";
	}
}

這裏,我們返回的這個hello,在springmvc中就叫做viewName(至於爲什麼返回的字符串會最終變爲頁面來顯示,這裏不做介紹。看參考其他的文章),有了這個名字,springmvc就可以從我們存放jsp頁面的目錄下去尋找與之名字相同的jsp文件,來顯示了。
那麼現在來想這麼一個問題,如果現在我們這裏不返回值了,如下圖所示,那麼瀏覽器請求的結果是什麼?springmvc他還怎麼去找對應的jsp文件呢?

@Controller
@RequestMapping("/view")
public class ViewController {
	@RequestMapping("/hellojsp")
	public void toHelloJsp(){
        // 訪問這個url,按理說應該顯示hello.jsp頁面,但是我現在這裏給註釋掉了,返回值改爲了void
        // return "hello";
	}
}

相信大家都會說,肯定是404了。對,沒錯,結果肯定是404,如下圖:

但是大家知不知道,在顯示404錯誤之前,springmvc還爲我們做了一步操作,就是使用我們今天的豬腳RequestToViewNameTranslator,然後用它的實現類的解析方式去解析了我們的請求,從請求中來的出一個字符串,來代替我們controller中的return的字符串(jsp文件的名字),然後在jsp文件目錄中找名字與這個字符串相同的jsp文件,如果找到了,就顯示這個jsp,如果找不到就顯示我們上面的404。

所以說,RequestToViewNameTranslator就是一個請求解析器,他的每個實現有各自的一個解析請求的算法,經過這個算法,從請求的url中獲得一個字符串,將這個字符串作爲要顯示的jsp的名字,去jsp文件目錄中查找,找到就顯示,找不到才最終顯示404.
在springmvc中默認使用的是一個名字爲DefaultRequestToViewNameTranslator(默認也只有這一個實現類),他解析請求的算法是將我們的請求直接解析爲jsp的名字,然後從存放jsp的目錄中去找,比如我們上面的請求是/view/hellojsp,那麼經過這個實現類的解析後得到的便是/view/hellojsp這個字符串,有了這個值後,就會在執行一次就等同於在controller中return "/view/viewjsp"一樣的效果,也就是去jsp目錄下的view文件夾下去找viewjsp.jsp文件,如果找到就顯示,找不到就404,因爲我們沒有這個文件,所以就最終404了。

那麼這個RequestToViewNameTranslator是在什麼時候被調用的呢?下面通過一次請求的代碼跟蹤來看一下,controller用的是上面那個沒有返回值的。
第一步:瀏覽器發送請求:http://localhost:8088/view/hellojsp
第二步:通過DispatcherServlet中的doDispatch方法調用controller中的toHelloJsp方法處理請求。如下:


第三步:調用完controller的方法後,便通過判斷來看是否使用RequestToViewNameTranslator來生成默認的viewname

第四步:因爲沒有返回值,所以mv(ModelAndView)中就沒有view,所以就要使用RequestToViewNameTranslator來生成默認的viewname

第五步:調用RequestToViewNameTranslator默認實現類DefaultRequestToViewNameTranslator的getDefaultViewName方法來獲取默認的viewname

 

第六步:下面就是DefaultRequestToViewNameTranslator中將請求變爲viewname的具體算法了

第七步:將這個返回的path作爲view賦值給mv,有了mv後,springmvc便會根據mv的內容去找對應的jsp,因爲此時mv的view爲view/hellojsp,所以便會到jsp目錄下的view目錄下去找hellojsp,因爲我們還沒有這個文件,所以就顯示404了。
到此整個請求就結束。

上面雖然給大家展示了並講述了RequestToViewNameTranslator是在哪,並且是如何被使用的,但最終因爲沒有找到默認生成的viewname所對應jsp,還是顯示了404,那麼現在我們爲了讓使用默認viewname生成的ModelAndView生效,最終能通過這個默認的viewname顯示出頁面,而不是404,我們就新建view文件夾,然後新建一個hellojsp.jsp,看看最終是否能顯示。


然後,我們再次瀏覽器發起http://localhost:8088/view/hellojsp ,下面看看結果如何,如下:

怎麼樣,是不是用默認的DefaultRequestToViewNameTranslator獲取的viewname,成功顯示出來了吧,這個時候404沒有了。
這也正如作者在開頭說的那樣,頁面在顯示404之前,其實springmvc還幫我們通過RequestToViewNameTranslator獲取一個默認的viewname,然後用這個viewname又去jsp的目錄中找了一次是否有與之同行的jsp文件。

 

三.自定義RequestToViewNameTranslator
我們現在自己自定義一個實現類,然後實現這樣的效果:controller我們依舊沒有返回值,然後在我們自定義的實現類中,我們通過返回一個hello字符串的viewname,然後頁面顯示hello.jsp。下面開始:
第一步:編寫RequestToViewNameTranslator實現類,MyRequestToViewNameTranslator

public class MyRequestToViewNameTranslator implements RequestToViewNameTranslator {
	@Override
	public String getViewName(HttpServletRequest request) throws Exception {
		// 直接返回hello,然後讓springmvc去幫我們顯示jsp目錄下的hello.jsp
		return "hello";
	}
}

第二步:通過spring-mvc.xml文件聲明這個類,放到容器中(也可以使用java configuration形式)

	<!-- 注意id必須爲viewNameTranslator -->
	<bean id="viewNameTranslator" class="com.lhb.MyRequestToViewNameTranslator"/> 

第三步:啓動程序,啓動時在初始化DispatcherServlet時,我們得到的不再是默認的DefaultRequestToViewNameTranslator,而是從容器中獲取的我們自定義的類,如下圖紅框

第四步:瀏覽器發起http://localhost:8088/view/hellojsp 請求
此時在運行完controller的方法後,因爲沒有返回值,所以便會調用我們自定義的類中,來通過算法從請求中解析出一個默認的viewname來使用,作爲將來查找的jsp文件的名字,因爲是例子,所以我們直接就返回hello了,如下:

最後,springmvc去jsp目錄下找到了hello.jsp頁面,就顯示出來了,如下:

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
到此,整個文章完了,下面做一下總結:

  1. 什麼是RequestToViewNameTranslator?
    就是將請求的url解析成一個viewname的解析器。具體怎麼個算法解析,可以自定義,也可以使用默認的實現類
  2. 什麼時候這個實現類會被調用?
    當我們的controller的方法中,沒有返回值時(只考慮返回值爲jsp頁面的名字,不考慮直接輸出字符串到瀏覽器),那麼便會調用Translator來獲取一個默認的viewname,然後使用這個viewname的值,去jsp目錄中找與之同名的jsp頁面,如果還找不到,那就顯示404了。
  3. 注意,在spring-mvc.xml中聲明我們的自定義實現類時,bean的名字一定爲viewNameTranslator,否則會使用默認的實現類。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章