国际化主要是引入了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

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

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

Spring boot国际化的更多相关文章

  1. 玩转spring boot——国际化

    前言 在项目开发中,可能遇到国际化的问题,而支持国际化却是一件很头疼的事.但spring boot给出了一个非常理想和方便的方案. 一.准备工作 pom.xml: <?xml version=& ...

  2. Spring boot 国际化自动加载资源文件问题

    Spring boot 国际化自动加载资源文件问题 最近在做基于Spring boot配置的项目.中间遇到一个国际化资源加载的问题,正常来说只要在application.properties文件中定义 ...

  3. Spring Boot国际化开发实战

    本章将讲解如何在Spring Boot和Thymeleaf中做页面模板国际化的支持,根据系统语言环境或者session中的语言来自动读取不同环境中的文字. 国际化自动配置 Spring Boot中已经 ...

  4. 58. Spring Boot国际化(i18n)【从零开始学Spring Boot】

    国际化(internationalization)是设计和制造容易适应不同区域要求的产品的一种方式.它要求从产品中抽离所有地域语言,国家/地区和文化相关的元素.换言之,应用程序的功能和代码设计考虑在不 ...

  5. Spring Boot国际化支持

    本章将讲解如何在Spring Boot和Thymeleaf中做页面模板国际化的支持,根据系统语言环境或者session中的语言来自动读取不同环境中的文字. 国际化自动配置 Spring Boot中已经 ...

  6. Spring Boot 国际化及点击链接跳转国家语言

    一.国际化 在SpringBoot中已经自动帮我们配置管理国际化资源的组件,所以我们只需要编写代码就可. @Bean @ConfigurationProperties(prefix = "s ...

  7. spring boot 国际化MessageSource

    转自:https://blog.csdn.net/flowingflying/article/details/76358970 spring中ResourceBundleMessageSource的配 ...

  8. spring boot 与 thymeleaf (1): 国际化

    在thymeleaf 里面有个消息表达式: #{...} , 可以借此来实现国际化. 在我使用这个功能的时候, 碰到了一个问题, 按照 JavaEE开发的颠覆者 Spring Boot实战  上面编码 ...

  9. Spring Boot Security 国际化 多语言 i18n 趟过巨坑

    网上很多的spring boot国际化的文章都是正常情况下的使用方法 如果你像我一样用了Spring Security 那么在多语言的时候可能就会遇到一个深渊 Spring Security里面的异常 ...

随机推荐

  1. ACL认证 vs 密码认证

    呼入时需要进行认证:acl IP认证 和 密码认证.  acl 认证优先进行. ACL认证成功: Access Granted.  直接进入 sip_profile>context 进行路由 A ...

  2. python学习第3天

    03 int 十进制与二进制之间的转换04 bool 05 str python中凡是用引号引起来的都是字符串 1,存储相对少量的数据. 2,描述信息. 1,bool str int 三者之间的转换 ...

  3. Golang 类型转换,断言和显式强制转换

    1 前言 类型转换,可以用断言(只能使用在interface{}类型转换成其它类型)和显式类型强制转换(常规是用于基本类型) 2 代码 //graphql-go func(params graphql ...

  4. winfrom里面打印类似小票

    首先在窗体上拖一个printDocument1控件和一个Button按钮,然后双击该控件的PrintPage事件,在事件里面复制下面代码: Pen blackPen = new Pen(Color.B ...

  5. Caffeine缓存

    在本文中,我们来看看 Caffeine — 一个高性能的 Java 缓存库. 缓存和 Map 之间的一个根本区别在于缓存可以回收存储的 item. 回收策略为在指定时间删除哪些对象.此策略直接影响缓存 ...

  6. linux中ping带时间及打印内容到文件

    ping命令就不多说了,-i是时间间隔,-c是ping的次数 这种是每隔30秒ping一次,并在后面显示时间: ping 192.168.30.123 -i 30 | awk '{ print $0& ...

  7. VUE 脚手架项目搭建

    1. 概述 1.1 说明 vue-cli是一个官方发布vue.js项目脚手架,使用vue-cli可以快速创建vue项目.GitHub地址是:https://github.com/vuejs/vue-c ...

  8. Python- 索引 B+数 比如书的目录

    1.索引 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题, 在生产环境中,我们遇到最多的,也是最容易出问题的,还是一些复杂的查询操作, 因此对查询 ...

  9. 彻底搞懂字符集编码:ASCII,Unicode 和 UTF-8

    一.ASCII 码 我们知道,计算机内部,所有信息最终都是一个二进制值.每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte).也就是说,一个 ...

  10. android中的LaunchMode详解----四种加载模式

    Activity有四种加载模式: standard singleTop singleTask singleInstance 配置加载模式的位置在AndroidManifest.xml文件中activi ...