flea-common使用之本地国际化实现
Posted Huazie
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了flea-common使用之本地国际化实现相关的知识,希望对你有一定的参考价值。
本地国际化实现 — Flea I18N
百度百科针对 国际化 的解释:
本地国际化,就是指应用程序根据所处语言环境的不同【如 Java 中可用 国际化标识类 java.util.Locale
区分不同语言环境】,自动匹配应用内置的相应的语言环境下的资源配置【如 Java 中可用 资源包类 java.util.ResourceBundle
来匹配】,从而获取并对外展示相应的语言环境下的资源信息。
话不多说,直接上干货:
1. 依赖
<!-- FLEA COMMON-->
<dependency>
<groupId>com.huazie.fleaframework</groupId>
<artifactId>flea-common</artifactId>
<version>2.0.0</version>
</dependency>
2. 实现
上面提到了 Java 中 的 国际化标识类 java.util.Locale
和 资源包类 java.util.ResourceBundle
,这两者就是本地国际化实现的关键所在。
2.1 定义国际化资源相关配置 — flea-config.xml
这里用于特殊配置国际化资源的路径和文件前缀。
<flea-config>
<!-- flea-common -->
<config-items key="flea-i18n-config" desc="Flea国际化相关配置">
<config-item key="error" desc="error国际化资源特殊配置,指定路径和文件前缀,逗号分隔">flea/i18n,flea_i18n</config-item>
</config-items>
</flea-config>
2.2 定义Flea I18N 配置类 — FleaI18nConfig
在使用 FleaI18nConfig 之前,我们先了解下Flea国际化资源文件的组成,主要有如下 5 部分:
上述国际化资源也可以配置默认资源文件,即文件名中不需要包含国际化标识 。例如: flea/i18n/flea_i18n_error.properties
注意: 国际化资源文件扩展名必须为 properties
好了,基础的认知有了,我们开始了解 FleaI18nConfig,如下贴出了实现:
/**
* Flea I18N 配置类,用于获取指定语言环境下的指定资源对应的国际化数据。
*
* <p> 它默认读取资源路径为 flea/i18n,资源文件前缀为 flea_i18n,当然
* 也可以在 flea-config.xml 中为指定资源文件配置路径和前缀,从而可以
* 实现读取任意位置的资源数据。
*
* @author huazie
* @version 2.0.0
* @since 1.0.0
*/
public class FleaI18nConfig
private static final FleaLogger LOGGER = FleaLoggerProxy.getProxyInstance(FleaI18nConfig.class);
private static volatile FleaI18nConfig config;
private ConcurrentMap<String, String> resFilePath = new ConcurrentHashMap<>(); // 资源文件路径集
private ConcurrentMap<String, ResourceBundle> resources = new ConcurrentHashMap<>(); // 资源集
/**
* 只允许通过 getConfig() 获取 Flea I18N 配置类实例
*/
private FleaI18nConfig()
init(); // 初始化资源文件相关配置
/**
* 获取 Flea I18N 配置类实例
*
* @return Flea I18N 配置类实例
* @since 1.0.0
*/
public static FleaI18nConfig getConfig()
if (ObjectUtils.isEmpty(config))
synchronized (FleaI18nConfig.class)
if (ObjectUtils.isEmpty(config))
config = new FleaI18nConfig();
return config;
/**
* 初始化资源名和资源文件相关属性的映射关系
*
* @since 1.0.0
*/
private void init()
ConfigItems fleaI18nItems = FleaConfigManager.getConfigItems(CommonConstants.FleaI18NConstants.FLEA_I18N_CONFIG_ITEMS_KEY);
if (ObjectUtils.isNotEmpty(fleaI18nItems) && CollectionUtils.isNotEmpty(fleaI18nItems.getConfigItemList()))
for (ConfigItem configItem : fleaI18nItems.getConfigItemList())
if (ObjectUtils.isNotEmpty(configItem) && StringUtils.isNotBlank(configItem.getKey()) && StringUtils.isNotBlank(configItem.getValue()))
String[] valueArr = StringUtils.split(configItem.getValue(), CommonConstants.SymbolConstants.COMMA);
if (ArrayUtils.isNotEmpty(valueArr) && CommonConstants.NumeralConstants.INT_TWO == valueArr.length)
// 获取资源文件路径
String filePath = StringUtils.trim(valueArr[0]);
// 获取资源文件前缀
String fileNamePrefix = StringUtils.trim(valueArr[1]);
if (StringUtils.isNotBlank(filePath) && StringUtils.isNotBlank(fileNamePrefix))
String configResFilePath;
// 如果资源文件路径最后没有 "/",自动添加
if (CommonConstants.SymbolConstants.SLASH.equals(StringUtils.subStrLast(filePath, 1)))
configResFilePath = filePath + fileNamePrefix;
else
configResFilePath = filePath + CommonConstants.SymbolConstants.SLASH + fileNamePrefix;
resFilePath.put(configItem.getKey(), configResFilePath);
// 添加默认资源文件路径
String defaultResFilePath = CommonConstants.FleaI18NConstants.FLEA_I18N_FILE_PATH +
CommonConstants.FleaI18NConstants.FLEA_I18N_FILE_NAME_PREFIX; // 默认资源文件路径(仅包含公共的部分)
resFilePath.put(CommonConstants.SymbolConstants.ASTERISK, defaultResFilePath);
/**
* 通过国际化数据的key,获取当前系统指定资源的国际化资源;
* 其中国际化资源中使用 标记的,需要values中的数据替换。
*
* @param key 国际化资源KEY
* @param values 待替换字符串数组
* @param resName 资源名
* @param locale 国际化标识
* @return 国际化资源数据
* @since 2.0.0
*/
public FleaI18nData getI18NData(String key, String[] values, String resName, Locale locale)
return new FleaI18nData(key, this.getI18NDataValue(key, values, resName, locale));
/**
* 通过国际化数据的key,获取当前系统指定资源的国际化资源
*
* @param key 国际化资源KEY
* @param resName 资源名
* @param locale 国际化标识
* @return 国际化资源数据
* @since 1.0.0
*/
public FleaI18nData getI18NData(String key, String resName, Locale locale)
return new FleaI18nData(key, this.getI18NDataValue(key, resName, locale));
/**
* <p> 通过国际化数据的key,获取当前系统指定资源的国际化资源数据 </p>
*
* @param key 国际化资源KEY
* @param values 国际化资源数据替换内容
* @param resName 资源名
* @param locale 国际化标识
* @return 国际化资源数据
* @since 1.0.0
*/
public String getI18NDataValue(String key, String[] values, String resName, Locale locale)
String value = getI18NDataValue(key, resName, locale);
if (ArrayUtils.isNotEmpty(values))
StringBuilder builder = new StringBuilder(value);
for (int i = 0; i < values.length; i++)
StringUtils.replace(builder, CommonConstants.SymbolConstants.LEFT_CURLY_BRACE + i + CommonConstants.SymbolConstants.RIGHT_CURLY_BRACE, values[i]);
value = builder.toString();
return value;
/**
* <p> 通过国际化数据的key,获取当前系统指定资源的国际化资源数据 </p>
*
* @param key 国际化资源KEY
* @param resName 资源名
* @param locale 国际化标识
* @return 国际化资源数据
* @since 1.0.0
*/
public String getI18NDataValue(String key, String resName, Locale locale)
Object obj = null;
if (LOGGER.isDebugEnabled())
obj = new Object()
;
LOGGER.debug1(obj, "Find the key : ", key);
LOGGER.debug1(obj, "Find the resName : ", resName);
LOGGER.debug1(obj, "Find the locale : , ", locale == null ? Locale.getDefault() : locale, locale == null ? Locale.getDefault().getDisplayLanguage() : locale.getDisplayLanguage());
ResourceBundle resource = getResourceBundle(resName, locale);
String value = null;
if (ObjectUtils.isNotEmpty(resource))
value = resource.getString(key);
if (StringUtils.isBlank(value)) // 如果取不到数据,则使用key返回
value = key;
if (LOGGER.isDebugEnabled())
LOGGER.debug1(obj, "Find the value : ", value);
return value;
/**
* <p> 根据资源名和国际化标识获取指定国际化配置ResourceBundle对象 </p>
*
* @param resName 资源名
* @param locale 国际化标识
* @return 国际化配置ResourceBundle对象
* @since 1.0.0
*/
private ResourceBundle getResourceBundle(String resName, Locale locale)
String key = generateKey(resName, locale);
Object obj = null;
if (LOGGER.isDebugEnabled())
obj = new Object()
;
LOGGER.debug1(obj, "Find the resKey : ", key);
ResourceBundle resource = resources.get(key);
// 获取资源文件名
StringBuilder fileName = new StringBuilder(getResFilePath(resName));
if (StringUtils.isNotBlank(resName))
fileName.append(CommonConstants.SymbolConstants.UNDERLINE).append(resName);
if (LOGGER.isDebugEnabled())
if (ObjectUtils.isEmpty(locale))
LOGGER.debug1(obj, "Find the expected fileName: .properties", fileName);
else
LOGGER.debug1(obj, "Find the expected fileName: _.properties", fileName, locale);
// 获取资源文件
if (ObjectUtils.isEmpty(resource))
if (ObjectUtils.isEmpty(locale))
resource = ResourceBundle.getBundle(fileName.toString());
else
resource = ResourceBundle.getBundle(fileName.toString(), locale);
resources.put(key, resource);
if (LOGGER.isDebugEnabled())
Locale realLocale = resource.getLocale();
if (ObjectUtils.isEmpty(locale) || StringUtils.isBlank(realLocale.toString()))
LOGGER.debug1(obj, "Find the real fileName: .properties", fileName);
else
LOGGER.debug1(obj, "Find the real fileName: _.properties", fileName, realLocale);
return resource;
/**
* <p> 获取国际化资源文件KEY </p>
* <p> 如果资源名不为空,则资源名作为key,同时如果国际化标识不为空,则取资源名+下划线+国际化语言作为key;
*
* @param resName 资源名
* @param locale 国际化标识
* @return 国际化资源文件KEY
* @since 1.0.0
*/
private String generateKey(String resName, Locale locale)
String key = "";
if (StringUtils.isNotBlank(resName))
key = resName;
if (ObjectUtils.isNotEmpty(locale))
key += CommonConstants.SymbolConstants.UNDERLINE + locale;
return key;
/**
* <p> 根据资源名,获取资源文件路径 </p>
*
* @param resName 资源名
* @return 资源文件路径
* @since 1.0.0
*/
private String getResFilePath(String resName)
// 首先根据资源名,从 资源文件路径集中获取
String resFilePathStr = resFilePath.get(resName);
if (ObjectUtils.isEmpty(resFilePathStr))
// 取默认资源文件路径
resFilePathStr = resFilePath.get(CommonConstants.SymbolConstants.ASTERISK);
return resFilePathStr;
2.3 定义Flea I18N 工具类 — FleaI18nHelper
Flea I18N 工具类 封装了 I18N 资源数据获取的静态方法,主要包含如下4种:
public static String i18n(String key, String resName, Locale locale)
return FleaI18nConfig.getConfig().getI18NDataValue(key, resName, locale);
public static String i18n(String key, String[] values, String resName, Locale locale)
return FleaI18nConfig.getConfig().getI18NDataValue(key, values, resName, locale);
// 实际在调用该方法之前,可以通过 FleaFrameManager.getManager().setLocale(Locale) 设置当前线程的国际化标识。
public static String i18n(String key, String resName)
return i18n(key, resName, FleaFrameManager.getManager().getLocale());
// 实际在调用该方法之前,可以通过 FleaFrameManager.getManager().setLocale(Locale) 设置当前线程的国际化标识。
public static String i18n(String key, String[] values, String resName)
return i18n(key, values, resName, FleaFrameManager.getManager().getLocale());
// 其他是对具体资源的封装,如错误码资源error、授权资源auth 和 公共信息资源common
2.4 定义Flea I18N资源枚举 — FleaI18nResEnum
/**
* Flea I18N 资源枚举
*
* @author huazie
* @version 1.0.0
* @since 1.0.0
*/
public enum FleaI18nResEnum
ERROR("error", "异常信息国际码资源文件类型"),
ERROR_CORE("error_core", "FLEA CORE异常信息国际码资源文件类型"),
ERROR_DB("error_db", "FLEA DB异常信息国际码资源文件类型"),
ERROR_JERSEY("error_jersey", "FLEA JERSEY异常信息国际码资源文件类型"),
ERROR_AUTH("error_auth", "FLEA AUTH异常信息国际码资源文件类型"),
AUTH("auth", "FLEA AUTH 国际码资源文件类型"),
COMMON("common", "公共信息国际码资源文件类型");
private String resName;
private String resDesc;
/**
* <p> 资源文件类型枚举构造方法 </p>
*
* @param resName 资源名
* @param resDesc 资源描述
* @since 1.0.0
*/
FleaI18nResEnum(String resName, String resDesc)
this.resName = resName;
this.resDesc = resDesc;
public String getResName()
return resName;
public String getResDesc()
return resDesc;
简单的介绍之后,初步了解了本地国际化的实现,下面就需要来实际测试一下了。
话不多说,开始操刀:
3. 自测
首先,我们先添加几个国际化配置文件,如下: