[springMVC]springMVC中的国际化

参考文章地址:

http://blog.sina.com.cn/s/blog_6d3c1ec601014eyj.html

http://www.mkyong.com/spring-mvc/spring-mvc-internationalization-example/


Spring国际化

web开发中经常会遇到国际化的问题,那么在spring mvc中如何实现动态国际化。Spring使用ResourceBundleMessageSource实现国际化资源的定义。使用LocaleResolver实现本地化信息的解析,使用LocaleChangeInterceptor实现本地化信息的监听(来实现url参数动态指定locale)。

I18N

人们常把I18N作为“国际化”的简称,其来源是英文单词 internationalization的首末字符in18为中间的字符数。

 

ALocaleResolver(本地化解析器)

org.springframework.web.servlet.LocaleResolver

public interface LocaleResolver

DispatcherServlet允许使用客户端本地化信息自动解析消息。这个工作由实现LocaleResolver的对象来完成。

但收到请求时,DispatcherServlet查找LocaleResolver,若找到就是用它来设置Locale信息。

 

A.1LocaleResolver的实现类

A.1.1AcceptHeaderLocaleResolver

org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

public class AcceptHeaderLocaleResolver extends Object implements LocaleResolver

这个本地化解析器检查请求中客户端浏览器发送的accept-language头信息,这里包含客户端操作系统的本地化信息。

 

A.1.2CookieLocaleResolver

org.springframework.web.servlet.i18n.CookieLocaleResolver

java.lang.Object

  org.springframework.web.util.CookieGenerator

      org.springframework.web.servlet.i18n.CookieLocaleResolver

public class CookieLocaleResolver extends CookieGenerator implements LocaleResolver

这个本地化解析器检查客户端中的cookie是否包含本地化信息。若有就使用。

 

A.1.3SessionLocaleResolver

org.springframework.web.servlet.i18n.SessionLocaleResolver

java.lang.Object
  org.springframework.web.servlet.i18n.AbstractLocaleResolver
      org.springframework.web.servlet.i18n.SessionLocaleResolver

public class SessionLocaleResolver extends AbstractLocaleResolver

这个本地化解析器检查客户端中的session是否包含本地化信息。若有就使用。

 

A.1.4FixedLocaleResolver

org.springframework.web.servlet.i18n.FixedLocaleResolver

java.lang.Object
  org.springframework.web.servlet.i18n.AbstractLocaleResolver
      org.springframework.web.servlet.i18n.FixedLocaleResolver

public class FixedLocaleResolver extends AbstractLocaleResolver

这个本地化解析器返回一个固定的本地化信息。默认值为当前JVMlocale

 

A.2、如何获得客户端的locale

通过RequestContext.getLocale()方法来获取由本地化解析器解析的客户端的本地化信息。

 

A.2.1RequestContext

org.springframework.web.servlet.support.RequestContext

public class RequestContext extends Object

Context holder for request-specific state, like current web application context, current locale, current theme, and potential binding errors. Provides easy access to localized messages and Errors instances.

Request特殊状态的上下文持有者,如:当前webapplication context,当前locale,当前主题和可能捆绑的错误。使访问本地化的信息和错误实例。

 

A.2.2RequestContext取得locale的例子

public ModelAndView handleRequest(HttpServletRequest req,

           HttpServletResponse res) throws Exception {

RequestContext requestContext = new RequestContext(req);

Locale myLocale = requestContext.getLocale();

System.out.println(myLocale);

}

 

BMessageSource

org.springframework.context.MessageSource

public interface MessageSource

spring通过实现MessageSource接口,来支持国际化。MessageSource来定义国际化需要资源的接口。MessageSource有很多实现方法,ResourceBundleMessageSource是一个常用的实现。它按照ResourceBundle标准实施。

 

B.1ResourceBundleMessageSource

org.springframework.context.support.ResourceBundleMessageSource

public class ResourceBundleMessageSource extends AbstractMessageSource implements BeanClassLoaderAware

org.springframework.context.support.MessageSourceSupport
      org.springframework.context.support.AbstractMessageSource
          org.springframework.context.support.ResourceBundleMessageSource

MessageSource implementation that accesses resource bundles using specified basenames. This class relies on the underlying JDK's ResourceBundle implementation, in combination with the JDK's standard message parsing provided by MessageFormat.

