Spring Boot、SpringMVC進行i18n國際化支持:使用MessageSource

項目示例倉庫

[Coding]https://meostar.coding.net/public/message-source-usage/message-source-usage/git

代碼分支說明

  • master分支

無配置,雖然能用,但是強烈建議使用配置。

  • code分支

通過代碼配置MessageSource,對應下面第二章節(jié) - 3.2

  • yml分支

通過yml文件配置MessageSource

一婚肆、國際化

1. 簡述

國際化是什么,簡單地說就是坐慰,在不修改內(nèi)部代碼的情況下较性,根據(jù)不同語言及地區(qū)顯示相應的語言界面。

2. Spring官方解釋

Spring中對國際化文件支持的基礎接口是MessageSource结胀。
參照Spring對于MessageSource解釋的官方文檔:

Strategy interface for resolving messages, with support for the parameterization and internationalization of such messages.
Spring provides two out-of-the-box implementations for production:
ResourceBundleMessageSource, built on top of the standard ResourceBundle
ReloadableResourceBundleMessageSource, being able to reload message definitions without restarting the VM

意思為:

Spring提供了兩種開箱即用的實現(xiàn)赞咙,一種是標準實現(xiàn),一種是運行時可重新加載糟港。



本文允許轉(zhuǎn)載攀操,轉(zhuǎn)載本文時請加上本文鏈接:
https://blog.csdn.net/nthack5730/article/details/82870368
http://www.reibang.com/p/a354d3f849ec
對于爬蟲網(wǎng)站隨意爬取以及轉(zhuǎn)載不加原文鏈接的,本人保留追究法律責任的權(quán)力秸抚!



二速和、SpringBoot中使用MessageSource國際化

1. SpringBoot自動化配置國際化支持

Spring Boot已經(jīng)對i18n國際化做了自動配置,自動配置類為:

org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration

使用MessageSource時只要@Autowired就行:

@Autowired
private MessageSource messageSource;

而Spring在啟動的時候裝備的實現(xiàn)類是:

org.springframework.context.support.ResourceBundleMessageSource

但是很多人會說:我用了Autowired為什么調(diào)用messageSource.getMessage(...)卻返回空內(nèi)容剥汤?
這是因為SpringBoot對國際化properties文件路徑默認設定是在message文件夾下颠放,找不到文件夾,所以就沒有信息返回唄吭敢。
下面會進行如何自定義i18n國際化配置講述碰凶。

2. 常見國際化支持配置參數(shù)解釋

MessageSource國際化配置中有幾個參數(shù)是常見的,在這里必須要說明下鹿驼,因為知道遮幾個參數(shù)才能理解下面的配置:

basename:默認的掃描的國際化文件名為messages欲低,即在resources建立messages_xx.properties文件,可以通過逗號指定多個畜晰,如果不指定包名默認從classpath下尋找砾莱。
encoding:默認的編碼為UTF-8,也可以改為GBK等等
cacheSeconds:加載國際化文件的緩存時間凄鼻,單位為秒腊瑟,默認為永久緩存面哼。
fallbackToSystemLocale:當找不到當前語言的資源文件時,如果為true默認找當前系統(tǒng)的語言對應的資源文件如messages_zh_CN.properties扫步,如果為false即加載系統(tǒng)默認的如messages.properties文件。

3. 自定義i18n國際化配置

很多時候我們要修改自動配置中的某些配置參數(shù)匈子,例如message.properties文件所在的文件夾路徑河胎、properties文件的編碼格式等等,可以用以下兩種方式進行配置修改虎敦,選一個就好:

  1. 修改Bean游岳,直接返回一個配置Bean
  2. 使用配置文件(比較推薦這種做法)

3.1 在application.yml配置文件中

在配置文件中加入下面的配置:(application.properties配置文件麻煩自行轉(zhuǎn)換下)

spring: 
  messages:
    basename: i18n/messages
    encoding: UTF-8

3.2 用Bean進行代碼配置

@Configuration下面加入Bean配置就好,下面是完整的類代碼:

@Configuration
public class MessageSourceConfig {

    @Bean(name = "messageSource")
    public ResourceBundleMessageSource getMessageSource() throws Exception {
        ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource();
        resourceBundleMessageSource.setDefaultEncoding("UTF-8");
        resourceBundleMessageSource.setBasenames("i18n/messages");
        return resourceBundleMessageSource;
    }
}

其中:

resourceBundleMessageSource.setBasenames("i18n/messages");

指定了i18n文件的位置其徙,這是個在i18n文件夾下的Resources Bundle文件集合胚迫,新建的時候在IDEA里面選擇的是Resource Bundle類型,名字寫的是messages唾那。這個很重要访锻,對應上方的配置文件!

