1.创建Resource Bundle
注意:这里添加Locales的时候,命令一定要和Locale内置的国家方言定义一致,如en,zh_CN,en_US等等,zh、en前面代表方言,CN、US后面代表国家。
language_en_US.properties:
name=test
args=hello,{0}
language_zh_CN.properties:
name=测试
args=你好,{0}
2.绑定Resource Bundle
在Spring中主要提供了两个实现类来进行Resouce Bundle的绑定,如下: org.springframework.context.support.ResouceBundleMessageSource,该类是基于JDK的标准实现,和JDK一样,只能从类路径中读取资源,不能指定外部文件。 org.springframework.context.support.ReloadableResouceBundleMessageSource比ResouceBundleMessageSource更加灵活,它允许从任何Spring路径读取资源(不仅仅是类路径),并支持热重载bundle属性文件。 代码如下:
<!--绑定Resource Bundle,该类只能从类路径读取,不能指定外部资源文件-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="defaultEncoding" value="UTF-8"/>
<property name="basename" value="classpath:/i18n/language"/>
</bean>
<!--绑定Resource Bundle,可以从类路径读取,也可以指定外部资源文件,一般建议使用该类-->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:/i18n/language"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
因为我是放在了类路径下面,所以两个类都可以用。注意:。
3.自动解析Locale和TimeZone
Spring提供了org.springframework.web.servlet.LocaleResolver解析器来解析Locale,看下它的类图:
我们在使用的时候主要是用到如下四个解析器: 1.org.springframework.web.servlet.i18n.CookieLocaleResolver 2.org.springframework.web.servlet.i18n.SessionLocaleResolver 3.org.springframework.web.servlet.i18n.FixedLocaleResolver 4.org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver 1.此解析器检查客户端发送的请求中的accept-language头,通常这个字段包含了用户操作系统的语言环境,而且不能设置Locale,会抛出异常。
2.此解析器在请求的时候,如果DispatcherServlet找不到名称为localeReslover的bean,将会初始化该类作为默认解析器。
3.请注意,。
1.CookieLocaleResolver
由名字我们也可以看出来该解析器是通过Cookie来解析Locale和TimeZone的,当一个请求过来的时候,该解析器会从HttpServletRequest中拿到我们设置的key对应的Cookie,然后通过解析Cookie的值,来判断当前是哪个Locale。
<!--此解析器检查客户端可能存在Cookie,以查看是否指定了区域设置或时区-->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="zh_CN"/>
<property name="cookieName" value="clientlanguage"/>
<!--单位:s,如果设置为-1,并不会持久化,当浏览器关闭的时候删除-->
<property name="cookieMaxAge" value="100000"/>
</bean>
源码如下:
2.SessionLocaleResolver
该解析器与CookieLocaleResolver相比,把Locale和TimeZone存储在Servlet容器的HttpSession中。因此,这些设置对于每个会话来说都是临时的,在每个会话终结的时候都会丢失。
<!--此解析器允许我们从可能与用户请求关联的Session检索Locale和TimeZone
与CookieLocaleResolver相比,此策略将本地选择的语言环境设置在Servlet容器的HttpSession中
因此,这些设置对于每个会话来说都是临时的,因此在每个会话终止时都会丢失
该解析器将仅根据当前的HttpServletRequest评估并修改相应的HttpSession属性-->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="zh_CN"/>
<property name="localeAttributeName" value="clientlanguage"/>
<property name="timeZoneAttributeName" value="clienttimezone"/>
</bean>
源码如下:
3.FixedLocaleResolver
该解析器一旦设置了默认的Locale和TimeZone,将不能更改,更改会抛出异常。
<!--固定解析器,一旦设置,不允许修改,修改会抛出异常-->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.FixedLocaleResolver">
<property name="defaultLocale" value=""/>
<property name="defaultTimeZone" value=""/>
</bean>
源码如下:
注意:。原因是当我们查看org.springframework.web.servlet.DispatcherServlet#initLocaleResolver源码时,可以看到如下:
4.设置Locale
我们该如何根据请求动态的设置我们的Locale?在上面,我们看到了Locale的解析是由org.springframework.web.servlet.LocaleResolver这个顶层接口来做的,这个顶层接口中有两个方法,如下:
这也就意味着,如果我们想要更改Locale,就必须要拿到LocaleResolver,通过调用setLocale方法来更改我们的Locale。 在Spring中提供了一个类:org.springframework.web.servlet.i18n.LocaleChangeInterceptor,看这个名字我们就知道这个是一个拦截器。下面看下他的具体实现:
正如我们前面说的,这个拦截器通过我们指定的某个请求是否有我们指定的参数名称,来进行请求拦截,然后根据我们参数的值来更改Locale。下面看下具体使用:
<mvc:interceptors>
<!--使用自带的拦截器-->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="language"/>
</bean>
</mvc:interceptors>
我们也可以自定义拦截器,实现和Spring提供的差不多,代码如下:
public class InternationalInterceptor extends HandlerInterceptorAdapter {
private static final String DEFAULT_PARAM_NAME = "language";
private String paramName = DEFAULT_PARAM_NAME;
public String getParamName() {
return paramName;
}
public void setParamName(String paramName) {
this.paramName = paramName;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String localeString = request.getParameter(getParamName());
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
if (localeResolver == null) {
throw new IllegalArgumentException("No LocaleResolver found: not in a DispatcherServlet request?");
}
localeResolver.setLocale(request, response, StringUtils.parseLocaleString(localeString));
return true;
}
}
#5.完整配置及测试 完整配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--自动解析Locale的几种方式-->
<!--此解析器允许我们从可能与用户请求关联的Session检索Locale和TimeZone
与CookieLocaleResolver相比,此策略将本地选择的语言环境设置在Servlet容器的HttpSession中
因此,这些设置对于每个会话来说都是临时的,因此在每个会话终止时都会丢失
该解析器将仅根据当前的HttpServletRequest评估并修改相应的HttpSession属性-->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="zh_CN"/>
</bean>
<!--绑定Resource Bundle,可以从类路径读取,也可以指定外部资源文件,一般建议使用该类-->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:/i18n/language"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<mvc:interceptors>
<!--自定义拦截器,拦截参数为language的HTTP请求,重新设置区域化信息-->
<!-- <bean class="com.ly.spring.interceptor.InternationalInterceptor">-->
<!-- <property name="paramName" value="language"/>-->
<!-- </bean>-->
<!--使用自带的拦截器-->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="language"/>
</bean>
</mvc:interceptors>
</beans>
@Controller
public class InternationalController {
/**
* 通过拦截器,根据Locale,改变返回的信息
*
* @param language
* @return
*/
@GetMapping("/international")
public String international(String language) {
System.out.println(language);
return "international";
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<!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>Title</title>
</head>
<body>
选择语言:
<a href="http://localhost:8080/spring_i18n/international?language=zh_CN">中文</a>
<a href="http://localhost:8080/spring_i18n/international?language=en_US">English</a>
<br>
<spring:message code="name"/>
</body>
</html>
测试结果: