LocaleResolver簡介
? ? localeResolver是當(dāng)前的區(qū)域解析器提澎,簡單來說我們可以通過這個接口來實現(xiàn)國際化。
官方介紹
1)基于web的區(qū)域設(shè)置解析策略接口
2)通過請求進(jìn)行區(qū)域設(shè)置解析
3)可以使用基于request虱朵、session莉炉、cookies實現(xiàn)。
默認(rèn)的實現(xiàn)是AcceptHeaderLocaleResolver【通過HTTP頭提供的信息進(jìn)行設(shè)置】
4)使用RequestContext.getLocale()檢索controller或views中的當(dāng)前區(qū)域設(shè)置
點擊查看詳細(xì)文檔介紹
接口分析
下面列出這個類的核心方法
可以看出這個接口的很簡單梆暮,含義也很清晰:
1)Locale resolveLocale(request):解析當(dāng)前區(qū)域語言绍昂,可以返回當(dāng)前的Locale;
2)void setLocale(request, response,locale)改變當(dāng)前的Locale窘游;
繼承結(jié)構(gòu)分析
我們來看下LocaleResovler的類成繼承結(jié)構(gòu)以及Spring提供給了我們哪些默認(rèn)的實現(xiàn)類:
可以看到默認(rèn)提供了4個實現(xiàn)類,下面分別介紹一下:
1.AcceptHeaderLocaleResolver
通過獲取http請求頭里邊的“accept-language”來設(shè)置區(qū)域信息贪嫂,因為我們無法通過改變客戶端傳入的header的頭信息來改變區(qū)域設(shè)置,所以這個類不支持修改Locale(即使這次能修改成功力崇,下次傳過來的header也還是原來的斗塘,所以spring在這個類里的resolveLocale方法做了拋出異常的操作)馍盟。
2.CookieLocaleResolver
這個類繼承了LocaleContextResolver接口,這個接口對頂級接口做了一些擴展贞岭,支持設(shè)置/返回Locale的context上下文搓侄,上下文中保存更多的信息例如:當(dāng)前的locale或者timeZone(典型的實現(xiàn)為TimeZoneAwareLocaleConext同時包含當(dāng)前l(fā)ocale和timeZone)
接下來繼續(xù)說這個CookieLocaleResolver類,簡單來說休讳,我們可以通過修改cookie里邊的區(qū)域值然后返回給客戶端,下次客戶端傳過來的時候就是我們上次修改后的區(qū)域值,這樣來達(dá)到動態(tài)改變locale的目的俊柔。
3.FixedLocaleResolver
這個類繼承了AbstractLocaleResolver和AbstractLocaleContextResolver兩個抽象類:
1) AbstractLocaleResolver
擴展了LocaleResolver:支持設(shè)置/返回默認(rèn)locale的能力;
2) AbstractLocaleContextResolver
繼承自AbstractLocaleResolver雏婶,在AbstractLocaleResolver的基礎(chǔ)上提供了設(shè)置默認(rèn)時區(qū)的能力;
再回來說這個類酵紫,它是從JVM獲取默認(rèn)的locale,并且不支持修改locale奖地,感覺實際用處不是很大。
4.SessionLocaleResolver
這個類是我們比較常用的類参歹,它比較靈活,因為它支持我們從session里邊去設(shè)置/獲取locale犬庇,同時它也實現(xiàn)了AbstractLocaleResolver和AbstractLocaleContextResolver接口,擁有獲取locale上下文的能力[同F(xiàn)ixedLocaleResolver]
實踐操作
下面來實際操作一下如何在項目中使用session來改變locale(文章最后補充了一種簡單的設(shè)置locale方式)
1.首先創(chuàng)建需要的i18n文件:
2.創(chuàng)建view視圖文件
3.注冊SessionLocaleResolver
????創(chuàng)建SessionLocaleResolver注入spring上下文中(如果不定義springboot默認(rèn)使用AcceptHeaderLocaleResolver);
4.注入controller,寫測試接口
5.瀏覽器輸入請求地址
6.輸入查看接口的地址
從測試結(jié)果來看欢峰,我們通過改變locale參數(shù),然后訪問localeResult接口闯狱,輸出的結(jié)果都會是當(dāng)前的設(shè)置的語言來解析的,除非再次改變locale參數(shù)哄孤。什么意思呢?就是說每次我們改變locale值瘦陈,就已經(jīng)保存在session里邊了。后續(xù)的請求都是去session里邊獲取locale然后去解析對應(yīng)的*. Properties文件里邊的“welcome”;
源碼分析
? ? 總的過程為:AbstractLocaleContextResolver默認(rèn)實現(xiàn)了頂級接口的setLocale方法晨逝,但是它調(diào)用了從LocaleContextResolver接口繼承的setLocaleContext()方法懦铺,而這個方法是在SessionLocaleResolver里邊實現(xiàn)的;
我們在程序里調(diào)用localeResolver.setLocale()方法時冬念,Spring會去查找實現(xiàn)了setLocale()的子類,雖然我們注入的是sessionLocaleResolver急前,但是它并沒有實現(xiàn)這個方法,而是它的父類AbstractLocaleContextResolver實現(xiàn)了setLocale()方法裆针,找到這個實現(xiàn)方法以后發(fā)現(xiàn)方法里又調(diào)用了setLocaleContext()方法,而實現(xiàn)這個方法的子類就是SessionLocaleResolver世吨,這樣實際的職責(zé)又回到了這個類里邊。我們發(fā)現(xiàn)它確實是在session里邊設(shè)置了locale另假。
那么Spring為什么要這么設(shè)計呢?直接在SessionLocaleResolver里邊實現(xiàn)setLocale方法不行嗎边篮?我認(rèn)為核心應(yīng)該就是這個localeContext戈轿,因為localeContext里邊包含了locale和timeZone,它倆最終定義包含在了AbstractLocaleContextResolver里邊思杯。但是這個類是個抽象類,它并沒有能力去設(shè)置locale色乾,而是把設(shè)置的方法預(yù)留了出來(也就是繼承自接口LocaleContextResolver.setLocaleContext()方法),它只需要去調(diào)用子類實現(xiàn)的這個方法去設(shè)置就好了暖璧。即:只要繼承了AbstractLocaleContextResolver這個抽象類,那么你肯定就得實現(xiàn)setLocaleContext()方法澎办,具體從哪里來的localeConext它就不管了。這樣代碼層次就會非常的清晰局蚀,印證了設(shè)計原則里邊的開閉原則:對修改關(guān)閉對擴展開放。
resolveLocale()方法就不在說了過程比較簡單琅绅,跟設(shè)置過程一樣。
簡單方法設(shè)置locale:
上面我是手動設(shè)置locale的千扶,除此之外Spring為我們提供了一個攔截器LocaleChangeInterceptor,通過這個攔截器可以達(dá)到自動設(shè)置locale的目的
步驟:其實我們只需創(chuàng)建一個這樣攔截器县貌,并且指定保存locale的參數(shù)就可以了(默認(rèn)通過request里邊的“l(fā)ocale”參數(shù));
原理:在每個request請求來的時候煤痕,通過攔截request獲取里邊的locale參數(shù),來進(jìn)行自動設(shè)置locale摆碉。大致源碼如下:
結(jié)束語:
1) localeResolver設(shè)置/獲取locale的核心方法是setLocale()和resovleLoccale()兩個方法;
2) LocaleContext是locale的上下文典型實現(xiàn)為SimpleTimeZoneAwareLocaleContext包含默認(rèn)的lcoale和timeZone;如果我們想自定義localeContext支持包含一些其它信息巷帝,可以通過繼承SimpleLocaleContext實現(xiàn);
3) 實現(xiàn)locale的設(shè)置兩種方式楞泼,手動設(shè)置locale和通過攔截器獲取請求參數(shù)自動設(shè)置,推薦第二種堕阔;
下節(jié)預(yù)覽:上面我們學(xué)習(xí)了比較簡單的localResolver接下來繼續(xù)看一下相對復(fù)雜點兒的viewResolver,它是mvc里邊的視圖層超陆,我們最終看到的html頁面的就跟這個viewResolver有關(guān)。