一、背景
很多网站的用户分布在世界各地,因此网站需要针对不同国家的用户展示不同语言的内容,因此就有了国际化实现的需求,大多数网站都会在网站的头部或尾部设置语言切换链接,这样就可以直接切换成相应的内容。其中有些网站是通过网站地址或参数进行区分,有些是通过设置cookie值进行进行区分。
二、解决思路
前面已经写过一篇JDK的国际化支持,讲解了JDK实现国际化的具体实现。那么网站的国际化实现具体如何做呢?
其实网站的国际化实现与前面介绍的JDK实现思路类似,只是本地化信息的获取需要从页面得到而已。得到了页面信息,再获取对应的数据并进行格式化处理,最后渲染到页面即可。这里主要说明后端的处理思路,前端的处理思路其实也类似,只是实现方式有区别而已。
那如何从页面获取本地化信息呢?这个是所有处理的首要环节,常用的几种方式有:
(1)直接根据Request.getLocale()方法得到本地化信息,实际就是从Http Request Headers里面取“accept-language”对应的值,该值拥有浏览器端的语言信息;
(2)在浏览器端保存一个自定义名字的cookie,默认情况下指定一个值,对应的切换通过语言切换链接的点击修改对应的值;
(3)在请求URL上面添加带本地化信息的参数或者地址里面包含本地化信息。
通过上面几种方式,在web程序中就可以直接从request中得到了本地化信息,然后根据本地化信息从相应的properties文件中获取数据(比如可以通过JDK的ResourceBundle类),得到数据后如果需要的化再对数据进行格式化处理(比如可以通过JDK的MessageFormat类),最后将处理过的数据展示到前台即完成了整个国际化操作。
思路已经有了,那么具体如何实现呢?下面以Spring MVC的实现为例,因为该框架做了很好的抽象和封装,是个非常好的参考例子。
三、Spring MVC实现及原理
3.1 本地化信息获取
3.1.1 概述
Spring MVC的DispatcherServlet类会在initLocaleResolver方法中查找一个locale resolver,如果没有找到就会用默认的AcceptHeaderLocaleResolver类。locale resolver会去根据请求Request设置当前的locale信息。
除了resolver类,还可以定义拦截器去设置locale信息,比如通过请求参数去设置,具体下面细讲。
Spring MVC相关的处理类都在org.springframework.web.servlet.i18n包下。而本地化信息的获取可以通过RequestContext.getLocale()方法得到。另外,RequestContext.getTimeZone()方法还可以得到时区信息。
3.1.2 AcceptHeaderLocaleResolver
这个从名字也能看出大概来,这个类是解析request的header中的accept-language值,这个值通常包含客户端支持的本地化信息,所以通过这个值可以获取本地化信息。不过这个类拿不到时区信息。这个类是默认配置的,所以使用的话不用额外配置。
3.1.3 CookieLocaleResolver
这个类是通过cookie去存取本地化信息,客户端可以在cookie中存储一个指定名字的值代表本地化信息,然后这个类获取后做相应的解析即可。具体的配置如下:
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"> <property name="cookieName" value="clientlanguage"/> <property name="cookieMaxAge" value="100000"/> <property name="cookiePath" value="/"/> </bean>
这里对几个配置的属性做下说明:
cookieName | 默认值:classname + LOCALE | cookie名字 |
cookieMaxAge | 默认值:Servlet容器默认值 | 这个值为cookie在客户端保留的时间,如果值为-1,则不保留;这个值会在关闭浏览器后无效。 |
cookiePath | 默认值:/ | 这个值设置cookie的适用路径,如果这个值设置了,那么就表示cookie只对当前目录及其子目录可见。 |
3.1.4 SessionLocaleResolver
这个类是通过request获取本地化信息的,然后存在HttpSession中,所以本地化信息存取依赖于session的生命周期。具体配置如下:
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
</bean>
3.1.5 LocaleChangeInterceptor
这个拦截器会拦截请求中的参数,然后根据参数去调用LocaleResolver的setLocale()方法,改变当前的locale值。下面举个例子,有这个地址http://www.sf.net/home.view?siteLanguage=nl,参数siteLanguage代表locale信息,配置拦截修改locale值:
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"> <property name="paramName" value="siteLanguage"/></bean> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"/>
这里配置CookieLocaleResolver是因为LocaleChangeInterceptor需要调用LocaleResolver的setLocale()方法,这个例子里面用到了CookieLocaleResolver,当然也可以用其他的LocaleResolver实现类。
3.2 数据获取与格式化
Spring MVC的数据处理定义了一个接口MessageSource,该接口定义了数据获取的方法。方法如下:
- String getMessage(String code, Object[] args, String defaultMessage, Locale locale);
这里code为属性文件中的key值,args是文件中需要替换的参数值,defaultMessage是找不到内容时的默认内容,locale为本地化信息。 - String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;
这个方法与上面的方法类似,只是没有了默认内容,而是找不到内容时抛出异常。 - String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
这里参数中有个新接口MessageSourceResolvable,对前面的参数进行了封装,locale为本地化信息。
对于MessageSource接口,Spring MVC的ApplicationContext和HierarchicalMessageSource都有继承,ApplicationContext在加载的时候,它会先去上下文里面查找bean名为messageSource的实现,找到后上面MessageSource方法的调用就用这个实现类; 如果找不到就会找包含MessageSource bean的类去使用; 再找不到就用DelegatingMessageSource去执行方法调用了。
MessageSource常见的实现主要有如下几个:
- ResourceBundleMessageSource类:这个类实际是依赖的JDK的ResourceBundle类获取数据、MessageFormat去做格式化。
- ReloadableResourceBundleMessageSource类:这个与上面的比较就多了可重新加载,即可以在不重新启动应用的情况下重新读取新的内容。具体实现方式也有区别,这个类是通过Spring的PropertiesPersister策略加载,依赖的是JDK的Properties类读取内容。
- StaticMessageSource类:这个类提供了简单的实现,内容是需要先配置好的。使用比较少,适合在内容较少较简单情况下使用。
下面以最常用的ResourceBundleMessageSource类做个简单示例:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>format</value> <value>exceptions</value> </list> </property> </bean>
format与exceptions为文件基础名,对应内容配置在具体locale相应的文件名中即可。详细示例见下面部分。
3.3 小结与示例
上面两节主要讲了本地化信息获取,数据获取与格式化两部分,这两部分其实也是整个国际化过程最核心的两个部分,至于请求的匹配与接收,返回结果的页面渲染这个就不展开讲,与国际化不直接相关,属于Spring MVC的基础内容。
这里对整个Spring MVC的国际化过程做个大概的梳理,整个过程大概是这样:接收请求——>LocaleResolver获取/设置locale信息——>MessageSource获取数据并格式化——>内容展示到页面。
讲了半天,还是有点抽象,下面直接来个详细示例:
@Controller public class I18nController { @Autowired private MessageSource messageSource; @RequestMapping("i18n") public String i18n(Model model){ //获取本地化信息,从LocaleContext中得到 Locale locale = LocaleContextHolder.getLocale(); //初始化参数,这里简便演示,真实参数可能是从数据库查询处理的。这里的参数是与i18n目录下的配置文件需要替换的内容对应的 Object [] objArr = new Object[4]; objArr[0] = new Date(); objArr[1] = messageSource.getMessage("goods", null, locale);//这个具体商品从配置中读取 objArr[2] = "taobao"; objArr[3] = new BigDecimal("39.20"); //获取格式化后的内容 String content = messageSource.getMessage("template", objArr, locale); model.addAttribute("content", content); return "/i18n/show"; } }
LocaleResolver配置,这里以Cookie为例:
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"> <property name="cookieName" value="clientlanguage"/> <property name="cookieMaxAge" value="100000"/> <property name="cookiePath" value="/"/> </bean>
MessageSource配置,这里以ResourceBundleMessageSource为例:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>/i18n/message</value> </list> </property> </bean>
Properties配置,这里统一放在/i18n目录下,message名字开头:
更详细的代码可以查看我的Github项目。
四、拓展介绍
4.1 LocaleResolver对应Bean是如何初始化的?
初始化工作是在DispatcherServlet类初始化时调用initLocaleResolver方法执行的。
private void initLocaleResolver(ApplicationContext context) { try { this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class); if (logger.isDebugEnabled()) { logger.debug("Using LocaleResolver [" + this.localeResolver + "]"); } } catch (NoSuchBeanDefinitionException ex) { // We need to use the default. this.localeResolver = getDefaultStrategy(context, LocaleResolver.class); if (logger.isDebugEnabled()) { logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME + "': using default [" + this.localeResolver + "]"); } } }
从代码里面可以看到处理化过程分为两步:
(1)先从当前上下文环境中取名字为localeResolver的bean;
(2)如果找不到就根据默认策略去取LocaleResolver这个Class名字的bean,即执行getDefaultStrategy方法,该方法实际是取DispatcherServlet.properties文件中的org.springframework.web.servlet.LocaleResolver对应的值,即默认的AcceptHeaderLocaleResolver类,再创建对应的bean。
所以如果上下文中自定义了LocaleResolver就用自定义的,没有定义会用默认的AcceptHeaderLocaleResolver类。这种写法在写公共逻辑且提供多种策略时很实用。
相关推荐
通过学习《Expert Spring MVC and Web Flow》这本书,开发者不仅能够深入了解 Spring MVC 和 Spring Web Flow 的核心原理和技术细节,还能掌握如何有效地将这两个框架结合在一起,构建出既稳定又易于维护的 Web 应用...
在Web应用中,Spring MVC框架结合JavaScript技术可以有效地实现基于Session的国际化,使得用户可以根据自己的语言偏好查看相应的界面内容。 1. 说明 基于Session的国际化主要是通过在用户的Session中存储所选择的...
通过阅读和分析这些源代码,开发者可以学习到Spring如何实现依赖注入、AOP代理、事件传播、异常处理、国际化和本地化、数据绑定、类型转换等机制。同时,测试代码可以帮助理解Spring如何测试自己的组件,这对于编写...
在描述中提到的“宏观和微观两个角度深入剖析Spring架构设计与实现原理”,说明了作者可能会通过不同层次的分析来讲解Spring。从宏观的角度可能包含Spring整体架构的介绍,如Spring如何通过模块化来支持各种不同的...
2. **资源文件**:如`src/main/resources`,存放数据库配置、国际化消息文件、MyBatis的XML映射文件等。 3. **Web应用结构**:`src/main/webapp`目录包含了HTML、CSS、JavaScript等前端资源,以及Spring MVC的视图...
- **spring-context-4.3.9.RELEASE.jar**:上下文支持,包括事件发布和国际化支持。 - **spring-aop-4.3.9.RELEASE.jar**:面向切面编程支持。 - **spring-aspects-4.3.9.RELEASE.jar**:AOP支持。 - **spring-...
### 开发Struts2+Spring应用 #### 12.1 介绍 Struts2是一个基于MVC(Model-...通过以上详细的步骤和说明,开发者可以全面掌握Struts2和Spring框架的基础知识及实际应用技巧,为进一步的学习和开发打下坚实的基础。
4. **国际化与本地化支持**:方便地实现多语言网站。 5. **配置驱动**:通过XML配置文件,可以灵活配置应用行为,降低代码的耦合度。 总的来说,Struts框架为Web开发提供了一个强大的基础架构,使得开发者能够专注...
Struts2中文API详细阐述了各种核心组件、拦截器、结果类型以及如何进行国际化和异常处理,是开发者理解和实现业务逻辑的重要参考资料。 Spring2.5是全面的轻量级应用框架,它不仅包含IoC(Inversion of Control)...
本项目是一个基于这两者实现的兼职招聘网站,让我们深入探讨一下这个项目的组成部分及其工作原理。 首先,SpringBoot是Spring框架的一种快速开发工具,它集成了大量常用的第三方库配置,如数据源、JPA、MVC、...
- **国际化(i18n)**:支持多语言环境,方便国际化应用的开发。 - **表单标签库**:提供了一系列的表单标签,用于简化表单元素的创建。 #### Struts与其他框架的比较 - **Spring MVC**:同样是基于MVC的设计模式,...
它与Spring的整合能够提供更强大的功能,比如数据校验和国际化支持。 MyBatis是一个持久层框架,它简化了数据库操作,允许开发者将SQL语句直接写在XML配置文件或者注解中,与Java对象进行映射,实现了数据访问层的...
6. **国际化和本地化**:Struts支持多语言环境,通过资源文件(`.properties`)来实现。网站可能会有不同语言版本的字符串资源,以适应不同的用户群体。 7. **异常处理**:Struts框架允许开发者自定义全局和局部的...
同时,这也将有助于理解和掌握其他Web框架,如Spring MVC,因为它们都基于相似的原理和技术栈。所以,《JSP动态网站开发实践教程(第2版)源代码》对于想要在Web开发领域深化的程序员来说,无疑是一份宝贵的参考资料...
第五章可能进一步讲解Struts2的高级特性,如国际化、插件机制、Action的组合以及Struts2与其他框架(如Spring、Hibernate)的整合。国际化支持多语言环境,让应用更具有普适性;Action的组合允许将复杂的业务逻辑...
5. `resources` 文件夹:可能包含数据库连接配置、国际化文件、静态资源等。 此外,开发者可能使用了Maven或Gradle作为构建工具,管理项目依赖和构建流程。IDE如Eclipse、IntelliJ IDEA等可能被用来编写和调试代码...
- **国际化和本地化**:可能实现了Spring的ResourceBundle和MessageSource,以支持多语言环境。 - **异常处理**:使用@ControllerAdvice和@ExceptionHandler注解进行全局异常处理。 - **配置管理**:使用YAML或XML...
Struts 2是Java Web开发中的一个强大框架,它基于Model-View-Controller(MVC)设计模式,为开发者提供了一种结构化和可扩展的方式来构建动态网站应用程序。《Struts 2 in Action》这本书是关于这个框架的权威指南,...
- **拦截器的实现原理**:拦截器是一种在Action执行前后进行拦截的机制。 - **拦截器的配置**:在struts.xml中配置拦截器及其参数。 - **内建拦截器**:Struts2提供了一系列预定义的拦截器,如参数填充拦截器、异常...