国际化主要是引入了MessageSource,我们简单看下如何使用,以及其原理。

1.1 设置资源文件

在 properties新建i18n目录

新建message文件:

messages.properties

error.title=Your request cannot be processed

messages_zh_CN.properties

error.title=您的请求无法处理

1.2 配置

修改properties文件的目录:在application.yml或者application.properties中配置 spring.message.basename

spring:
application:
name: test-worklog
messages:
basename: i18n/messages
encoding: UTF-8

1.3 使用

引用自动注解的MessageSource,调用messageSource.getMessage即可,注意,需要通过 LocaleContextHolder.getLocale()获取当前的地区。

@Autowired
private MessageSource messageSource;
/**
* 国际化
*
* @param result
* @return
*/
public String getMessage(String result, Object[] params) {
String message = "";
try {
Locale locale = LocaleContextHolder.getLocale();
message = messageSource.getMessage(result, params, locale);
} catch (Exception e) {
LOGGER.error("parse message error! ", e);
}
return message;
}

如何设置个性化的地区呢? forLanguageTag 即可

 Locale locale = Locale.forLanguageTag(user.getLangKey());

1.4 原理分析

MessageSourceAutoConfiguration中,实现了autoconfig

@Configuration
@ConditionalOnMissingBean(value = MessageSource.class, search = SearchStrategy.CURRENT)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Conditional(ResourceBundleCondition.class)
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "spring.messages")
public class MessageSourceAutoConfiguration {

该类一方面读取配置文件,一方面创建了MessageSource的实例:

@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
if (StringUtils.hasText(this.basename)) {
messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(this.basename)));
}
if (this.encoding != null) {
messageSource.setDefaultEncoding(this.encoding.name());
}
messageSource.setFallbackToSystemLocale(this.fallbackToSystemLocale);
messageSource.setCacheSeconds(this.cacheSeconds);
messageSource.setAlwaysUseMessageFormat(this.alwaysUseMessageFormat);
return messageSource;
}

因此,默认是加载的ResourceBundleMessageSource,该类派生与于AbstractResourceBasedMessageSource

@Override
public final String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
String msg = getMessageInternal(code, args, locale);
if (msg != null) {
return msg;
}
if (defaultMessage == null) {
String fallback = getDefaultMessage(code);
if (fallback != null) {
return fallback;
}
}
return renderDefaultMessage(defaultMessage, args, locale);
}

最终是调用resolveCode来获取message,通过ResourceBundle来获取message

	@Override
protected MessageFormat resolveCode(String code, Locale locale) {
// 遍历语言文件路径
Set<String> basenames = getBasenameSet();
for (String basename : basenames) {
ResourceBundle bundle = getResourceBundle(basename, locale);
if (bundle != null) {
MessageFormat messageFormat = getMessageFormat(bundle, code, locale);
if (messageFormat != null) {
return messageFormat;
}
}
}
return null;
} // 获取ResourceBundle
protected ResourceBundle getResourceBundle(String basename, Locale locale) {
if (getCacheMillis() >= 0) {
// Fresh ResourceBundle.getBundle call in order to let ResourceBundle
// do its native caching, at the expense of more extensive lookup steps.
return doGetBundle(basename, locale);
}
else {
// Cache forever: prefer locale cache over repeated getBundle calls.
synchronized (this.cachedResourceBundles) {
Map<Locale, ResourceBundle> localeMap = this.cachedResourceBundles.get(basename);
if (localeMap != null) {
ResourceBundle bundle = localeMap.get(locale);
if (bundle != null) {
return bundle;
}
}
try {
ResourceBundle bundle = doGetBundle(basename, locale);
if (localeMap == null) {
localeMap = new HashMap<Locale, ResourceBundle>();
this.cachedResourceBundles.put(basename, localeMap);
}
localeMap.put(locale, bundle);
return bundle;
}
catch (MissingResourceException ex) {
if (logger.isWarnEnabled()) {
logger.warn("ResourceBundle [" + basename + "] not found for MessageSource: " + ex.getMessage());
}
// Assume bundle not found
// -> do NOT throw the exception to allow for checking parent message source.
return null;
}
}
}
} // ResourceBundle
protected ResourceBundle doGetBundle(String basename, Locale locale) throws MissingResourceException {
return ResourceBundle.getBundle(basename, locale, getBundleClassLoader(), new MessageSourceControl());
}

