MessageSource接口
MessageSource接口定义如下:
package org.springframework.context;
import java.util.Locale;
import org.springframework.lang.Nullable;
public interface MessageSource {
@Nullable
String getMessage(String code, @Nullable Object[] args, @Nullable String default, Locale loc);
String getMessage(String code, @Nullable Object[] args, Locale loc) throws NoSuchMessageException;
String getMessage(MessageSourceResolvable code, Locale loc) throws NoSuchMessageException;
}
code:配置文件键值
args:配置中的占位符{0}、{1}…的值数组
default:当对应键值不存在时显示的默认值
loc:对应Locale,如Locale.CHINA就是语言
ApplicationContext与MessageSource的关系
ApplicationContext实现了MessageSource接口,我们可以直接通过context实例调用以上方法来实现国际化。
ApplicationContext在加载时与MessageSource相关的代码如下:
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
if (beanFactory.containsLocalBean("messageSource")) {
this.messageSource = (MessageSource)beanFactory.getBean("messageSource", MessageSource.class);
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource)this.messageSource;
if (hms.getParentMessageSource() == null) {
hms.setParentMessageSource(this.getInternalParentMessageSource());
}
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Using MessageSource [" + this.messageSource + "]");
}
} else {
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(this.getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton("messageSource", this.messageSource);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No 'messageSource' bean, using [" + this.messageSource + "]");
}
}
}
该方法在AbstractApplicationContext类中
分析此方法我们知道,ApplicationContext在被加载时会自动搜索容器中是否有名称为messageSource的bean,如果有则加载。如果没有则定义一个空的DelegatingMessageSource类型的MessageSource。
加载MessageSource(Java配置方式)
我们一般通过ResourceBundleMessageSource来加载
package com.yyoo.boot.config;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.ResourceBundleMessageSource;
import java.util.Locale;
@Configuration
@Import({DevConfig.class,TestConfig.class})
@PropertySource({"classpath:test.properties"})
public class AppConfig {
@Bean("messageSource") // 注意名称必须是messageSource
public MessageSource getMessageSource(){
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("message");// i18n文件的名称
messageSource.setDefaultLocale(Locale.US);// 默认语言,如果不设置则为当前系统的语言(建议设置)
return messageSource;
}
}
这里我们使用了我们前面定义的AppConfig类,多定义了一个bean而已。
i18n文件的名称规则为 basename_language_country.properties跟java的国际化要求是一致的。
在resource目录添加如下两个配置文件
message_en_US.properties
message=default message
message_zh_CN.properties
message=中文消息
demo
package com.yyoo.boot.annotation;
import com.yyoo.boot.config.AppConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import java.util.Locale;
public class Demo13 {
@Test
public void test(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
ConfigurableEnvironment environment = context.getEnvironment();
environment.setActiveProfiles("dev");
context.register(AppConfig.class);
context.refresh();
System.out.println(context.getMessage("message",null, Locale.CHINA));
System.out.println(context.getMessage("message",null, Locale.US));
System.out.println(context.getMessage("message",null, Locale.UK));
}
}
结果
中文消息
default message
default message
第一段和第二段分别打印中文和英文消息,第三段我们的Locale是Locale.UK我们配置文件没有message_en_UK.properties所以它会查询默认的message配置,我们在AppConfig中默认配置的Locale.US所以打印出default message。
如果我们使用了配置文件中没有定义的key值,我们示例的方法将会抛出异常。
如果我们使用context.getMessage(“message1”,null,“默认值”, Locale.CHINA)来调用,那么当message1不存在的时候,将会显示“默认值”
在容器管理的Bean中使用MessageSource
ApplicationContext是MessageSource的实现,我们前面提到过通过@Resource注解或@Autowired注解可以直接注入对应的实例。同理我们的MessageSource也可以。
@Resource
private MessageSource messageSource;
message配置中的占位符
message配置中可以使用占位符
message=您好,{0}。今天是{1}
message=Hello {0}, today is {1}
Demo
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
ConfigurableEnvironment environment = context.getEnvironment();
environment.setActiveProfiles("dev");
context.register(AppConfig.class);
context.refresh();
System.out.println(context.getMessage("message",new Object[]{"张三","2021年7月14日 星期三"},"默认值", Locale.CHINA));
System.out.println(context.getMessage("message",new Object[]{"zhangsan","2021/7/14 Wed"},"默认值", Locale.US));