注意:如果返回值不是MessageSource類型就要在@Bean上面指定name參數(shù)闹获,否則無法使用@Autowired進行自動裝入期犬,這個是SpringIOC的東西,大家可以去查找對應的資料避诽。

4. 使用i18n國際化

4.1 寫入國際化文件

根據(jù)上面的配置龟虎,在resouces-i18n下面加入Resource Bundle類型文件:
名稱為messages,然后加入以下兩種類型:

zh_CN
en_US

完成之后會生成下面三個文件:

  1. 【默認】messages.properties
  2. 【英文】messages_en_US.properties
  3. 【中文】messages_zh_CN.properties

在里面寫入同樣的字段:

hello=xxx

其中xxx在不同文件里面寫不同的語句(你能分辨出來就行)

4.2 代碼中使用MessageSource

在需要用到的類中@Autowired就可以使用了:

@Autowired
private MessageSource messageSource;

然后使用:

messageSource.getMessage(code, args, defaultMessage, locale);

就可以獲得對應的信息內(nèi)容沙庐。

4.3 MessageSource接口中的方法

MessageSource中有三個方法鲤妥,分別是:

String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);

String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;

String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;

常用的是第一個(主要是其他兩個會拋出NoSuchMessageException,不太方便)拱雏,下面是第一個方法中的參數(shù)解釋:

code:信息的鍵棉安,properties中的key
args:系統(tǒng)運行時參數(shù),可為空
defaultMessage:默認信息古涧,可為空
locale:區(qū)域信息垂券,我們可以通過java.util.Locale類下面的靜態(tài)常量找到對應的值。如:簡體中文就是zh_CN羡滑;英文就是en_US菇爪,詳見java.util.Locale中的常量值。

測試用例:

@RunWith(SpringRunner.class)
@SpringBootTest(properties = "spring.main.web-application-type=reactive")
public class TestMessageSource {
    private static final Logger logger = LoggerFactory.getLogger(TestMessageSource.class);

    @Autowired
    private MessageSource messageSource;

    @Test
    public void testGetMessage() {
        logger.info(messageSource.getMessage("hello", null, "", null));
    }
}

測試用例中使用了nulllocale參數(shù)柒昏,這里會輸出messages.propertieshello的值凳宙,這個參數(shù)會在下面4.4節(jié)中說明原因。

4.4 指定和默認的國際化信息

上面4.3中說明了MessageSource接口的三個方法职祷,我們最常用的是第一個不拋出異常的方法氏涩。其中有一個是locale參數(shù)届囚,這個參數(shù)的作用就是指定語言環(huán)境
java.util.Locale類中定義了很多的語言環(huán)境是尖,如:

...
static public final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN");
static public final Locale CHINA = SIMPLIFIED_CHINESE;
static public final Locale UK = createConstant("en", "GB");
static public final Locale US = createConstant("en", "US");
static public final Locale CANADA = createConstant("en", "CA");
...

MessageSource.getMessage(...)所有方法中意系,都有Locale參數(shù),指定區(qū)域信息饺汹。
當調(diào)用時蛔添,要如果指定位置為:Locale.CHINA,這時ResourceBundelMessageSource會從messages_zh_CN.properties中尋找對應的鍵值兜辞。
當給出Locale參數(shù)值為null迎瞧,空的區(qū)域信息;或者對應的properties文件中沒有找到對應的鍵值對逸吵,那么ResourceBundelMessageSource默認會從messages.properties中尋找鍵凶硅,當都找不到的時候,會返回空字符串扫皱。

三足绅、SpringMVC使用國際化

裝配到代碼中

有了上面的配置,只要使用:

@Autowired
private MessageSource messageSource;

就能將MessageSource注入韩脑。

使用規(guī)范

通常编检,我們都會在ControllerControllerAdvice中進行使用扰才,最好不在Service中使用允懂,這樣統(tǒng)一開發(fā)規(guī)范,Service可以返回properties相對應的key給上層衩匣,由Controller層統(tǒng)一處理蕾总。
這種做法的原因是在遇到拋異常給統(tǒng)一異常處理ControllerAdvice下的ExceptionHandler)時,異常處理能正確獲取到對應的信息琅捏。

簡化使用

上面的使用例子中生百,使用:

messageSource.getMessage("hello", null, "", null)

