一、背景

  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,设置如下:

java exception 国际化输出 java项目国际化_路径


6. 设置后,会发现tips_zh_CN.properties中文展示如下:

java exception 国际化输出 java项目国际化_路径_02


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自带的国际化工具比想象的好用;