学习SpringMVC国际化(二)

本文主要介绍springMVC中国际化的相关配置

MessageSource

示例:

1
2
3
4
5
6
7
8
@Bean
public ReloadableResourceBundleMessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasenames("classpath:i18n/server");
messageSource.setDefaultEncoding("UTF-8");
messageSource.setFallbackToSystemLocale(false);
return messageSource;
}

SpringBean名称必须是messageSource

ApplicationContext被加载时,会寻找bean名称为messageSource的类,如果没有找到,将会寻找bean父类中相同名称的类,如果还没有找到,将会实例化一个空的DelegatingMessageSource作为使用。

When an ApplicationContext is loaded, it automatically searches for a MessageSource bean defined in the context. The bean must have the name messageSource. If such a bean is found, all calls to the preceding methods are delegated to the message source. If no message source is found, the ApplicationContext attempts to find a parent containing a bean with the same name. If it does, it uses that bean as the MessageSource. If the ApplicationContext cannot find any source for messages, an empty DelegatingMessageSource is instantiated in order to be able to accept calls to the methods defined above.

介绍

MessageSource是Spring中提供国际化的接口,提供了3个方法:

1
2
3
4
5
6
7
8
9
public interface MessageSource {

String getMessage(String code, Object[] args, String defaultMessage, Locale locale);

String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;

String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;

}

其实去看这个接口相关的实现类时,会发现底层都是调用了JDK中MessageFormat类,只是Spring做了封装,并且提供了更多的功能。

Spring提供了两种MessageSource的实现:StaticMessageSourceResourceBundleMessageSource。其中StaticMessageSource很少使用,ResourceBundleMessageSource底层使用的是JDK中ResourceBundle类,所以语言资源文件命名规范以及加载规则都和ResourceBundles相同。

Spring还提供了另外一个更加灵活的类:ReloadableResourceBundleMessageSource
它允许在Spring资源中任何位置加载资源文件,同时支持热加载(修改配置文件之后不用重启服务)。

常用方法

ReloadableResourceBundleMessageSource为例:

设置资源文件路径

1
2
3
messageSource.setBasenames("classpath:i18n/server");
messageSource.setBasename("classpath:i18n/server");

一般使用第一个方法,可以加载不同basename的资源文件

设置编码

1
2
messageSource.setDefaultEncoding("UTF-8");

默认编码为ISO-8859-1

设置默认是否使用系统Locale

1
2
messageSource.setFallbackToSystemLocale(false);

默认为true。如果设置为true,并且找不到对应locale的语言文件,将会使用系统locale的语言文件。例如有语言文件test_en.propertiestest_zh.propertiestest.properties,并且当前系统Locale为Locale.China,此时访问的locale为Locale.FRANCE,如果设置为true,将会使用test_zh.properties,如果设置为false,将会使用test.properties

其他相关设置

1
2
3
4
5
6
7
8
// 默认为false,当不需要占位符替换时,不会调用MessageFormat方法
messageSource.setAlwaysUseMessageFormat(false);

// 默认为false,如果参数code在语言资源中不存在,会抛出异常;如果设置为true,会直接展示code
messageSource.setUseCodeAsDefaultMessage(false);

// 设置缓存时间,单位为秒,默认为-1永久缓存。注意生产环境不要设置为0,设置0表示每次调用都会检查文件的最后更新时间
messageSource.setCacheSeconds(-1);

获取国际化文本

1
2
getMessage(String code, Object[] args, Locale locale);

上面方法基本可以理解为:

1
2
3
1. 调用ResourceBundle.getBundle(String baseName, Locale locale)获取资源文件
2. 调用ResourceBundle.getString(String code)获取国际化文本内容
3. 如果需要占位符替换,调用MessageFormat.format(String pattern, Object ... arguments)

LocaleResolver

LocaleResolver是SpringMVC中设置存储Locale的类

常用方法

setDefaultLocale(Locale locale)

设置默认Locale。当无法取得请求中的Locale信息时,会使用此处设置的Locale

实现类

FixedLocaleResolver

默认使用JVM的Locale,不支持setLocaleContext()方法,用的不多

AcceptHeaderLocaleResolver

从Http请求头中的accept-language检查Locale信息,但是不支持检查时区信息

CookieLocaleResolver

从Cookie从检查是否有Locale信息或者时区信息,支持设置Cookie的名称和过期时间等

SessionLocaleResolver

从Session从检查是否有Locale信息或者时区信息

1
2
3
4
5
6
@Bean
public SessionLocaleResolver localeResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(Locale.ENGLISH); // 设置默认Locale为英语地区,当无法从请求中获取到Locale时使用
return localeResolver;
}

LocaleChangeInterceptor

SpringMVC提供的拦截器,用于处理请求中的Locale信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 拦截器设置
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
// 设置请求参数名为`lang`,如请求参数`lang=en`
localeChangeInterceptor.setParamName("lang");

// 是否忽略不合法的Locale,如请求参数`lang=@12`,如设置为false,将会抛出异常
localeChangeInterceptor.setIgnoreInvalidLocale(true);
return localeChangeInterceptor;
}

// 配置拦截器拦截所有请求
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}