关于SpringMVC中的国际化

国际化概述

  为了让Web项目支持国际化,需要识别每个用户的首选区域,并根据这个区域显示内容。在spring MVC应用程序中,用户的区域是通过区域解析器来识别的,它必须实现LocaleResolver接口。
  Spring MVC提供了几个LocaleResolver的实现,我们可以根据不同的需求来解析区域。如果SpringMVC提供的解析器不能满足需求,我们可以实现LocaleResolver接口,创建自定义的区域解析器。
  要定义一个区域解析器,只需在web应用程序上下文中注册一个LocaleResolver类型的Bean就可以了。必须将区域解析器的Bean名称设置为localeResolver,这样DispatcherServlet才能自动侦测到它。注意,每DispatcherServlet只能注册一个区域解析器。
  
  Spring采用的默认区域解析器是AcceptHeaderLocaleResolver。它通过检验HTTP请求头的accept-language属性来解析区域。   

默认区域解析器AcceptHeaderLocaleResolver的示例

  下面通过两个例子展示默认的区域解析器AcceptHeaderLocaleResolver的效果:
  
  示例一:在页面上能够根据浏览器语言设置的情况对文本(不是内容), 时间, 数值进行本地化处理。
  
  要实现上述功能,使用 JSTL 的 fmt 标签即可。(假设请求不经过控制器,直接跳转到jsp页面)


创建国际化资源文件

i18n_zh_CN.properties:

1
2
i18n.username=\u7528\u6237\u540D
i18n.password=\u5BC6\u7801

注:\u7528\u6237\u540D为“用户名”,\u5BC6\u7801为“密码”

i18n_en_US.properties:

1
2
i18n.username=username
i18n.password=password


配置国际化资源文件

spring配置文件:

1
2
3
4
5
6
7
8
9
<!-- 配置国际化资源文件 -->
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n"></property>
</bean>
<!--同时配置jsp页面的直接跳转-->
<mvc:view-controller path="/i18n" view-name="i18n"/>
<mvc:view-controller path="/i18n2" view-name="i18n2" />


页面

i18n.jsp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<fmt:message key="i18n.username"></fmt:message>
<br><br>
<a href="i18n2">I18N2 Page</a>
</body>
</html>

i18n2.jsp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<fmt:message key="i18n.password"></fmt:message>
<br><br>
<a href="i18n">I18N Page</a>
</body>
</html>


运行结果:
  当设置浏览器语言为zh-cn时,i18n.jsp显示“用户名”,i18n2.jsp显示“密码”;
  当设置浏览器语言为en-us时,i18n.jsp显示“username”,i18n2.jsp显示“password”。


  示例二:在 bean 中获取国际化资源文件 对应于 Locale 的信息。
  
  要实现上述功能,在 bean 中注入 ResourceBundleMessageSource 的实例, 使用其对应的 getMessage 方法即可:(创建国际化资源文件、配置国际化资源文件同示例一,但是令/i18n映射到控制器,而非直接跳转)


页面

index.jsp:

1
<a href="i18n">I18N Page</a>


控制器:

1
2
3
4
5
6
7
8
9
@Autowired
private ResourceBundleMessageSource messageSource;
@RequestMapping("/i18n")
public String testI18N(Locale locale) {
String val = messageSource.getMessage("i18n.username", null, locale);
System.out.println(val);
return "i18n";
}


运行结果:
  当设置浏览器语言为zh-cn时,点击index.jsp中的超链接,控制台输出“用户名”;
  当设置浏览器语言为en-us时,点击index.jsp中的超链接,控制台输出“username”。

使用SessionLocaleResolver实现通过超链接切换 Locale

  示例三:现在我们希望可以通过超链接切换 Locale, 而不再依赖于浏览器的语言设置情况
  
  实现方法为配置 SessionLocalResolver 和 LocaleChangeInterceptor。(创建、配置国际化资源文件同上面的例子)


配置SessionLocaleResolver和LocaleChangeInterceptor

spring配置文件:

1
2
3
4
5
6
7
8
9
10
<mvc:interceptors>
<!-- 配置 LocaleChanceInterceptor 拦截器
作用: 获取name=locale的请求参数 -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
</mvc:interceptors>
<!-- 配置 SessionLocalResolver
作用:将Locale对象设置为session的属性;从session中获取Locale对象 -->
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>


页面:

1
2
3
<a href="i18n?locale=zh_CN">Chinese</a>
<br><br>
<a href="i18n?locale=en_US">English</a>


控制器: (同示例二)

1
2
3
4
5
6
7
8
9
@Autowired
private ResourceBundleMessageSource messageSource;
@RequestMapping("/i18n")
public String testI18N(Locale locale) {
String val = messageSource.getMessage("i18n.username", null, locale);
System.out.println(val);
return "i18n";
}


运行结果:
  当点击页面的Chinese时,控制台输出“用户名”;
  当点击页面的English时,控制台输出“username”。   

SessionLocaleResolver&LocaleChangeInterceptor的工作原理

  通过查看源码,我了解到利用SessionLocaleResolver和LocaleChangeInterceptor实现示例三功能的工作流程为:

  1. 在目标方法执行之前,LocaleChangeInterceptor拦截器的preHandle方法会先被调用,该方法获取请求参数中的locale属性,如果locale不为空,则获取到当前的区域解析器(此时为SessionLocaleResolver),然后调用SessionLocaleResolver对象的setLocale方法,其中把 根据locale值生成的Locale对象 作为参数传递到该方法中。
  2. 在SessionLocaleResolver对象的setLocale方法中,会将Locale对象设置到Session中。
  3. DispatchServlet通过SessionLocaleResolver区域解析器在session中获取到Locale对象,将其传入目标方法,然后即可在目标方法中使用Locale对象。