它是MessageSource的一个实现,它访问资源束,资源束的路径由的basenames属性来指定。这个类依赖于JDK的底层类java.util.ResourceBundle。并结合由java.text.MessageFormat类提供的JDK标准message解析。

set方法

void  setBasename(String basename)

Set a single basename, following ResourceBundle conventions: essentially, a fully-qualified classpath location. If it doesn't contain a package qualifier (such as org.mypackage), it will be resolved from the classpath root.

Messages will normally be held in the "/lib" or "/classes" directory of a web application's WAR structure. They can also be held in jar files on the class path.

Note that ResourceBundle names are effectively classpath locations: As a consequence, the JDK's standard ResourceBundle treats dots as package separators. This means that "test.theme" is effectively equivalent to "test/theme", just like it is for programmatic java.util.ResourceBundle usage.

设置单个basename,遵照ResourceBundle协定:一个合格的classpath路径。若它没有包含包路径(如:org.mypackage),它将被解析classpath的根目录。

信息一般被放在WAR结构的web项目的/lib/classes目录下。你也可以放在对应的jar文件中。

要注意的是:JDK中使用“.”作为路径的分隔符。也就是说“test.theme”实际表示为根目录下的“test/theme”目录。

 

B.1.1ResourceBundleMessageSource的配置

<!-- 资源文件绑定器 -->

<bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource">

    <property name="basename" value="messages" />

    <property name="useCodeAsDefaultMessage" value="true" />

</bean>

其中,message-info是你的properties文件的通用名。如:我的配置文件叫messages.propertiesmessages_zh_CN.properties等等。

 

B.1.2、范例说明

范例1

1.配置messagesSourcebean

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <!--bean的名称必须定义为messageSource  -->

    <bean id="messageSource"

       class="org.springframework.context.support.ResourceBundleMessageSource">

       <property name="basename">

           <value>spring.chapter13.demo2.messages</value>

           <!-- 前面的是包名,messages是配置文件的前缀 -->

       </property>

    </bean>

</beans>

关于basename的命名方式曾困扰我好久,特别是要加上包的名称,指定properties存放位置。一定要注意不然会报org.springframework.context.NoSuchMessageException的错

2.资源文件messages_zh_CN.properties

customer.name=david, age \: {0}, URL \: {1}

ABC=sdsd

3.测试类

package spring.chapter13.demo2;

import java.util.Locale;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.FileSystemXmlApplicationContext;

public class test {

    public static void main(String[] args) {     

       String fileName = "src/spring/chapter13/demo2/bean.xml";

       ApplicationContext context = new FileSystemXmlApplicationContext(fileName);

       String name = "";

       name = context.getMessage("ABC", null, Locale.CHINA);

       System.out.println(name);

       String namechinese = context.getMessage("customer.name", new Object[] {

              28, "http://www.xxx.com" }, Locale.SIMPLIFIED_CHINESE);

       System.out.println("Customer name (Chinese) : " + namechinese);

    }

}

因为ApplicationContext也是MessageSource接口的实现,故可以直接调用getMessage()方法。

 

CHandlerInterceptor(处理拦截器接口)

org.springframework.web.servlet.HandlerInterceptor

public interface HandlerInterceptor

C.1LocaleChangeInterceptor(处理拦截器实现)

org.springframework.web.servlet.i18n.LocaleChangeInterceptor

java.lang.Object
  org.springframework.web.servlet.handler.HandlerInterceptorAdapter
      org.springframework.web.servlet.i18n.LocaleChangeInterceptor

public class LocaleChangeInterceptor extends HandlerInterceptorAdapter

前面LocaleResolver是自动解析用户的本地化信息locale,除了这个方法外,还可以把一个Interceptor拦截器放到处理器controller中,以便在某种情况下改变locale。(例如:基于请求中参数变更locale)。

 

C.1.1、基于拦截器的范例

我们再回到《[spring]8 初识MVCSpring MVC框架》中的范例上,让我们在这个范例的基础上增加动态国际化支持,基于请求参数的动态国际。

范例2

