spring core国际化
spring core支持国际化,是其它模块支持国际化的基础,正因为spring core支持国际化,spring mvc才能支持国际化。国际化就是MessageSource接口来实现的。MessageSource是个策略接口,提供了两个开箱即用的实现,ResourceBundleMessageSource和ReloadableResourceBundleMessageSource。ReloadableResourceBundleMessageSource顾名思义,不需要重启JVM就可以重新加载资源文件。
MessageSource
要想理解国际化,只要理解了MessageSource的getMessage方法
String getMessage(String code, Object[] args, Locale locale)
ResourceBundle就是资源文件,比如mylocale_zh_CN.properties、mylocale_zh_TW.properties,注意文件的后缀zh_CN、zh_TW代表地区语言。
mylocale_zh_CN.properties
my.code=爱你
mylocale_zh_TW.properties
my.code=愛你
getMessage(“my.code”,null,地区),如果地区是中国大陆,则返回爱你,如果是中国台湾则是愛你。
spring启动对MessageSource的操作
spring启动时,applicationcontext会寻找MessageSource的bean,如果找到则使用,否则创建DelegatingMessageSource。
所以实现国际化,通常在beans.xml中配置
<!-- 国际化资源文件 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:mylocale" />
<property name="defaultEncoding" value="utf8" />
<property name="useCodeAsDefaultMessage" value="true" />
</bean>
上边的配置会将mylocale文件,当作消息源,getMessage时会从mylocale文件_地区语言取值,以下都是消息源
mylocale_zh_CN.properties
mylocale_zh_TW.properties
mylocale_en_US.properties
spring mvc国际化
到了web项目中,国际化通常有两个需求,第一,切换语言,比如菜单栏中有中英文按钮来切换当前语言。spring提供了LocaleChangeInterceptor
第二,切换后,要记住当前语言,在当前会话中始终维持所选语言,这就要用到session,所以spring提供了SessionLocaleResolver,除了SessionLocaleResolver还有两个locale相关类,CookieLocaleResolver、AcceptHeaderLocaleResolver
- AcceptHeaderLocaleResolver,顾名思义,分别是通过header中的accept-language来识别locale
- CookieLocaleResolver就是cookie中存储locale信息,比如cookie中存放locale、timezone等信息,跟SessionLocaleResolver正好相反,CookieLocaleResolver是将locale放在cookie中,而SessionLocaleResolver是将这些信息放在session中。
中英文切换LocaleChangeInterceptor
从类层次结构图中可以看出来,LocaleChangeInterceptor说到底是个拦截器,从源码得知在请求到达RequestMapping之前执行,它的作用,简单来说就是从请求中获取请求参数(默认是locale),然后在LocaleResolver设置当前locale。
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws ServletException {
String newLocale = request.getParameter(getParamName());
if (newLocale != null) {
if (checkHttpMethod(request.getMethod())) {
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
if (localeResolver == null) {
throw new IllegalStateException(
"No LocaleResolver found: not in a DispatcherServlet request?");
}
try {
localeResolver.setLocale(request, response, StringUtils.parseLocaleString(newLocale));
}
catch (IllegalArgumentException ex) {
if (isIgnoreInvalidLocale()) {
logger.debug("Ignoring invalid locale value [" + newLocale + "]: " + ex.getMessage());
}
else {
throw ex;
}
}
}
}
// Proceed in any case.
return true;
}
一般都会在spring-mvc中配置
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean id="localeChangeInterceptor" class="com.bsmartd.handler.LocaleInterceptor"/>
</mvc:interceptor>
SessionLocaleResolver 获取当前session中的地区
从类继承层次结构图上看,SessionLocaleResolver 是个解析器。
顶级接口类LocaleResolver的resolveLocale方法用来解析给定请求的locale。我们看到render时,会调用此方法。所以它的执行时机与LocaleChangeInterceptor是不同的。
/**
* Resolve the current locale via the given request. Can return a default locale as
* fallback in any case.
* @param request the request to resolve the locale for
* @return the current locale (never {@code null})
*/
Locale resolveLocale(HttpServletRequest request);
DispatcherServlet
/**
* Render the given ModelAndView.
* <p>This is the last stage in handling a request. It may involve resolving the view by name.
* @param mv the ModelAndView to render
* @param request current HTTP servlet request
* @param response current HTTP servlet response
* @throws ServletException if view is missing or cannot be resolved
* @throws Exception if there's a problem rendering the view
*/
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
//省略不相关的代码
}