Java Web國際化及亂碼解決方案

一、背景

  1. 項目過程中,難免需要提示中文或者英文提示信息,有了國際化,方便切換;
  2. 實際項目中,一般都不允許直接把中文提示信息寫在代碼中,避免其他國家程序猿看不懂(國際化公司和開源項目涉及),也容易招來其他國家的惡意攻擊。比如菊花公司把中文寫在代碼中就算成非常嚴重的違規。

二、目標

  1. 在項目中引入簡單易用的國際化框架,方便同事使用。

三、步驟

  1. Java SDK自帶國際化API:java.util.ResourceBundle,使用也特別簡單,目前就選定使用它;
  2. 對應的國際化資源目錄結構如下:
    國際化截圖
    說明下:我這裏是採用maven作爲代碼構建工具,資源默認路徑是在src/main/resources,編譯後對應路徑爲$bin/classes目錄。$bin表示代碼生成class的根路徑。$bin在maven中實際默認爲:與src同級的target目錄。
  3. 瞭解了下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,設置如下:
properties編碼設置
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()
    {
    }
} 
  1. 在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();
  1. 剛開始考慮還有沒有什麼編碼設置給遺漏了,包括是不是springboot集成的springmvc部件沒有指定編碼,結果發現根本不起作用。後面只能懷疑是response響應數據時,沒有指定編碼。
  2. 在上述代碼前加上ContentType設置(“application/json;utf-8”):
            response.setContentType(ContentType.APPLICATION_JSON.toString());

問題解決。

四、總結

  1. 在這麼多年的Java Web項目中,碰到了很多次亂碼的問題,而且每次問題都還不一樣,解決方案也不一樣T_T;
  2. Java自帶的國際化工具比想象的好用;
  3. 網上關於Java自帶國際化的使用大多隻說了部分問題和部分代碼,基本上沒有看到像我這樣完整寫出來的,希望對你有幫助;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章