SpringBoot項目中實現返回結果和枚舉類的國際化

前言

什麼是國際化呢?國際慣例,來時來一段官方介紹:

國際化(internationalization)是設計和製造容易適應不同區域要求的產品的一種方式。它要求從產品中抽離所有地域語言,國家/地區和文化相關的元素。換言之,應用程序的功能和代碼設計考慮在不同地區運行的需要,其代碼簡化了不同本地版本的生產。開發這樣的程序的過程,就稱為國際化。

在我們實際開發中,一個web應用可能要在多個地區使用,面對不同地區的不同語言,為了適應不同的用戶,我們可以嘗試在前端頁面實現多語言的支持,那麼同樣對於後端返回的一些提示信息,異常信息等,我們後端也可以根據不同的語言環境來進行國際化處理,返回相應的信息。

開發工具

IDEA、Maven、SpringBoot2.0.5、Jdk1.8、google瀏覽器

SpringBoot中的國際化

原理:

想要使應用支持國際化,首先需要知道用戶的語言環境,即用戶想要看到的語言,我們設想在用戶每次請求時告訴服務器自己的語言環境,服務器收到請求後,根據不同的語言環境返回不同的信息來實現國際化。在spring應用中,用戶的語言環境是通過區域解析器來識別的,而區域解析器有分為好幾種(後面詳細說),在我們不做配置修改時,spring使用AcceptHeaderLocaleResolver作為默認的區域解析器,它是根據HTTP請求 Header中的Accept-language的值來解析,當然區域解析器我們也可以自定義配置。

springboot默認就支持國際化。我們只需要只需要作相應的配置即可。

1.首先你需要一個springboot項目。IDEA中分分鐘創建好一個項目。

2.在resources下定義國際化配置文件,注意名稱必須以messages開始。(在springboot中,當我們不修改配置時默認去解析名稱以message開始的properties文件)

messages.properties (默認環境,無法確定語言環境時,解析該文件中的相應信息)

messages_zh_CN.properties(中文語言環境時,解析該文件中的相應信息)

messages_en_US.properties(英文語言環境時,解析該文件中的相應信息)

在三個配置文件中分別以Key = Value形式存儲如下三條信息,如下:

welcome = 這是一個支持國際化的項目。

welcome = 這是一個支持國際化的項目。


welcome = This is a project supporting internationalization.

3.創建thymeleaf頁面

加入thymeleaf依賴

<dependency> <groupid>org.springframework.boot/<groupid> <artifactid>spring-boot-starter-thymeleaf/<artifactid>

在resources/templates目錄下創建hello.html頁面:

嘗試在不同的語言環境下,通過#{welcome}獲取信息

<title>demo/<title>

<label>

4.創建訪問頁面的controller

注意這裡controller的註解時@Controller

import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;/** * 描述: * * @author zhengql * @date 2018/9/25 19:28 */@Controllerpublic class BaseController { @RequestMapping("/hi") public String hello() { return "/hello"; }}

測試國際化效果

這裡使用google瀏覽器進行測試,測試之前需要安裝插件Language Switcher

Language Switcher : 可以改變當前請求的語言環境(根據自己的選擇)

啟動我們的springboot項目,google瀏覽器訪問 http://127.0.0.1:8080/hi ,可以看到如下頁面:

通過Language Switcher切換語言環境為English - United States,重新訪問 http://127.0.0.1:8080/hi ,可以看到如下頁面:

ok,大功告成,到此一個簡單的國際化項目就完成了。

擴展國際化

通過上面的小栗子,我們可以看到一個簡單的國際化使用,但是在開發中中還需要我們進行一定的配置,來滿足我們不同情況下的使用。

在返回結果中獲取國際化信息

很多時候,後端接收到一個請求後,需要返回一個提示信息,而此時我們可以使這個返回信息支持國際化

這裡就用到了org.springframework.context.MessageSource接口,MessageSource提供了三個方法

@Nullable//參數字段可為空

String getMessage(String var1, @Nullable Object[] var2, @Nullable String var3, Locale var4);String getMessage(String var1, @Nullable Object[] var2, Locale var3) throws NoSuchMessageException;String getMessage(MessageSourceResolvable var1, Locale var2) throws NoSuchMessageException;

String getMessage(String var1, @Nullable Object[] var2, @Nullable String var3, Locale var4):用來從MessageSource獲取消息的基本方法。如果在指定的locale中沒有找到消息,則使用默認的消息。var2中的參數將使用標準類庫中的MessageFormat來作消息中替換值。

String getMessage(String code, Object[] args, Locale loc):本質上和上一個方法相同,其區別在:沒有指定默認值,如果沒找到消息,會拋出一個NoSuchMessageException異常。

String getMessage(MessageSourceResolvable resolvable, Locale locale):上面方法中所使用的屬性都封裝到一個MessageSourceResolvable實現中,而本方法可以指定MessageSourceResolvable實現。

