spring - 国际化

一、国际化

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

基本实现思路:

1. 判断 - 两种方式

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

2. 请求与状态保存

  • WEB应用
    • 后台判断时机
      1. 设置一个专门的”语言切换请求”,对应前端首页右上角弄个切换语言下拉框;
      2. 进入首页时判断一次;
    • 后台状态保存
      1. 在如上的判断时机情况下,把语言标识放入session中,需要国际化数据的请求都去session中取语言标识。
      2. cookie如上,只不过将语言标识放入客户端,然后再每次请求中取值。
        web-service:没办法,只能每次都在请求本身上去判断了。

3. 数据源

  1. 如果数据是可以被管理系统编辑的:将其存入数据库表中,一种语言一个字段。
  2. 如果数据是不变(最多只允许管理员或程序员去手写修改)的:将其存入服务器的静态资源文件中,一种语言一个静态资源文件(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

  1. 并不该拦截所有的请求,只应该拦截发布了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

  1. 我们只需要给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>

spring - 国际化_第1张图片
2. 对应上面的两种思路,在spring-mvc中分别有几个解析器
- AcceptHeaderLocaleResolver:请求头中的参数
- FixedLocaleResolver:固定的(默认jvm的locale)
- SessionLocaleResolver:设置session方式
- CookieLocaleResolver:设置cookie方式
- AbstractLocaleResolver:当然你也可以继承这个抽象类,来实现自己的个性化国际化需求
2. 步骤:
1. DispatcherServlet收到request后会去找LocaleResolver,如果找到了一个实现类(上面几个)那么就会调用它;
2. 任意一个LocaleResolver中的resolveLocale被调用后,会根据相应策略返回一个Locale对象;

你可能感兴趣的:(java,spring,web开发,javaweb,国际化)