前言
什麼是國際化呢?國際慣例,來時來一段官方介紹:
在我們實際開發中,一個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 = 這是一個支持國際化的項目。
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代碼
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 可以看到相應語言環境的返回信息。