下面我們實踐一下:

1.創建一個以json返回格式的controller,注入MessageSource,注意controller的註解為@RestController

在這裡首先我們需要獲取到當前請求的Locale,有兩種方法:

Locale locale = LocaleContextHolder.getLocale();Locale locale = RequestContextUtils.getLocale(request);

兩種方式根據情況選擇使用,下面是controller代碼

package com.example.i18n.controller;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.MessageSource;import org.springframework.context.i18n.LocaleContextHolder;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * 描述: * * @author zhengql * @date 2018/9/21 10:54 */@RestControllerpublic class JsonController { @Autowired private MessageSource messageSource; @RequestMapping("/ha") public String ha() { return messageSource.getMessage("welcome", null, LocaleContextHolder.getLocale()); }}

2.啟動項目訪問 http://127.0.0.1:8080/ha ,可以看到相應語言環境的返回信息

通過Language Switcher切換語言環境為English - United States,重新訪問http://127.0.0.1:8080/ha,可以看到如下頁面:

支持佔位符國際化信息返回

我們經常會遇到這樣一個場景,登錄賬號需要驗證碼,填寫完手機號獲取驗證碼後會收到一條類似於尊敬的用戶13099999999您好,您的驗證碼是6666,這種信息,其實就是一個模板,通過改變參數,重複使用。我們通過國際化資源文件中的佔位符,配合MessageSource提供的api也可以實現。

資源文件中加入如下屬性:

messages.properties,messages_zh_CN.properties

hello=你好:{0} , 你的驗證碼為 :{1}

messages_en_US.properties

hello=Hello: {0}, your verification code is: {1}

我們在JsonController中,創建一個測試接口

@RequestMapping("/haha") public String haha() { return messageSource.getMessage("hello", new Object[]{"zhangsan","123456"}, LocaleContextHolder.getLocale()); }

啟動項目直接,訪問 http://127.0.0.1:8080/haha 可以看到相應語言環境的返回信息

通過Language Switcher切換語言環境為English - United States,重新訪問 http://127.0.0.1:8080/haha ,可以看到如下頁面:

支持國際化的枚舉類

既然返回信息可以實現國際化,那我們的枚舉類同樣也可以實現國際化咯

創建一個枚舉類EnumSuccessOrError.java

/** * 描述:枚舉類舉例 * * @author zhengql * @date 2018/9/26 20:52 */public enum EnumSuccessOrError { SUCCESS(0, "操作成功"), ERROR(1, "操作失敗"); /** * 返回狀態碼 */ private int statusCode; /** * 返回狀態信息 */ private String statusMsg; EnumSuccessOrError(int statusCode, String statusMsg) { this.statusCode = statusCode; this.statusMsg = statusMsg; } /** * @return the statusCode */ public int getStatusCode() { return statusCode; } /** * @return the statusMsg */ public String getStatusMsg() { return statusMsg; }}

如上,剛剛創建的枚舉類是不支持國際化的,我們呢需要改造他,當調用getStatusMsg方法時根據語言環境返回相應的國際化字符串。可以從如下兩個點著手:

getStatusMsg方法改造

資源文件中添加不同語言環境對應的返回值

先在三個資源文件中加入不同環境的返回值:

messages.properties,messages_zh_CN.properties

SUCCESS = 操作成功ERROR = 操作失敗

messages_en_US.properties

SUCCESS=successERROR=error

改造後的枚舉如下:

public enum EnumSuccessOrError { SUCCESS(0, "SUCCESS"), ERROR(1, "ERROR"); /** * 返回狀態碼 */ private int statusCode; /** * 返回狀態信息 */ private String statusMsg; EnumSuccessOrError(int statusCode, String statusMsg) { this.statusCode = statusCode; this.statusMsg = statusMsg; } private MessageSource messageSource; public EnumSuccessOrError setMessageSource(MessageSource messageSource) { this.messageSource = messageSource; return this; } //通過靜態內部類的方式注入bean,並賦值到枚舉中 @Component public static class ReportTypeServiceInjector { @Autowired private MessageSource messageSource; @PostConstruct public void postConstruct() { for (EnumSuccessOrError rt : EnumSet.allOf(EnumSuccessOrError.class)) rt.setMessageSource(messageSource); } } /** * @return the statusCode */ public int getStatusCode() { return statusCode; } /** * @return the statusMsg,根據語言環境返回國際化字符串 */ public String getStatusMsg() { return messageSource.getMessage(statusMsg,null,statusMsg, LocaleContextHolder.getLocale()); }

此時我們在JsonController中,再創建一個測試接口

@RequestMapping("/enumDemo") public String enumDemo() { return EnumSuccessOrError.SUCCESS.getStatusMsg(); }

啟動項目直接,訪問 http://127.0.0.1:8080/enumDemo 可以看到相應語言環境的返回信息。