国际化指的是:在web开发(http协议的website/web-service)中,对于不同的语言环境给出相应的语言数据。
- 根据Request Headers中的Accept-language来判断。
- 要求客户端第一次(也可以每次)传递的自定义参数值来判断,如规定传locale,值为:zh-cn、en-us等等内容。
- 如果数据是可以被管理系统编辑的:将其存入数据库表中,一种语言一个字段。
- 如果数据是不变(最多只允许管理员或程序员去手写修改)的:将其存入服务器的静态资源文件中,一种语言一个静态资源文件(java中是properties文件)。
根据请求的判断结果(请求本身/session/cookie),读取不同数据源即可。
messages_en.properties:
error.user.userName.NotBlank = userName Cann't be Blank
messages_zh_CN.properties:
error.user.userName.NotBlank = userName不能为空
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n.messages"/>
</bean>
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
场景 :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)上。
<!-- 仅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>
@NotBlank(message = "{error.user.userName.NotBlank}")
private String userName;
get/set...
@RequestMapping(value = "/login")
public String login(@Valid TestReq dtoReq, Errors errors){...}
场景 :验证前台传递的参数,如果错误返回国际化错误信息。
1. 拦截请求,并根据请求或者默认的设置来getMessage返回
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
注解的类。
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;
}
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对象;