用了4個參數(shù),這4個參數(shù)對應的都是地理位置等信息柄延,但這類參數(shù)每次在Controller調(diào)用的時候都要放一遍蚀浆,確實很不方便,因為我們只要傳進的是key搜吧。
我們可以考慮讓包裝一個類去屏蔽這些參數(shù)市俊。
當然,下面的例子是忽略地理位置信息的滤奈,如果需要帶上地理位置信息摆昧,可以考慮使用攔截器方式通過前端傳回語言信息,再去對應的地方拿對應的信息蜒程。

@Component
public class MessageSourceUtil {

    @Autowired
    private MessageSource messageSource;

    public String getMessage(String code) {
        return getMessage(code, null);
    }

    public String getMessage(String code, Object[] args) {
        return getMessage(code, args, "");
    }

    public String getMessage(String code, Object[] args, String defaultMsg) {
        //這里使用比較方便的方法绅你,不依賴request.
        Locale locale = LocaleContextHolder.getLocale();
        return messageSource.getMessage(code, args, defaultMsg, locale);
    }

}

上面使用@Component注解來指定該類是組件伺帘,這樣講就能直接在Controller層中使用:

@Autowired
private MessageSourceUtil messageSourceUtil;

然后使用:

messageSourceUtil.getMessage(String);

可以看到我們使用的是LocaleContextHolder.getLocale();來處理locale位置參數(shù),這里指定的是服務器的位置忌锯。與客戶地理位置誤關伪嫁。如果需要根據(jù)客戶不同位置,可以使用攔截器方式偶垮,請求的時候帶上位置信息(最好放在header)礼殊,然后在攔截器中獲取,帶參數(shù)到這里针史。當然,上面的類中LocaleContextHolder也需要做對應的修改碟狞。

使用例子

在Controller中使用

@RestController
@RequestMapping("/")
public class BaseController {

    @Autowired
    private MessageSourceUtil messageSourceUtil;

    /**
     * Ping一下啄枕,神清氣爽
     *
     * @param str
     * @return
     */
    @RequestMapping("/ping")
    public ResponseEntity ping(String str) {
        return ResponseEntity.ok(messageSourceUtil.getMessage(str));
    }
}

在全局異常處理中使用

@ControllerAdvice
public class ExceptionHandlerUtil {
    @Autowired
    private MessageSourceUtil messageSourceUtil;

    /**
     * 全局處理業(yè)務的異常
     * 通過{@link MessageUtil}直接返回Service中拋出的信息
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity handleBussinessException(Exception ex) {
        return ResponseEntity.badRequest().body(messageSourceUtil.getMessage(ex.getMessage()));
    }
}

最后:版權(quán)聲明

本文允許轉(zhuǎn)載,轉(zhuǎn)載本文時請加上本文鏈接:
https://blog.csdn.net/nthack5730/article/details/82870368
http://www.reibang.com/p/a354d3f849ec
對于爬蟲網(wǎng)站隨意爬取以及轉(zhuǎn)載不加原文鏈接的族沃,本人保留追究法律責任的權(quán)力频祝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市脆淹,隨后出現(xiàn)的幾起案子常空,更是在濱河造成了極大的恐慌,老刑警劉巖颜说,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件儒将,死亡現(xiàn)場離奇詭異闹丐,居然都是意外死亡,警方通過查閱死者的電腦和手機昆禽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蝇庭,“玉大人醉鳖,你說我怎么就攤上這事∠冢” “怎么了盗棵?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長北发。 經(jīng)常有香客問我纹因,道長,這世上最難降的妖魔是什么琳拨? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任辐怕,我火速辦了婚禮,結(jié)果婚禮上从绘,老公的妹妹穿的比我還像新娘寄疏。我一直安慰自己是牢,他們只是感情好,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布陕截。 她就那樣靜靜地躺著驳棱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪农曲。 梳的紋絲不亂的頭發(fā)上社搅,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音乳规,去河邊找鬼形葬。 笑死,一個胖子當著我的面吹牛暮的,可吹牛的內(nèi)容都是我干的笙以。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼冻辩,長吁一口氣:“原來是場噩夢啊……” “哼猖腕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起恨闪,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤倘感,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后咙咽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體老玛,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年钧敞,在試婚紗的時候發(fā)現(xiàn)自己被綠了逻炊。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡犁享,死狀恐怖余素,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情炊昆,我是刑警寧澤桨吊,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站凤巨,受9級特大地震影響视乐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜敢茁,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一佑淀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧彰檬,春花似錦伸刃、人聲如沸谎砾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽景图。三九已至,卻和暖如春碉哑,著一層夾襖步出監(jiān)牢的瞬間挚币,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工扣典, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留妆毕,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓贮尖,卻偏偏與公主長得像笛粘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子远舅,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354