最后来看getMessageFormat:

/**
* Return a MessageFormat for the given bundle and code,
* fetching already generated MessageFormats from the cache.
* @param bundle the ResourceBundle to work on
* @param code the message code to retrieve
* @param locale the Locale to use to build the MessageFormat
* @return the resulting MessageFormat, or {@code null} if no message
* defined for the given code
* @throws MissingResourceException if thrown by the ResourceBundle
*/
protected MessageFormat getMessageFormat(ResourceBundle bundle, String code, Locale locale)
throws MissingResourceException { synchronized (this.cachedBundleMessageFormats) {
// 从缓存读取
Map<String, Map<Locale, MessageFormat>> codeMap = this.cachedBundleMessageFormats.get(bundle);
Map<Locale, MessageFormat> localeMap = null;
if (codeMap != null) {
localeMap = codeMap.get(code);
if (localeMap != null) {
MessageFormat result = localeMap.get(locale);
if (result != null) {
return result;
}
}
}
// 缓存miss,从bundle读取
String msg = getStringOrNull(bundle, code);
if (msg != null) {
if (codeMap == null) {
codeMap = new HashMap<String, Map<Locale, MessageFormat>>();
this.cachedBundleMessageFormats.put(bundle, codeMap);
}
if (localeMap == null) {
localeMap = new HashMap<Locale, MessageFormat>();
codeMap.put(code, localeMap);
}
MessageFormat result = createMessageFormat(msg, locale);
localeMap.put(locale, result);
return result;
} return null;
}
}

作者:Jadepeng

出处:jqpeng的技术记事本--http://www.cnblogs.com/xiaoqi

您的支持是对博主最大的鼓励,感谢您的认真阅读。

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

最新文章

  1. iOS在线更新framework,使用NSBundle动态读取
  2. 创建并追加img元素(jquery!)
  3. Oracle - PL/SQL Commands
  4. HDOJ 1754 I Hate It 线段树 第二题
  5. vs 添加坚竖虚线(垂直虚线、肾虚线 by 我的Y韬)
  6. ref和out的使用与区别
  7. java实现时间的比较
  8. C语言学习之笔记
  9. swift 实现漂亮的粒子效果CAEmitterLayer
  10. iOS 系统架构 &amp;&amp; 常用 framework
  11. 【C#基础知识】静态构造函数,来源于一道面试题的理解
  12. SharePoint2013 Excel导出好的代码
  13. java调用控制台命令
  14. java 整型数组基本排序,冒泡,快速选择,插入,归并
  15. vue 2 仿IOS 滚轮选择器 从入门到精通 (一)
  16. 【技术分析】DowginCw病毒家族解析
  17. JavaScript基础视频教程总结(071-080章)
  18. 图论分支-差分约束-SPFA系统
  19. build tool 的简单认知
  20. CH 1602 - The XOR Largest Pair - [字典树变形]

热门文章

  1. 题解-bzoj4061 CERC-2012Farm and Factory
  2. 洛谷 [USACO17OPEN]Bovine Genomics G奶牛基因组(金) ———— 1道骗人的二分+trie树(其实是差分算法)
  3. Delta DVP 系列 PLC 各装置 Modbus 地址
  4. oracle 多行变一行 wmsys.wm_concat
  5. nginx或者squid正向代理实现受限网站的访问
  6. 【原创】Linux基础之Shell脚本常用命令
  7. 【转载】 Eclipse注释模板设置详解
  8. Selenium WebDriver中鼠标事件
  9. Mybaits动态Sql
  10. react 中子组件调用父组件的方法