一、背景
- 项目过程中,难免需要提示中文或者英文提示信息,有了国际化,方便切换;
- 实际项目中,一般都不允许直接把中文提示信息写在代码中,避免其他国家程序猿看不懂(国际化公司和开源项目涉及),也容易招来其他国家的恶意攻击。比如菊花公司把中文写在代码中就算成非常严重的违规。
二、目标
- 在项目中引入简单易用的国际化框架,方便同事使用。
三、步骤
- 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前面加上‘/’。
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自带的国际化工具比想象的好用;