1.Spring配置文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <!-- 定义一个自定义的locale解析器  -->

    <bean id="localeResolver"

       class="spring.chapter13.demo1.MyAcceptHeaderLocaleResolver">

    </bean>

    <!-- 定义一个locale的处理拦截器  -->

    <bean id="localeChangeInterceptor"    class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />

    <!-- 定义处理映射HandlerMapping -->

    <bean id="urlMapping"       class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

       <property name="interceptors" ref="localeChangeInterceptor" />

       <property name="mappings">

           <props>

              <prop key="helloWorld.form*">helloWorldAction</prop>

              <!-- 把对helloWorld.form访问映射到idhelloWorldActionbean -->

           </props>

       </property>

    </bean>

    <!-- 定义Controller -->

    <bean id="helloWorldAction"

       class="spring.chapter13.demo1.HelloWorldAction">

       <property name="helloWorld">

           <value>Hello Spring World!</value>

       </property>

       <property name="viewPage">

           <value>sayHello.jsp</value>

       </property>

    </bean>

</beans>

我们定义了locale解析器(localeResolver)用于解析locale,还定义了一个处理拦截器(HandlerInterceptor)用于拦截urllocale参数。并在处理映射(handlerMapping)中增加了拦截器(Interceptor)。

2.自定义的locale解析器

package spring.chapter13.demo1;

import java.util.Locale;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;

public class MyAcceptHeaderLocaleResolver extends AcceptHeaderLocaleResolver {

    private Locale myLocal;

    public Locale resolveLocale(HttpServletRequest request) {

       return myLocal;

    }

    public void setLocale(HttpServletRequest request,

           HttpServletResponse response, Locale locale) {

       myLocal = locale;

    }

}

若使用AcceptHeaderLocaleResolver类,程序运行会抛出异常"Cannot change HTTP accept header - use a different locale resolution strategy",根本原因是spring source做了限制,请注意上面的类,该类允许继承,所以需要改写setLocale方法。

3.资源文件的定义

<?xml version="1.0" encoding="UTF-8"?>

<beans >

    <!--bean的名称必须定义为messageSource  -->

    <bean id="messageSource"    class="org.springframework.context.support.ResourceBundleMessageSource">

       <property name="basename">

           <value>messages</value>

           <!-- 前面的是包名,messages是配置文件的前缀 -->

       </property>

    </bean>

</beans>

4.Controller处理器的处理方法

public ModelAndView handleRequest(HttpServletRequest req,

           HttpServletResponse res) throws Exception {     

       RequestContext requestContext = new RequestContext(req);

        Locale myLocale = requestContext.getLocale();

        String fileName = "../src/spring/chapter13/demo2/bean.xml";

       ApplicationContext context = new FileSystemXmlApplicationContext(

              fileName);

       String name = "";

       name = context.getMessage("ABC", null, myLocale);

       // 在该方法中处理用户请求

       Map model = new HashMap();

       model.put("helloWorld", getHelloWorld());

       // helloWorld属性存 model

       return new ModelAndView(getViewPage(), model);

       // 调用getViewPage获取要返回的页面

    }

 

D、用Spring标签实现国际化

Spring标签中实现国际化的标签为spring:message。详细细节见《[spring]14 使用Spring标签库》。

范例3

1.web.xml中加载spring配置文件

<!-- 使用监听器加载spring配置文件 -->

<context-param>

    <param-name>contextConfigLocation</param-name>

    <param-value>/WEB-INF/bean.xml</param-value>

</context-param>

<listener>

    <listener-class>

       org.springframework.web.context.ContextLoaderListener

    </listener-class>

</listener>

2.配置Spring配置文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <!--bean的名称必须定义为messageSource  -->

    <bean id="messageSource"

    class="org.springframework.context.support.ResourceBundleMessageSource">

       <property name="basename">

           <value>spring.chapter13.demo2.messages</value>

           <!-- 前面的是包名,messages是配置文件的前缀 -->

       </property>

    </bean>

</beans>

3.定义资源文件

customer.name=david china, age \: {0}, URL \: {1}

ABC=sdsdx

4.JSP文件中使用标签

<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="from"%>

<html>

    <head>

       <title></title>

    </head>

    <body>

       <spring:message code="ABC"></spring:message>

       <from:form></from:form>

    </body>

</html>



