zoukankan      html  css  js  c++  java
  • 第一节:SpringMVC 国际化

    一、简单国际化

      1、操作步骤

        (1)编写国际化资源文件;

        (2)让 SpringMVC 的 ResourceBundleMessageSource 管理国际化资源文件;

        (3)在页面中通过标签取值;

      2、代码示例

        (1)国际化资源文件

          中文:login_zh_CN.properties

    welcomeInfo=欢迎来到登录页面
    username=用户名
    password=密码
    loginBtn=登录

          英文:login_en_US.properties

    welcomeInfo=welcom to login
    username=USERNAME
    password=PASSWORD
    loginBtn=LOGIN

        (2)配置文件

        <!--  让SpringMVC管理国际化  id 必须是 messageSource-->
        <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
            <property name="basename" value="login"/>
        </bean>

        (3)控制器跳转

        @RequestMapping(value = "/toLoginPage")
        public String toLoginPage() {
            return "login";
        }

        (4)页面取值

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
    <html>
    <head>
        <title>登录</title>
    </head>
    <body>
    <h1>
        <fmt:message key="welcomeInfo" />
    </h1>
    <form action="" method="post">
        <fmt:message key="username" /><input /><br>
        <fmt:message key="password" /><input /><br>
        <input type="submit" value='<fmt:message key="loginBtn" />'/>
    </form>
    
    </body>
    </html>

    二、区域信息解析器

       国际化的区域信息是决定国际化显示的因素。

       SpringMVC 中区域信息是又是区域信息解析器得到的:

       DispatcherServlet 中:

    /** LocaleResolver used by this servlet */
    private LocaleResolver localeResolver;

      现象:区域是按照浏览器带来语言信息决定

    Locale locale = request.getLocale(); //获取到浏览器的区域信息
    

      

      来看 LocaleResolver 的装配:

        /**
         * Initialize the LocaleResolver used by this class.
         * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
         * we default to AcceptHeaderLocaleResolver.
         */
        private void initLocaleResolver(ApplicationContext context) {
            try {
                this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
                if (logger.isDebugEnabled()) {
                    logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
                }
            }
            catch (NoSuchBeanDefinitionException ex) {
                // We need to use the default.
                this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);//加载默认的策略
                if (logger.isDebugEnabled()) {
                    logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
                            "': using default [" + this.localeResolver + "]");
                }
            }
        }

      如果配置文件中没有配置区域解析器,会加载 DispatcherServlet.properties 中的区域解析器:

    org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

      所有用到区域信息的地方,默认都会用AcceptHeaderLocaleResolver获取的:

    public class AcceptHeaderLocaleResolver implements LocaleResolver {
    
        @Override
        public Locale resolveLocale(HttpServletRequest request) {
            return request.getLocale();
        }
    
        @Override
        public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
            throw new UnsupportedOperationException(
                    "Cannot change HTTP accept header - use a different locale resolution strategy");
        }
    
    }

      等到其他地方再用到区域解析器的时候,直接获取:

    Locale locale = this.localeResolver.resolveLocale(request);
    

      

    三、程序中获取国际化信息

      SpringMVC 使用 MessageSource 帮我们管理了国际化配置,可以通过注入 messageSource 来获取国际化信息

    @Controller
    public class I18nTestController {
    
        @Autowired
        private ResourceBundleMessageSource messageSource;
        
        
        @RequestMapping(value = "/toLoginPage")
        public String toLoginPage(Locale locale) {
            System.out.println("locale = " + locale);
            String key = "welcomeInfo";
            //第一个参数:获取的key;第二个参数:国际化文件中动态参数;第三个参数:Locale 区域信息
            String message = messageSource.getMessage(key, null, locale);
            System.out.println("message = " + message);
            return "login";
        }
    }

    四、动态切换国际化——自定义区域解析器

      我们可以通过自定义区域解析器来替换默认的 AcceptHeaderLocaleResolver 区域解析器:

      (1)页面发送请求及请求参数

    <a href="${ctp}/toLoginPage?locale=zh_CN">中文</a>|<a href="${ctp}/toLoginPage?locale=en_US">English</a>

      (2)自定义区域解析器

    public class MyLocaleResolver implements LocaleResolver {
    
        /**
         * 解析返回 Locale,如果带了请求参数 locale,就获取参数的信息,否则就获取请求的区域信息
         * @param request
         * @return
         */
        @Override
        public Locale resolveLocale(HttpServletRequest request) {
            Locale locale = null;
    
            String localeStr = request.getParameter("locale");
            System.out.println("localeStr = " + localeStr);
            if (localeStr != null && !"".equals(localeStr)) {
                locale = new Locale(localeStr.split("_")[0], localeStr.split("_")[1]);
            } else {
                locale = request.getLocale();
            }
            return locale;
        }
    
        /**
         * 修改 Locale
         * @param request
         * @param response
         * @param locale
         */
        @Override
        public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
            throw new UnsupportedOperationException(
                    "Cannot change HTTP accept header - use a different locale resolution strategy");
        }
    }

      (3)配置区域解析器

        <!--  自定义区域信息解析器  -->
        <bean id="localeResolver" class="com.njf.component.MyLocalResolver"></bean>

      (4)控制器

    @Controller
    public class I18nTestController {
    
        @Autowired
        private ResourceBundleMessageSource messageSource;
        
        
        @RequestMapping(value = "/toLoginPage")
        public String toLoginPage(Locale locale) {
            System.out.println("locale = " + locale);
            String key = "welcomeInfo";
            String message = messageSource.getMessage(key, null, locale);
            System.out.println("message = " + message);
            return "login";
        }
    }

      (5)页面取值

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
    <html>
    <head>
        <title>登录</title>
    </head>
    <body>
    <h1>
        <fmt:message key="welcomeInfo" />
    </h1>
    <form action="" method="post">
        <fmt:message key="username" /><input /><br>
        <fmt:message key="password" /><input /><br>
        <input type="submit" value='<fmt:message key="loginBtn" />'/>
    </form>
    
    </body>
    </html>

    五、各种区域解析器

      区域解析器继承树:

       

       (1)AcceptHeaderLocaleResolver:使用请求头的区域信息

    public class AcceptHeaderLocaleResolver implements LocaleResolver {
    
        @Override
        public Locale resolveLocale(HttpServletRequest request) {
            return request.getLocale();
        }
    
        @Override
        public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
            throw new UnsupportedOperationException(
                    "Cannot change HTTP accept header - use a different locale resolution strategy");
        }
    
    }

       (2)MyLocaleResolver:自定义区域解析器

       (3)SessionLocalResolver:区域信息是从 session 中获取,可以根据请求参数创建一个 locale 对象,放在 session 中;

    public class SessionLocaleResolver extends AbstractLocaleContextResolver {
        @Override
        public Locale resolveLocale(HttpServletRequest request) {
            Locale locale = (Locale) WebUtils.getSessionAttribute(request, LOCALE_SESSION_ATTRIBUTE_NAME);
            if (locale == null) {
                locale = determineDefaultLocale(request);
            }
            return locale;
        }
    
        @Override
        public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, LocaleContext localeContext) {
            Locale locale = null;
            TimeZone timeZone = null;
            if (localeContext != null) {
                locale = localeContext.getLocale();
                if (localeContext instanceof TimeZoneAwareLocaleContext) {
                    timeZone = ((TimeZoneAwareLocaleContext) localeContext).getTimeZone();
                }
            }
            WebUtils.setSessionAttribute(request, LOCALE_SESSION_ATTRIBUTE_NAME, locale);
            WebUtils.setSessionAttribute(request, TIME_ZONE_SESSION_ATTRIBUTE_NAME, timeZone);
        }
    
    }

       (4)FixedLocalResolver:获取本地固定的区域信息,使用系统默认的区域信息

    public class FixedLocaleResolver extends AbstractLocaleContextResolver {
        @Override
        public Locale resolveLocale(HttpServletRequest request) {
            Locale locale = getDefaultLocale();
            if (locale == null) {
                locale = Locale.getDefault();
            }
            return locale;
        }
    
        @Override
        public LocaleContext resolveLocaleContext(HttpServletRequest request) {
            return new TimeZoneAwareLocaleContext() {
                @Override
                public Locale getLocale() {
                    return getDefaultLocale();
                }
                @Override
                public TimeZone getTimeZone() {
                    return getDefaultTimeZone();
                }
            };
        }
    
        @Override
        public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, LocaleContext localeContext) {
            throw new UnsupportedOperationException("Cannot change fixed locale - use a different locale resolution strategy");
        }
    
    }

       (5)CookieLocaleResolver:区域信息是从 cookie中获取

    public class CookieLocaleResolver extends CookieGenerator implements LocaleContextResolver {
    
        @Override
        public Locale resolveLocale(HttpServletRequest request) {
            parseLocaleCookieIfNecessary(request);
            return (Locale) request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
        }
    
        @Override
        public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
            setLocaleContext(request, response, (locale != null ? new SimpleLocaleContext(locale) : null));
        }
    }

    六、动态切换国际化——使用 SessionLocaleResolver

      1、配置 SessionLocaleResolver

        <!--  区域信息从 session 中获取  -->
        <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/>

      2、控制器方法

      从请求参数中获取 locale 参数,然后把区域信息手动放到 session 域中:

        @RequestMapping(value = "/toLoginPage")
        public String toLoginPage(@RequestParam(value = "locale", defaultValue = "zh_CN") String localeStr, Locale locale, HttpSession session) {
            System.out.println("locale = " + locale);
            String key = "welcomeInfo";
            String message = messageSource.getMessage(key, null, locale);
            System.out.println("message = " + message);
    
            Locale localeInfo = null;
            System.out.println("localeStr = " + localeStr);
            if (localeStr != null && !"".equals(localeStr)) {
                localeInfo = new Locale(localeStr.split("_")[0], localeStr.split("_")[1]);
            } else {
                localeInfo = locale;
            }
    
            //把区域信息存在session中
            session.setAttribute(SessionLocaleResolver.class.getName() + ".LOCALE", localeInfo);
    
            return "login";
        }

    七、动态切换国际化——使用SessionLocaleResolver 与LocaleChangeInterceptor 拦截器

      1、配置拦截器(需要配置 SessionLocaleResolver 和 LocaleChangeInterceptor )

        <!--  区域信息从 session 中获取  -->
        <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/>
    
        <!--  配置国际化拦截器  -->
        <mvc:interceptors>
            <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
        </mvc:interceptors>

      2、控制器方法

        @RequestMapping(value = "/toLoginPage")
        public String toLoginPage(@RequestParam(value = "locale", defaultValue = "zh_CN") String localeStr, Locale locale, HttpSession session) {
            System.out.println("locale = " + locale);
            String key = "welcomeInfo";
            String message = messageSource.getMessage(key, null, locale);
            System.out.println("message = " + message);
    
            return "login";
        }

      3、LocaleChangeInterceptor 源码

    public class LocaleChangeInterceptor extends HandlerInterceptorAdapter {
    
        /**
         * Default name of the locale specification parameter: "locale".
         */
        public static final String DEFAULT_PARAM_NAME = "locale";
    
        private String paramName = DEFAULT_PARAM_NAME;
    
    
        /**
         * Set the name of the parameter that contains a locale specification
         * in a locale change request. Default is "locale".
         */
        public void setParamName(String paramName) {
            this.paramName = paramName;
        }
    
        /**
         * Return the name of the parameter that contains a locale specification
         * in a locale change request.
         */
        public String getParamName() {
            return this.paramName;
        }
    
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws ServletException {
    
            String newLocale = request.getParameter(this.paramName);
            if (newLocale != null) {
                LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
                if (localeResolver == null) {
                    throw new IllegalStateException("No LocaleResolver found: not in a DispatcherServlet request?");
                }
                localeResolver.setLocale(request, response, StringUtils.parseLocaleString(newLocale));
            }
            // Proceed in any case.
            return true;
        }
    
    }

       拦截器会从请求中获取 locale 参数,然后把区域化信息放在 session 域中。

      注意:使用拦截器切换语言的参数名称必须:locale

    八、总结

      1、默认情况下,SpringMVC  根据 Accept-Language 参数判断客户端的本地化类型。

      2、当接受到请求时,SpringMVC 会在上下文中查找一个本地化解析器(LocalResolver),找到后使用它获取请求所对应的本地化类型信息。

      3、SpringMVC 还允许装配一个动态更改本地化类型的拦截器,这样通过指定一个请求参数就可以控制单个请求的本地化类型。

      4、SessionLocaleResolver & LocaleChangeInterceptor 工作原理 

      

      5、本地化解析器和本地拦截器

        AcceptHeaderLocaleResolver根据 HTTP 请求头的 Accept-Language 参数确定本地化类型,如果没有显式定义本地化解析器, SpringMVC 使用该解析器。
        CookieLocaleResolver:根据指定的 Cookie 值确定本地化类型
        SessionLocaleResolver:根据 Session 中特定的属性确定本地化类型
        LocaleChangeInterceptor:从请求参数中获取本次请求对应的本地化类型。

        

  • 相关阅读:
    iOS IM开发建议(三)添加一个自定义键盘
    iOS IM开发建议(二)计算TableViewCell的高度:图文混排
    iOS IM开发建议(一)App框架设计
    iOS IM开发准备工作(五)iOS中的struct怎么处理
    关东升的iOS实战系列图书 《iOS实战:入门与提高卷(Swift版)》已经上市
    关东升的《从零开始学Swift》3月9日已经上架
    《从零开始学Swift》学习笔记(Day 71)——Swift与C/C++混合编程之数据类型映射
    《从零开始学Swift》学习笔记(Day 70)——Swift与Objective-C混合编程之Swift与Objective-C API映射
    《从零开始学Swift》学习笔记(Day 69)——Swift与Objective-C混合编程之语言
    《从零开始学Swift》学习笔记(Day 10)——运算符是“ +、-、*、/ ”吗?
  • 原文地址:https://www.cnblogs.com/niujifei/p/15650764.html
Copyright © 2011-2022 走看看