您的位置:首页 > 编程语言 > Java开发

spring - 国际化

2015-12-01 15:10 369 查看

一、国际化

国际化指的是:在web开发(http协议的website/web-service)中,对于不同的语言环境给出相应的语言数据。

基本实现思路:

1. 判断 - 两种方式

根据Request Headers中的Accept-language来判断。

要求客户端第一次(也可以每次)传递的自定义参数值来判断,如规定传locale,值为:zh-cn、en-us等等内容。

2. 请求与状态保存

WEB应用

后台判断时机

设置一个专门的”语言切换请求”,对应前端首页右上角弄个切换语言下拉框;

进入首页时判断一次;

后台状态保存

在如上的判断时机情况下,把语言标识放入session中,需要国际化数据的请求都去session中取语言标识。

cookie如上,只不过将语言标识放入客户端,然后再每次请求中取值。

web-service:没办法,只能每次都在请求本身上去判断了。

3. 数据源

如果数据是可以被管理系统编辑的:将其存入数据库表中,一种语言一个字段。

如果数据是不变(最多只允许管理员或程序员去手写修改)的:将其存入服务器的静态资源文件中,一种语言一个静态资源文件(java中是properties文件)。

4. 读取

根据请求的判断结果(请求本身/session/cookie),读取不同数据源即可。

二、spring中

1. 首先定义好相应的国际化资源文件:



后缀名要按规定写成*_语言码_地区码.properties,值有哪些可以查看java.util.Locale中的定义;

在相应的properties文件中key写一样,value写成不同的语言

messages_en.properties:
error.user.userName.NotBlank = userName Cann't be Blank

messages_zh_CN.properties:
error.user.userName.NotBlank = userName不能为空


2. 配置spring

spring-context.jar中提供了一个消息源类org.springframework.context.support.ResourceBundleMessageSource,来容纳properties文件的消息内容,设置其basename属性后,容器就将其指定value前缀的properties文件都加载进这一个messageSource中。

spring容器ApplicationContext的所有子类都实现了MessageSource接口,能直接使用容器的方法取出资源中数据。

<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n.messages"/>
</bean>


3. java实现

当实例化spring容器(context)之后,就可以直接使用容器的方法getMessage(**)来获取对应不同Locale的消息了

MessageSource messageSource = new ClassPathXmlApplicationContext("spring-context-i18n.xml");
//ApplicationContext messageSource = new ClassPathXmlApplicationContext("spring-context-i18n.xml");
String message1 = messageSource.getMessage("error.user.userName.NotBlank", null, Locale.UK);
//String message2 = messageSource.getMessage("error.user.userName.Length", new Object[]{"10"}, Locale.CHINESE);
System.out.println(message1);
//System.out.println(message2);


编码问题

1. 改变properties文件编码为UTF-8/GBK,然后ResourceBundleMessageSource的默认编码defaultEncoding是ISO-8859-1,你可以在xml中增加一个相应属性将其改变为你需要的UTF-8/GBK之类。
2. 如果资源文件想统一使用ISO-8859-1格式也没关系,你可以将原本用UTF-8写好的中文资源文件使用jdk自带的工具native2ascii将UTF-8文件和内容转为ISO-8859-1文件,其中的中文内容会使用16进制unicode编码为\u****格式;


cmd命令:
JAVA_HOME\bin\native2ascii -encoding UTF-8 messages_zh_CN.properties messages_zh_C1N.properties

################## User #####################
error.user.userName.NotBlank = userName不能为空

↓

################## User #####################
error.user.userName.NotBlank = userName\u4e0d\u80fd\u4e3a\u7a7a


三、spring-mvc中

1. 场景与思路一

场景 :RESTful web service中验证前台传递的参数,如果错误返回国际化错误信息。

1. 定义国际化资源文件messageSource。

2. 使用基于JSR349 Bean Validation 1.1 (老版本JSR303 1.0)的hibernate实现方案,并制定这个validator的messageSource为1中我们定义的。

3. 指定RequestMappingHandlerMapping(支持@Valid)默认使用的validator为2中的。

4. 定义Request DTO,并在其字段上定义校验规则。

5. 在Controller的method上声明使用注解@Valid式验证bean,然后将返回结果绑定在Error(BeanPropertyBindingResult)上。

2. 分解步骤

1. 123xml(properties见二.1)

<!-- 仅scan所有的@controller -->
<context:component-scan base-package="com.ddup" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 3 -->
<mvc:annotation-driven validator="validator"/>
<!-- 1 -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="defaultEncoding" value="UTF-8"/>
<property name="basename" value="i18n.messages"/>
<property name="useCodeAsDefaultMessage" value="true" />
</bean>
<!-- 2 -->
<bean id="validator"  class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass"  value="org.hibernate.validator.HibernateValidator"/>
<property name="validationMessageSource" ref="messageSource"/>
</bean>


2. DTO

@NotBlank(message = "{error.user.userName.NotBlank}")
private String userName;
get/set...


3. Controller

@RequestMapping(value = "/login")
public String login(@Valid TestReq dtoReq, Errors errors){...}


2. 场景与思路二

场景 :验证前台传递的参数,如果错误返回国际化错误信息。

1. 拦截请求,并根据请求或者默认的设置来getMessage返回

分解步骤

1. 拦截请求
RequestMappingHandlerMapping

并不该拦截所有的请求,只应该拦截发布了url的请求(
@RequestMapping
),所以使用:

<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<!-- 拦截器 Interceptors -->
<property name="interceptors">
<list>
<!-- i18n -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
</list>
</property>
</bean>


其中RequestMappingHandlerMapping(请求映射处理器映射)是默认的加载
@RequestMapping
注解的类。

2. 拦截器
LocaleChangeInterceptor

我们只需要给
RequestMappingHandlerMapping
配置拦截器
LocaleChangeInterceptor
,这是一个接口也可括展实现。内容是:

LocaleChangeInterceptor去请求中找国际化参数(默认为locale)如果找到了,就继续从request的attribute中找到LocalResolver,并setLocale


@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws ServletException {

String newLocale = request.getParameter(getParamName());
if (newLocale != null) {
if (checkHttpMethod(request.getMethod())) {
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
if (localeResolver == null) {...}
try {
localeResolver.setLocale(request, response, StringUtils.parseLocaleString(newLocale));
}
catch (IllegalArgumentException ex) {...}
}
}
return true;
}


3. Locale解析器
LocaleResolver

<bean id="validator"  class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass"  value="org.hibernate.validator.HibernateValidator"/>
<!-- 如果不加默认到 使用classpath下的 ValidationMessages.properties -->
<property name="validationMessageSource" ref="messageSource"/>
</bean>




2. 对应上面的两种思路,在spring-mvc中分别有几个解析器

- AcceptHeaderLocaleResolver:请求头中的参数

- FixedLocaleResolver:固定的(默认jvm的locale)

- SessionLocaleResolver:设置session方式

- CookieLocaleResolver:设置cookie方式

- AbstractLocaleResolver:当然你也可以继承这个抽象类,来实现自己的个性化国际化需求

2. 步骤:

1. DispatcherServlet收到request后会去找LocaleResolver,如果找到了一个实现类(上面几个)那么就会调用它;

2. 任意一个LocaleResolver中的resolveLocale被调用后,会根据相应策略返回一个Locale对象;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: