DispatcherServlet使得开发人员可以通过客户端的Locale来自动转换消息进行国际化;在整个国际化的过程中,主要分成两步,一是解析客户端的Locale,一是查找国际化的消息;
1. 解析Locale
解析Locale是通过LocaleResolver来完成的。
当有请求时,DispatcherServlet查找LocaleResolver类型的Bean,如果找到,则使用它获取并设置Locale。在这之后,通过RequestContext.getLocale方法则可以获取到Locale。
Spring默认在i18n包中提供了几种实现,如通过Cookie、Header、Session等方式来获取Locale的实现等。
1.1 定义所使用的LocaleResolver:
Spring Boot中可以通过Bean注解来定义所使用的LocaleResolver
@Configuration
public class AdditionalBeanConfig {
@Bean
public LocaleResolver getLocalResolver() {
return new CookieLocaleResolver();
默认情况下,SpringBoot中是没有包含LocaleResolver对象的。
1.2 获取Locale
如果需要在应用中获取当前客户端所使在的Locale,在Controller中通过以下方式查找Locale:
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/locale")
public String locale(HttpServletRequest request) {
RequestContext requestContext = new RequestContext(request);
System.out.println(requestContext.getLocale().toLanguageTag());
System.out.println(LocaleContextHolder.getLocale().toLanguageTag());
return RequestContextUtils.getLocale(request).toLanguageTag();
打印及返回的结果为:zh-CN
RequestContext:用于存储请求相关的一些信息,如当前请求的Web上下文、Theme、Locale等;
RequestContextUtils: 使用RequestContext的一个辅助类;提供静态方法来使用RequestContext,这样就不需要手动创建RequestContext对象;
2. 查找消息
查找消息一般通过MessageSource接口进行,它可以根据Code查找消息,同时支持国际化及参数传递。
2.1 MessageSource接口
当不配置任何的MessageSource时,Spring默认使用DelegatingMessageSource,如以下控制器:
@GetMapping("/message")
public String message() {
return messageSource.toString();
请求返回后是:org.springframework.context.support.DelegatingMessageSource@76b6471e
这个时候,我们使用MessageSource来获取Message:
@GetMapping("/message")
public String message(HttpServletRequest request) {
Locale locale = RequestContextUtils.getLocale(request);
return messageSource.getMessage("test", null, locale);
此时会报错,错误信息:
There was an unexpected error (type=Internal Server Error, status=500).
No message found under code 'test' for locale 'zh_CN'.
经过跟踪,这个异常在DelegatingMessageSource的getMessage方法中处理:
@Override
public String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
if (this.parentMessageSource != null) {
return this.parentMessageSource.getMessage(code, args, locale);
else {
throw new NoSuchMessageException(code, locale);
由于parentMessageSource为空,直接抛出异常,即访问接口时看到的消息。
2.2 指定MessageSource
MessageSource包含有以下几个实现类:
- StaticMessageSource: 基于程序注册的方式来管理资源;一般用于测试;
- ResourceBundleMessageSource: 基于JDK中的ResourceBundle实现;
- ReloadableResourceBundleMessageSource:包含运行时动态加载机制的实现;
2.2.1 StaticMessageSource
先使用StaticMessageSource来进行实验:
@Bean
public MessageSource messageSource() {
StaticMessageSource messageSource = new StaticMessageSource();
messageSource.addMessage("test", Locale.CHINA, "测试消息");
return messageSource;
仍旧使用之前的Controller,这时不会报错直接会返回“测试消息”这个串了。
2.2.2 ResourceBundleMessageSource
上面已经说过,StaticMessageSource这种方式一般用于测试当中,在生产中一般使用ResourceBundleMessageSource。
我们将上面使用staticMessageSource的地方进行替换:
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("messages");
return messageSource;
它会去Classpath下的目录中查找名称为mesages开头的国际化文件并进行加载。
在resources目录下添加messages.properties及messages_zh_cn.properties两个文件,并在message_zh_cn.properties中添加test=测试消息 的内容。
执行前面的Controller,可以看到获取到的消息。也可以仅在messages.properties中添加;它会先去对应Locale的文件中查找,如果未找到则去默认的messages.properties中查找;如果仍旧未找到则抛出异常。
有时候resources目录东西过多需要分子目录,可以在定义MessageSource的时候进行指定,如下面在resources下增加子目录i18n:
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("i18n.messages");
return messageSource;
3. 总结
综上,在项目国际化过程中,需要创建LocaleResolver及MessageSource对象并注入到容器中,然后定义相关的国际化属性文件;在文件中定义好相关信息即可在需要使用的地方通过Autowired注入MessageSource对象并使用它来解析国际化消息了。
注意到在每个使用的地方都要传入Locale到MessageSource的方法中,实际上,通过使用LocaleContextHolder可以进行进一步的简化:
@Component
public class MessageSourceProxy {
@Autowired
private MessageSource messageSource;
public String getMessage(String code, Object[] params) {
return messageSource.getMessage(code, params, LocaleContextHolder.getLocale());
然后改造前面的Controller:
@Autowired
private MessageSourceProxy messageSourceProxy;
@GetMapping("/message")
public String message(HttpServletRequest request) {
return messageSourceProxy.getMessage("test", null);
这样简化后,使用者甚至都不用手动去获取Locale了。
本文主要分析国际化的配置过程是怎样完成的,关于MessageSource对象的使用,可以参考具体的API。
DispatcherServlet使得开发人员可以通过客户端的Locale来自动转换消息进行国际化;在整个国际化的过程中,主要分成两步,一是解析客户端的Locale,一是查找国际化的消息;1. 解析Locale解析Locale是通过LocaleResolver来完成的。当有请求时,DispatcherServlet查找LocaleResolver类型的Bean,如果找到,则使用它获...
找不到message文件,该文件的路径为src/main/resources/static/i18n/messages,因操作失误被删除了。
# Spring配置
spring:
# 资源信息
messages:
# 国际化资源文件路径
basename: static/i18n/messages
恢复messag
转自http://www.sandzhang.com/blog/2011/04/07/spring-study-notes-initialization-5/
refresh()方法中在上篇看完了对PostProcessors的处理,这篇继续往下看。
注:refresh()的代码就不再次列举了,请看spring源码中AbstractApplicationContext类。
一、initM
这个错误在网上找了好久,试过许多方法都不行,我的代码也检查了几遍,也和别人的对照过,愣是没有找到,后来脑壳突发奇想的想到一种可能,那就是自己的创建方式有问题,之后也解决了问题,俺在这里记录下。
俺的springmvc.xml相关配置:
<!--国际化-->
<bean id="messageSource" class="org.springframework.contex...
<!--国际化操作拦截器,如果采用基于Session/Cookie则必须配置-->
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
<...
Spring Boot 支持国际化,可以通过配置来实现。下面是一个简单的示例:
1. 在 src/main/resources 目录下创建 i18n 目录,在该目录下创建 messages.properties 文件,并填写需要国际化的文本,例如:
hello=Hello
2. 在 messages.properties 文件所在目录下创建 messages_zh_CN.properties 文件,填写中文翻译,例如:
hello=你好
3. 在 Spring Boot 配置文件 application.properties 中添加如下配置:
spring.mvc.locale=zh_CN
spring.messages.basename=i18n/messages
其中,`spring.mvc.locale` 指定默认语言为中文,`spring.messages.basename` 指定国际化文件的前缀,Spring Boot 会自动加载 messages.properties 和 messages_zh_CN.properties 文件。
4. 在代码中使用国际化文本,例如:
```java
@Controller
public class HelloController {
@Autowired
private MessageSource messageSource;
@RequestMapping("/hello")
@ResponseBody
public String hello(@RequestHeader("Accept-Language") String language) {
Locale locale = LocaleContextHolder.getLocale();
return messageSource.getMessage("hello", null, locale);
在上面的例子中,我们使用 `MessageSource` 接口来获取国际化文本,`LocaleContextHolder.getLocale()` 方法获取当前的语言环境。
5. 启动应用程序,访问 /hello 接口,可以看到返回的文本为:"你好"。
以上就是 Spring Boot 国际化的简单实现方法。