概述
首先熟悉一下Spring MVC的国际化结构。DispatcherServlet会解析一个LocaleResolver接口对象,通过它来决定用户区域(User Locale),读出对应用户系统设定的语言或者用户选择的语言,以确定其国际化。
•AcceptHeaderLocaleResolver:Spring默认的区域解析器,它通过检验HTTP请求的acceptlanguage头部来解析区域。这个头部是由用户的web浏览器根据底层操作系统的区域设置进行设定。注意,这个区域解析器无法改变用户的区域,因为它无法修改用户操作系统的区域设置,所以它并不需要开发,因此也没有进一步讨论的必要。
•FixedLocaleResolver:使用固定Locale国际化,不可修改Locale,这个可以由开发者提供固定的规则,一般不用,本书不再讨论它。
•CookieLocaleResolver:根据Cookie数据获取国际化数据,由于用户禁止Cookie或者没有设置,如果是这样,它会根据acceptlanguage HTTP头部确定默认区域。
•SessionLocaleResolver:根据Session进行国际化,也就是根据用户Session的变量读取区域设置,所以它是可变的。如果Session也没有设置,那么它也会使用开发者设置默认的值。
为了可以修改国际化,Spring MVC还提供了一个国际化的拦截器——LocaleChangeInterceptor,通过它可以获取参数,然后既可以通过CookieLocaleResolver使用浏览器的Cookie来实现国际化,也可以用SessionLocaleResolver通过服务器的Session来实现国际化。但是使用Cookie的问题是用户可以删除或者禁用Cookie,所以它并非那么可靠,而使用Session虽然可靠,但是又存在过期的问题。不过在讨论国际化之前,还需要讨论如何加载国际化文件的问题,在Spring MVC中它就是MessageSource接口的使用问题。
MessageSource接口
MessageSource接口是Spring MVC为了加载消息所设置的接口,我们通过它来加载对应的国际化属性文件
其中Spring MVC一共提供了4个非抽象的实现类作为其子类。StaticMessageSource类是一种静态的消息源,DelegatingMessageSource实现的是一个代理的功能,这两者在实际应用中使用并不多,ResourceBundleMessageSource和ReloadableResourceBundleMessage Source在实际应用中使用较多,所以着重介绍它们。
ResourceBundleMessageSource和ReloadableResourceBundleMessageSource的区别主要在于:ResourceBundleMessageSource使用的是JDK提供的ResourceBundle,它只能把文件放置在对应的类路径下。它不具备热加载的功能,也就是需要重启系统才能重新加载它。而ReloadableResourceBundleMessageSource更为灵活,它可以把属性文件放置在任何地方,可以在系统不重新启动的情况下重新加载属性文件,这样就可以在系统运行期修改对应的国际化文件,重新定制国际化的内容。
代码清单16-26:使用XML定义MessageSource接口
<!--MessageSource接口是Spring MVC为了加载消息所设置的接口--> <!-- ResourceBundleMessageSource 和 ReloadableResourceBundleMessageSource可二者选其一 --> <!--<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="defaultEncoding" value="UTF-8"/> <property name="basenames" value="msg"/> </bean>--> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="defaultEncoding" value="UTF-8"/> <property name="basenames" value="classpath:message/msg"/> <property name="CacheSeconds" value="3600"/> </bean>
CookieLocaleResolver和SessionLocaleResolver
代码清单16-29:使用XML方式配合LocaleResolver
<!--根据Cookie数据获取国际化数据--> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"> <property name="cookieName" value="lang"/> <property name="cookieMaxAge" value="20"/> <property name="defaultLocale" value="zh_CN"/> </bean> <!--根据Session进行国际化--> <!--<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">--> <!--<property name="defaultLocale" value="zh_CN"/>--> <!--</bean>-->
只是对于Cookie而言,用户可以进行删除甚至禁用,使得其安全性难以得到保证,导致大量的使用默认值,也许这些并不是用户所期待的。为了避免这个问题,一般用得更多的是Session-LocaleResolver,它是基于Session实现的,具有更高的可靠性。
国际化拦截器(LocaleChangeInterceptor)
通过请求参数去改变国际化的值时,我们可以使用Spring提供的拦截器LocaleChangeInterceptor,它继承了HandlerInterceptorAdapter
代码清单16-30:配置拦截器LocaleChangeInterceptor
<!--国际化拦截器(LocaleChangeInterceptor)--> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/message/*.do"/> <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"> <!--监控请求参数language--> <property name="paramName" value="language"/> </bean> </mvc:interceptor> </mvc:interceptors>
当请求到来时,首先拦截器会监控有没有language请求参数,如果有则获取它,然后通过使用系统所配置的LocaleResolver实现国际化,不过需要注意的是,有时候获取不到参数,或者获取的参数的国际化并非系统能够支持的主题,这个时候会采用默认的国际化主题,也就是LocaleResolver所调用的setDefaultLocale方法指定的国际化主题。
开发国际化
国际化的开发,首先需要新建两个国际化的属性文件msg_en_US.properties和msg_zh_CN.properties。
•msg_en_US.properties
welcome=the project name is chapter16
•msg_zh_CN.properties
welcome=u5DE5u7A0Bu540Du79F0u4E3AuFF1Achapter16
代码清单16-31:国际化JSP文件
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <%@taglib prefix="mvc" uri="http://www.springframework.org/tags/form" %> <%@taglib prefix="spring" uri="http://www.springframework.org/tags" %> <html> <head> <title>Spring MVC国际化</title> </head> <body> <h2> <!-- 找到属性文件变量名为welcome的配置 --> <spring:message code="welcome"/> </h2> Locale: ${pageContext.response.locale } </body> </html>
代码清单16-32:国际化控制器
package com.ssm.chapter15.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/message") public class MessageController { /** * http://localhost:8081/message/msgpage.do * http://localhost:8081/message/msgpage.do?language=en_US */ @RequestMapping("/msgpage") public String page(Model model) { return "msgpage"; } }