内容简介:Spring对国际化这一块支持还是蛮友好的,上手也是蛮简单,但是加载流程还是需要大家掌握的,不然会少定义一个资源文件会让你莫名其妙的出现一些bug。接下来主要分享一下关于这一块的基本知识。顶层接口一共提供了三个获取信息的方法:在获取对应信息时,里面还有些许流程,我下面将会结合例子来进行说明,得先熟悉下该接口的主要实现类。
前言
Spring对国际化这一块支持还是蛮友好的,上手也是蛮简单,但是加载流程还是需要大家掌握的,不然会少定义一个资源文件会让你莫名其妙的出现一些bug。接下来主要分享一下关于这一块的基本知识。
MessageSource
public interface MessageSource { @Nullable String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale); String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException; String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException; } 复制代码
顶层接口一共提供了三个获取信息的方法:
- 提供默认值
defaultMessage
参数,当根据code
无法从相应的ResourceBundle
中查询出数据时,会将defaultMessage
的值返回。 - 当根据
code
无法从相应的ResourceBundle
中查询出数据时,直接抛出NoSuchMessageException
异常。 - 通过自定义
MessageSourceResolvable
解析器去获取信息,MessageSourceResolvable
也就是封装了code
,args
,defaultMessage
三个参数,用法上并没有什么不同。只不过code参数为String[]
数组形式,通过遍历调用的方式去获取信息,只要其中一个code
能够获取到值,便直接返回。查询不出数据时且defaultMessage
为空时,直接抛出NoSuchMessageException
异常。
在获取对应信息时,里面还有些许流程,我下面将会结合例子来进行说明,得先熟悉下该接口的主要实现类。
从类图结构中可以看出,顶层接口 MessageSource
下面有个抽象类 AbstractMessageSource
,三个基本实现类 ResourceBundleMessageSource
, ReloadableResourceBundleMessageSource
, StaticMessageSource
。
-
ResourceBundleMessageSource
:支持对.properties
的解析,解析完成后也是用map进行封装,最后数据存储在PropertyResourceBundle
的成员变量private Map lookup;
中。 -
ReloadableResourceBundleMessageSource:
可以解析.properties
和.xml
文件,解析完成利用PropertiesHolder
进行封装,底层还是Properties
结构。 -
StaticMessageSource
:这个相对来说最容易理解,内部就是直接用map封装了咱们需要的信息。
以上三个实现类均可以对返回信息做格式化处理。
下面我将拿 ResourceBundleMessageSource
这个类进行分析,先对其几个属性值进行分析一下:
-
alwaysUseMessageFormat
:默认值为false,即默认不对返回信息做格式化处理。 -
useCodeAsDefaultMessage
:默认值为false,设置成true时,当无法通过code
参数返回信息时,会默认将code
的值进行返回。 -
fallbackToSystemLocale
:默认值为true,当根据code
和locale
参数无法获取对应的ResourceBundle
时,会根据当前的环境设置获取defaultLocale
,然后获取对应的ResourceBundle
。
注入spring容器:
可以选择配置文件或者注解的方式进行配置到spring容器中,例如下方的注解方式:
@Bean MessageSource messageSource() { ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource(); resourceBundleMessageSource.setBasename("exception"); resourceBundleMessageSource.setDefaultEncoding("UTF-8"); return resourceBundleMessageSource; } 复制代码
而spring 容器在初始化时,会在 refresh
方法中调用 initMessageSource
方法:
protected void initMessageSource() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) { //从容器中获取name为 "messageSource",类型为MessageSource的bean this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class); if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) { HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource; if (hms.getParentMessageSource() == null) { hms.setParentMessageSource(getInternalParentMessageSource()); } } if (logger.isTraceEnabled()) { logger.trace("Using MessageSource [" + this.messageSource + "]"); } } else { DelegatingMessageSource dms = new DelegatingMessageSource(); dms.setParentMessageSource(getInternalParentMessageSource()); this.messageSource = dms; beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource); if (logger.isTraceEnabled()) { logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]"); } } } 复制代码
上面这段代码逻辑很清晰,先判断当前是否有该bean的BeanDefinition,若存在,则对MessageSource进行初始化并赋值给其成员变量 messageSource
。如果不存在该bean的BeanDefinition,则赋值一个空的MessageSource,也就是DelegatingMessageSource,以便能够正常的进行 getMessage
方法的调用。
具体使用:
有以下两种方式可以获取到容器中的 MessageResource
:
//方式一: @Autowired private MessageSource messageSource; //方式二: @Component public class MessageResourceConfiguration implements MessageSourceAware { private MessageSource messageSource; @Override public void setMessageSource(MessageSource messageSource) { this.messageSource = messageSource; } } 复制代码
PS:其实用 ApplicationContext
也可以, ApplicationContext
实现了 MessageSource
接口,并且在 refresh
方法中也对 messageSource
进行了注入,不熟悉的可以回顾下上面的 注入spring容器 环节。
使用案例:
如下图所示先定义好这三个配置文件(文件名需要和上面定义MessageSource的baseName属性值一致):
exception.properties
我们称之为基类文件,它可以作为 exception_en.properties
和 exception_zh.properties
两种配置文件的父类,联想一下spring的子父容器的概率,相信不难理解。
1.String app = messageSource.getMessage("0000", null, Locale.ENGLISH); //en_exception 2.String app = messageSource.getMessage("0001", null, Locale.ENGLISH); //base_exception 3.String app = messageSource.getMessage("0000", null, Locale.CHINESE); //zh_exception 4.String app = messageSource.getMessage("0000", null, Locale.JAPAN); //zh_exception 复制代码
分别执行这四句代码,出现这个四个结果:
- 能够从
exception_en.properties
中获取”0000“对应的值:en_exception。 - 无法从
exception_en.properties
中获取”0001“对应的值,在其父类exception.properties
中获取对应的值:base_exception。 - 能够从
exception_zh.properties
中获取”0000“对应的值:zh_exception。 - 无法获取
Locale.JAPAN
对应的ResourceBundle
,但由于fallbackToSystemLocale
值默认是true,所以会根据环境设置获取defaultLocale
,然后获取对应的ResourceBundle
。当前环境通过System.getProperty("user.language")
去获取,目前是该值是zh
,所以会从exception_zh.properties
中获取”0000“对应的值:zh_exception。
假设在注入bean时将 fallbackToSystemLocale
改成false:
运行上面的代码,会发现前面三个结果一致,但是最后一个结果有些许变化:
String app = messageSource.getMessage("0000", null, Locale.JAPAN); //exception 复制代码
由于没有匹配到对应国家的 ResourceBundle
,直接从基类文件中获取结果。其实这里直接将 exception_zh.properties
配置文件移除也会获取相同的结果,都会从基类文件中获取。
假设在注入bean时将 useCodeAsDefaultMessage
改成true:
运行代码:
String app = messageSource.getMessage("0003", null, Locale.CHINESE); //0003 复制代码
返回结果为“0003”,正是查询时用的 code
参数。“0003”不存在于咱们的 exception_zh.properties
和 exception.properties
文件对应的 ResourceBundle
中,所以直接将 code
作为默认结果进行返回了。
总结:
对上面的基本流程进行简单的总结,可以分为三步:
- 检测是否有对应
locale
的配置,有的话则从当前locale
配置中读取信息,并且可以追踪到基类文件中。 - 若没有对应
locale
的配置,如果fallbackToSystemLocale
为true
,则获取默认defaultLocale
的配置,并且可以追踪到基类文件中。 - 如果
fallbackToSystemLocale
为false
,则直接到基类文件中获取信息。
目前只是接触到根据不同的国家响应不同的异常状态码,后面会对页面这一块的国际化进行分享一下,SpringMVC也提供有对国际化这一块的支持。测试案例均在 github 中。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Open Data Structures
Pat Morin / AU Press / 2013-6 / USD 29.66
Offered as an introduction to the field of data structures and algorithms, Open Data Structures covers the implementation and analysis of data structures for sequences (lists), queues, priority queues......一起来看看 《Open Data Structures》 这本书的介绍吧!