Spring MVC 国际化
本小记学习目标
-
Java国际化思想介绍
-
Spring MVC的国际化介绍
-
自定义切换语言
一、Java国际化的思想介绍
把程序中的信息放在资源文件中,程序根据语言信息来读取相应的国际化资源文件。
资源文件是以key-value对的形式存在,资源文件中的key是保持不变的,但是value会随不同的语言环境而有所变化。
Java程序的国际化主要由两个类来支持
java.util.Locale:它提供本地信息,一般把它称为语言环境。对于不同的语言,不同的地区使用不同的Locale对象来表示。
java.util.ResourceBundle:这个类称为资源包,包含了特定于语言环境的的资源对象。当程序需要一个特定于语言环境的资源时,程序可以从适合当前用户语言环境的资源包中加载它,这样可以编写独立于语言环境的程序代码,对于特定语言环境的信息通过资源包来提供即可。
从上面可以看到,需要实现Java程序的国际化,必须事先提供程序需要的资源文件,资源文件则是同由多个key-value对组成,其中key是在程序中需要使用的,value则是在界面中呈现的内容。
资源文件的命名可以有如下三种形式:
-
baseName.properties
-
baseName_language.properties
-
basName_language_country.properties
baseName是资源文件的基本名称,是由用户自行定义的,但是language和country则必须是Java所支持定义的语言和地区代码
如:中国大陆则定义名称为:baseName_zh_CN.properties
注意:Java中的资源文件只支持ISO-8859-1编码的格式字符,可以使用Java命令native2ascii.exe解决资源文件的中文乱码问题
java.util.Locale常用构造方法:
public Locale(String language);
public Locale(String language,String country);
language:语言代码,由两个小写的字母组成
country:国家代码,由两个大写的字母组成
如果需要获取Java可以支持的language和country则可以通过getAvailableLocales方法获取,它会返回一个Locale的数组
新增一个Java程序,通过如下方法进行遍历获取Java所支持的语言及国家信息
package com.xiaoxie.locale.test;
import java.util.Locale;
public
class Test {
public
static
void main(String[]
args) {
//返回Java支持的语言及国家代码
Locale[]
availableLocales = Locale.
getAvailableLocales();
//遍历数组
for (Locale
locale :
availableLocales) {
System.
out.print(
"国家:");
System.
out.print(
locale.getDisplayCountry() +
" = " +
locale.getCountry());
System.
out.print(
"\t语言:");
System.
out.println(
locale.getDisplayLanguage() +
" = " +
locale.getLanguage());
}
}
}
现在需要进行国际化处理,则需要把工呈现的信息定义为资源文件
新增两个资源文件:messageResource_zh_CN.properties、messageResource_en_US.properties
messageResource_zh_CN.properties
hello=
\u6211\u5411\u4E0D\u540C\u56FD\u5BB6\u7684\u4EBA\u95EE\u597D\uFF01
注意:上面的实际是对中文的unicode编码,Eclipse中会自动处理,直接把hello对应的中文复制进去即可这个转unicode的会自动进行
messageResource_en_US.properties
hello=
I
want
to
say
hello!
修改测试类及测试方法
package com.xiaoxie.locale.test;
import java.util.Locale;
import java.util.ResourceBundle;
public
class Test {
public
static
void main(String[]
args) {
//printLocales();
//取得系统默认的语言环境
Locale
defaultLocale = Locale.
getDefault();
//加载资源文件
ResourceBundle
rb = ResourceBundle.
getBundle(
"messageResource",
defaultLocale);
//打印从资源文件中获取的信息
System.
out.println(
rb.getString(
"hello"));
}
/*打印所有的Locale信息*/
private
static
void
printLocales() {
//返回Java支持的语言及国家代码
Locale[]
availableLocales = Locale.
getAvailableLocales();
//遍历数组
for (Locale
locale :
availableLocales) {
System.
out.print(
"国家:");
System.
out.print(
locale.getDisplayCountry() +
" = " +
locale.getCountry());
System.
out.print(
"\t语言:");
System.
out.println(
locale.getDisplayLanguage() +
" = " +
locale.getLanguage());
}
}
}
注意:ReourceBundle.getBundle方法中的“messageResource”是一个baseName,当程序找不到对应的资源文件时,它会做如下的资源文件顺序的检索:messageResource_zh_CN.properties、messageResource_zh.properties、messageResource.properties
如果经过上面的检索还找不到则会报出异常
带占位符的国际化消息
在资源文件中对于消息的文本可以带有占位符,如
hello=My name is {0}
这里的{0}就是一个占位符,它可以在呈现消息的时候动态地被替换。这里占位符中的数字可以是0~9,也就是说一个消息中可以最多设置10个占位符
如何动态地替占位符?
可以使用java.text.MessageFormat类,这个类有一个静态的方法format,可以用来格式化带参数的文本
public static String format(String pattern,Object ... args)
这里pattern是一个带有占位符的字符串(可能理解为就是一个资源文件中需要呈现的文本,这个文本中带有占位符)
消息文本中的占位符会按照顺序从第二个参数开始依次地被替
我们在前面实例中messageResource_zh_CN.properties中添加一个info的资源展示信息
info=
\u4F60\u597D\u6211\u53EB
{0}
,\u6211\u6765\u81EA\u4E8E
{1}
\u3002
对main方法中填加一行代码以展示这个info资源对应的信息(这个资源中存在两个占位符),需要对获取的的信息调用MessageFormat.format方法进行格式化
//带占位符信息的展示
System.
out
.println(MessageFormat.
format
(
rb
.getString(
"info"
),
"小谢"
,
"湖南"
));
二、Spring MVC国际化介绍
Spring MVC的国际化实现是建立在Java国际化基础之上的,它的底层国际化与Java国际化是一致的。只是它把Java国际化的功能进行了封装和简化。
要实现国际化有两个必要的条件
-
把文本信息放到资源属性文件中
-
选择和读取正确位置资源文件
Spring MVC如何加载资源属性文件
在Java国际化中我们看到在加载资源文件时的方法如下:
//加载资源文件
ResourceBundle
rb = ResourceBundle.
getBundle(
"messageResource",
defaultLocale);
但是Spring MVC不可以直接使用ResourceBundle加载资源属性文件,而是配置bean来通知Spring MVC 框架资源属性文件放到哪里
示例如下:
<
bean
class=
"org.springframework.context.support.ResourceBundleMessageSource"
id=
"messageSource"
>
<!-- 资源文件 -->
<
property
name=
"
basename"
value=
"classPath:messages"
/>
</
bean
>
注意:其中classpath表示是classpath路径,也可以指定在其它的路下
如果有一组属性文件则可以把beanname替换为beannames
<
property
name=
"
basenames"
>
<list>
classPath:messages
</list>
<list>
classPath:messages1
</list>
</property>
Spring MVC中可以使用语言区域解析器bean选择语言区域,这个bean有三个常见的实现类
-
AcceptHeaderLocaleResolver
-
SessionLocaleResolver
-
CookieLocaleResolver
AcceptHeaderLocaleResolver:
根据浏览器Http Header中的accept-language域设定
SessionLocaleResolver:根据用户本次会话Session中的语言设定(比如:用户在进入首页后选择了语言,则在这次会话周期内都会使用这种语言设定)
CookieLocaleResolver:根据Cookie判断用户的语言设定,Cookie中保存了用户上一次的语言设定参数
例如使用SessionLocaleResolver实现则在配置文件中需要做两个配置
第一个,指定语言区域解析器的bean
<
bean
id=
"localeResolver"
class=
"org.springframework.web.servlet.i18n.SessionLocaleResolver"
/>
第二个,配置拦截器(对于使用Cookie和Session的语言配置bean必须要配置这个拦截器)
<
mvc:interceptors
>
<!-- 国际化操作拦截器如果采用基于(Session/Cookie则必须配置) -->
<
bean
class=
"org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
/>
</
mvc:interceptors
>
JSP页面显示国际化信息方式:使用message标签
当要使用message标签需要在jsp页面中添加taglib指令做好标签声明
<%@taglib prefix="spring" uri="http://www.springframework.org/tags" %>
message标签的常用属性:
-
code:获得国际化消息的key
-
arguments:代表替换消息中的占位符参,如:<spring:message code="info" arguments="1,2"/>(这其中的1和2分别会替换消息占位符{0},{1})
-
argumentSeparator:用来分隔参数的字符,它是有默认值的,默认值为逗号
-
text:当code这个key值不存在,或者是无法获取到消息时则显示text指定的文本信息
三、自己定义切换语言的实现实例
1.创建一个maven的war工程,在pom.xml中添加如下依赖
<
dependencies
>
<!-- context -->
<
dependency
>
<
groupId
>org.springframework
</
groupId
>
<
artifactId
>spring-context
</
artifactId
>
<
version
>5.0.2.RELEASE
</
version
>
</
dependency
>
<!-- Spring MVC -->
<
dependency
>
<
groupId
>org.springframework
</
groupId
>
<
artifactId
>spring-
webmvc
</
artifactId
>
<
version
>5.0.2.RELEASE
</
version
>
</
dependency
>
<!-- Spring web -->
<
dependency
>
<
groupId
>org.springframework
</
groupId
>
<
artifactId
>spring-web
</
artifactId
>
<
version
>5.0.2.RELEASE
</
version
>
</
dependency
>
<!-- commons-logging -->
<
dependency
>
<
groupId
>commons-logging
</
groupId
>
<
artifactId
>commons-logging
</
artifactId
>
<
version
>1.2
</
version
>
</
dependency
>
<!-- spring-
aop
-->
<
dependency
>
<
groupId
>org.springframework
</
groupId
>
<
artifactId
>spring-
aop
</
artifactId
>
<
version
>5.0.2.RELEASE
</
version
>
</
dependency
>
<
dependency
>
<
groupId
>javax.servlet
</
groupId
>
<
artifactId
>
jstl
</
artifactId
>
<
version
>1.2
</
version
>
</
dependency
>
</
dependencies
>
2.新增国际化资源文件:message_zh_CN.properties、message_en_US.properties
message_zh_CN.properties
name=
\u59D3\u540D
submit=
\u63D0\u4EA4
welcome=
\u6B22\u8FCE
info=
\u6211\u7684\u540D\u5B57\u662F
{0}
language.cn=
Chinese
language.en=
English
message_en_US.properties
name=
name
submit=
submit
welcome=
welcome
info=
my
name
is
{0}
language.cn=
Chinese
language.en=
English
3.新增jsp文件first.jsp、home.jsp(在/WEB-INF/jsp下)
first.jsp
<%@
page
language=
"java"
contentType=
"text/html; charset=UTF-8"
pageEncoding=
"UTF-8"
%>
<!
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
>First
</
title
>
</
head
>
<
body
>
<
a
href=
"${pageContext.request.contextPath }
/i18n?locale=zh_CN"
>
<
spring:message
code=
"language.cn"
/>
</
a
>
<
a
href=
"${pageContext.request.contextPath }
/i18n?locale=en_US"
>
<
spring:message
code=
"language.en"
/>
</
a
>
<
form
action=
"${pageContext.request.contextPath }
/submit"
method=
"post"
>
<
spring:message
code=
"name"
/>:
<
input
type=
"text"
name=
"name"
/>
<
input
type=
"submit"
value=
"
<
spring:message
code=
"submit"
/>
"
>
</
form
>
</
body
>
</
html
>
home.jsp
<%@
page
language=
"java"
contentType=
"text/html; charset=UTF-8"
pageEncoding=
"UTF-8"
%>
<!
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
>home
</
title
>
</
head
>
<
body
>
<
spring:message
code=
"welcome"
/>,
<
spring:message
code=
"info"
arguments=
"${name }
"
/>
</
body
>
</
html
>
3.新增controller实现类:I18Controller、HomeController
I18Controller
package com.xiaoxie.controller;
import java.util.Locale;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public
class I18nController {
@RequestMapping(
"/i18n")
public String first(Locale
locale) {
return
"first";
}
}
HomeController
package com.xiaoxie.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public
class HomeController {
@RequestMapping(
"/first")
public String first() {
return
"first";
}
@RequestMapping(
"/submit")
public String submit(String
name,Model
model) {
model.addAttribute(
"name",
name);
return
"home";
}
}
1、访问/first时经过拦截器会进入到first.jsp页面
2、当提交信息时会带上提交过来的参数进入到home.jsp页面
3、当点击first.jsp中的资源链接,会调用/i18n,并且会带上指定的locale参数
4.新增spring的配置文件springmvc.xml
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns:context=
"http://www.springframework.org/schema/context"
xmlns:mvc=
"http://www.springframework.org/schema/mvc"
xsi:schemaLocation=
"http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"
>
<
context:component-scan
base-package=
"com.xiaoxie.controller"
/>
<!-- 配置视图解析器 -->
<
bean
class=
"org.springframework.web.servlet.view.InternalResourceViewResolver"
id=
"internalResourceViewResolver"
>
<!-- 前缀 -->
<
property
name=
"
prefix"
value=
"/WEB-INF/jsp/"
/>
<!-- 后缀 -->
<
property
name=
"
suffix"
value=
".jsp"
/>
</
bean
>
<!-- 加载国际化资源文件 -->
<
bean
id=
"messageSource"
class=
"org.springframework.context.support.ResourceBundleMessageSource"
>
<
property
name=
"
basename"
value=
"message"
/>
</
bean
>
<
mvc:interceptors
>
<!-- 国际化操作拦截器如果采用基于(Session/Cookie则必须配置) -->
<
bean
class=
"org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
/>
</
mvc:interceptors
>
<!-- 存储区域设置信息 -->
<
bean
id=
"localeResolver"
class=
"org.springframework.web.servlet.i18n.SessionLocaleResolver"
>
<
property
name=
"
defaultLocale"
value=
"zh_CN"
/>
</
bean
>
</
beans
>
5.配置web.xml文件
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
<
web-app
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns=
"http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation=
"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id=
"WebApp_ID"
version=
"2.5"
>
<!-- 前端核心
servlet
的配置(DispatcherServlet) -->
<
servlet
>
<
servlet-name
>springDispatcherServlet
</
servlet-name
>
<
servlet-class
>org.springframework.web.servlet.DispatcherServlet
</
servlet-class
>
<
init-param
>
<
param-name
>contextConfigLocation
</
param-name
>
<
param-value
>classpath:springmvc.xml
</
param-value
>
</
init-param
>
<
load-on-startup
>1
</
load-on-startup
>
</
servlet
>
<!-- Map all requests to the DispatcherServlet for handling -->
<
servlet-mapping
>
<
servlet-name
>springDispatcherServlet
</
servlet-name
>
<
url-pattern
>/
</
url-pattern
>
</
servlet-mapping
>
<!-- 配置解决
psot
请求中文乱码问题 -->
<
filter
>
<
filter-name
>CharacterEncodingFilter
</
filter-name
>
<
filter-class
>org.springframework.web.filter.CharacterEncodingFilter
</
filter-class
>
<
init-param
>
<
param-name
>encoding
</
param-name
>
<
param-value
>
utf-8
</
param-value
>
</
init-param
>
<
init-param
>
<
param-name
>forceEncoding
</
param-name
>
<
param-value
>true
</
param-value
>
</
init-param
>
</
filter
>
<
filter-mapping
>
<
filter-name
>CharacterEncodingFilter
</
filter-name
>
<
url-pattern
>/*
</
url-pattern
>
</
filter-mapping
>
</
web-app
>