一、背景
- 項目過程中,難免需要提示中文或者英文提示信息,有了國際化,方便切換;
- 實際項目中,一般都不允許直接把中文提示信息寫在代碼中,避免其他國家程序猿看不懂(國際化公司和開源項目涉及),也容易招來其他國家的惡意攻擊。比如菊花公司把中文寫在代碼中就算成非常嚴重的違規。
二、目標
- 在項目中引入簡單易用的國際化框架,方便同事使用。
三、步驟
- Java SDK自帶國際化API:java.util.ResourceBundle,使用也特別簡單,目前就選定使用它;
- 對應的國際化資源目錄結構如下:
說明下:我這裏是採用maven作爲代碼構建工具,資源默認路徑是在src/main/resources,編譯後對應路徑爲$bin/classes目錄。$bin表示代碼生成class的根路徑。$bin在maven中實際默認爲:與src同級的target目錄。 - 瞭解了下ResourceBundle的用法,編寫測試類:
import org.junit.Test;
import java.io.UnsupportedEncodingException;
import java.util.Locale;
import java.util.ResourceBundle;
import static org.junit.Assert.assertTrue;
public class I18nTest
{
@Test
public void testI18n() throws UnsupportedEncodingException
{
Locale locale = Locale.getDefault();
System.out.println("current locale:" + locale.toString());
ResourceBundle bundle = ResourceBundle.getBundle("i18n/tips", locale);
String msg = bundle.getString("test.failed");
System.out.println("current msg:" + msg);
assertTrue(null != msg);
}
}
其中ResourceBundle.getBundle的第一個參數叫baseName,就是相對於classes目錄的文件路徑,因爲涉及國際化,所以不能帶上國家(區域)後綴,也不需要帶上porperties這個文件類型後綴。記住baseName是相對路徑,不要在i18n/tips前面加上‘/’。
4. 國家(區域)後綴有標準的定義。也有網友總結的參照表。
5. 執行上述測試代碼過程中,發現輸入中文時,會出現亂碼。原因:IDE工具默認的字符編碼不是UTF-8。建議把IDE的所有文件類型編碼都設置成UTF-8,同時設置properties內容轉換爲ASCII碼。我使用的是IDEA,設置如下:
6. 設置後,會發現tips_zh_CN.properties中文展示如下:
7. 再次執行,亂碼消失了。
8. 驗證通過後,封裝對應的工具類:
public final class I18nUtils
{
/**
* 獲取國際化值
*
* @param key
* @return
*/
public static String get(String key)
{
String value = BUNDLE.getString(key);
if (StringUtils.isEmpty(value))
{
value = StringUtils.EMPTY;
}
LOGGER.info("i18n:[{}]={}", key, value);
return value;
}
private static final Logger LOGGER = LogManager.getLogger(I18nUtils.class);
//國際化文件路徑
private static final String I18N_FILE = "i18n/tips";
//國際化bundle
private static ResourceBundle BUNDLE;
static
{
BUNDLE = ResourceBundle.getBundle(I18N_FILE, Locale.getDefault());
}
private I18nUtils()
{
}
}
- 在springboot框架下使用該工具類給頁面返回中文結果時,發現還是存在亂碼。springboot的application.properties編碼配置如下:
server.tomcat.uri-encoding=UTF-8
spring.banner.charset=UTF-8
spring.messages.encoding=UTF-8
spring.http.encoding.charset=UTF-8
spring.http.encoding.force=true
spring.http.encoding.enabled=true
給前臺返回結果的代碼(過濾器)如下:
Writer writer = response.getWriter();
String failedMsg = I18nUtils.get(“test.failed”);
String failedJson = JsonUtils.toJson(failedMsg);
writer.write(failedJson);
writer.flush();
- 剛開始考慮還有沒有什麼編碼設置給遺漏了,包括是不是springboot集成的springmvc部件沒有指定編碼,結果發現根本不起作用。後面只能懷疑是response響應數據時,沒有指定編碼。
- 在上述代碼前加上ContentType設置(“application/json;utf-8”):
response.setContentType(ContentType.APPLICATION_JSON.toString());
問題解決。
四、總結
- 在這麼多年的Java Web項目中,碰到了很多次亂碼的問題,而且每次問題都還不一樣,解決方案也不一樣T_T;
- Java自帶的國際化工具比想象的好用;
- 網上關於Java自帶國際化的使用大多隻說了部分問題和部分代碼,基本上沒有看到像我這樣完整寫出來的,希望對你有幫助;