--------------------------------------------------------------------------------------------------------------------------------------------------

In Spring MVC application, comes with few “LocaleResolver” to support the internationalization or multiple languages features. In this tutorial, it shows a simple welcome page, display the message from properties file, and change the locale based on the selected language link.

1. Project Folder

Directory structure of this example.

SpringMVC-Internationalization-Folder
2. Properties file

Two properties files to store English and Chinese messages.

welcome.properties

welcome.springmvc = Happy learning Spring MVC

welcome_zh_CN.properties

welcome.springmvc = \u5feb\u4e50\u5b66\u4e60 Spring MVC
Note
For UTF-8 or non-English characters , you can encode it with  native2ascii tool.
3. Controller

Controller class, nothing special here, all the locale stuff is configure in the Spring’s bean configuration file later.

package com.mkyong.common.controller;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
 
public class WelcomeController extends AbstractController{
 
	@Override
	protected ModelAndView handleRequestInternal(HttpServletRequest request,
		HttpServletResponse response) throws Exception {
 
		ModelAndView model = new ModelAndView("WelcomePage");
		return model;
	}
 
}
4. Spring Configuration

To make Spring MVC application supports the internationalization, register two beans :

1. SessionLocaleResolver
Register a “SessionLocaleResolver” bean, named it exactly the same characters “localeResolver“. It resolves the locales by getting the predefined attribute from user’s session.

Note
If you do not register any “localeResolver”, the default  AcceptHeaderLocaleResolver will be used, which resolves the locale by checking the accept-language header in the HTTP request.

2. LocaleChangeInterceptor
Register a “LocaleChangeInterceptor” interceptor and reference it to any handler mapping that need to supports the multiple languages. The “paramName” is the parameter value that’s used to set the locale.

In this case,

  1. welcome.htm?language=en – Get the message from English properties file.
  2. welcome.htm?language=zh_CN – Get the message from Chinese properties file.
	<bean id="localeChangeInterceptor"
		class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
		<property name="paramName" value="language" />
	</bean>
 
	<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" >
		<property name="interceptors">
		   <list>
			<ref bean="localeChangeInterceptor" />
		    </list>
		</property>
	</bean>

See full example below
mvc-dispatcher-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
	<bean id="localeResolver"
		class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
		<property name="defaultLocale" value="en" />
	</bean>
 
	<bean id="localeChangeInterceptor"
		class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
		<property name="paramName" value="language" />
	</bean>
 
	<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" >
		<property name="interceptors">
		   <list>
			<ref bean="localeChangeInterceptor" />
		   </list>
		</property>
	</bean>
 
	<!-- Register the bean -->
	<bean class="com.mkyong.common.controller.WelcomeController" />
 
	<!-- Register the welcome.properties -->
	<bean id="messageSource"
		class="org.springframework.context.support.ResourceBundleMessageSource">
		<property name="basename" value="welcome" />
	</bean>
 
	<bean id="viewResolver"
    	class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
        <property name="prefix">
            <value>/WEB-INF/pages/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
 
</beans>
5. JSP

A JSP page, contains two hyperlinks to change the locale manually, and use the spring:message to display the message from the corresponds properties file by checking the current user’s locale.

WelcomePage.jsp

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
<body>
<h1>Spring MVC internationalization example</h1>
 
Language : <a href="?language=en">English</a>|<a href="?language=zh_CN">Chinese</a>
 
<h3>
welcome.springmvc : <spring:message code="welcome.springmvc" text="default text" />
</h3>
 
Current Locale : ${pageContext.response.locale}
 
</body>
</html>
Note
The ${pageContext.response.locale} can be used to display the current user’s locale.
Warning
Remember put the “<%@ page contentType=”text/html;charset=UTF-8″ %>” on top of the page, else the page may not able to display the UTF-8 (Chinese) characters properly.
7. Demo

Access it via http://localhost:8080/SpringMVC/welcome.htm, change the locale by clicking on the language’s link.

1. English locale – http://localhost:8080/SpringMVC/welcome.htm?language=en

SpringMVC-Internationalization-Example-1

2. Chinese locale – http://localhost:8080/SpringMVC/welcome.htm?language=zh_CN

SpringMVC-Internationalization-Example-2

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值