资讯专栏INFORMATION COLUMN

SpringMVC之源码分析--LocaleResolver(二)

RichardXG / 3112人阅读

摘要:概述上一篇就默认的进行了分析,详细请参考,本节我们继续分析学习,主要分析解析器类继承关系如下图由上面类图可知,继承并实现接口,主要是操作的工具类,继承接口,增加了信息操作。即通过实现的选择。

概述

上一篇就Spring MVC默认的LocaleResovler(AcceptHeaderLocaleResolver)进行了分析,详细请参考https://segmentfault.com/a/1190000014797899,本节我们继续分析学习,主要分析CookieLocaleResolver

解析器(CookieLocaleResolver)

CookieLocaleResolver类继承关系如下图:

由上面类图可知,CookieLocaleResolver继承CookieGenerator并实现LocaleContextResolver接口,CookieGenerator主要是操作Cookie的工具类,LocaleContextResolver继承LacleResovler接口,增加了TimeZone信息操作。即通过Cookie实现Locale的选择。

CookieLocaleResolver类的入口是resolveLocaleContext(final HttpServletRequest request),即Spring MVC接收到客户端请求后,会调用此方法,源码如下:

@Override
public LocaleContext resolveLocaleContext(final HttpServletRequest request) {
    // 解析Cookie信息
    parseLocaleCookieIfNecessary(request);
    // 返回Locale和TimeZone
    return new TimeZoneAwareLocaleContext() {
        @Override
        @Nullable
        public Locale getLocale() {
            return (Locale) request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
        }
        @Override
        @Nullable
        public TimeZone getTimeZone() {
            return (TimeZone) request.getAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME);
        }
    };
}

private void parseLocaleCookieIfNecessary(HttpServletRequest request) {
    // 第一次请求为null
    if (request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME) == null) {
        Locale locale = null; // 地区
        TimeZone timeZone = null; // 时区

        // 获取cookie的名称,取自Spring MVC配置,默认为:CookieLocaleResolver.DEFAULT_COOKIE_NAME
        String cookieName = getCookieName();
        if (cookieName != null) {
            // 根据名称获取当前请求中的Cookie(第一次访问为null)
            Cookie cookie = WebUtils.getCookie(request, cookieName);
            if (cookie != null) {
                // 以下主要是从客户端Cookie中解析出Locale
                String value = cookie.getValue();
                String localePart = value;
                String timeZonePart = null;
                int spaceIndex = localePart.indexOf(" ");
                if (spaceIndex != -1) {
                    localePart = value.substring(0, spaceIndex);
                    timeZonePart = value.substring(spaceIndex + 1);
                }
                try {
                    locale = (!"-".equals(localePart) ? parseLocaleValue(localePart) : null);
                    if (timeZonePart != null) {
                        timeZone = StringUtils.parseTimeZoneString(timeZonePart);
                    }
                }
                catch (IllegalArgumentException ex) {
                    if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
                        // Error dispatch: ignore locale/timezone parse exceptions
                        if (logger.isDebugEnabled()) {
                            logger.debug("Ignoring invalid locale cookie "" + cookieName +
                                    "" with value [" + value + "] due to error dispatch: " + ex.getMessage());
                        }
                    }
                    else {
                        throw new IllegalStateException("Invalid locale cookie "" + cookieName +
                                "" with value [" + value + "]: " + ex.getMessage());
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Parsed cookie value [" + cookie.getValue() + "] into locale "" + locale +
                            """ + (timeZone != null ? " and time zone "" + timeZone.getID() + """ : ""));
                }
            }
        }
        // 把Locale设置到请求的Attribute区,客户端请求没有携带Cookie,取Spring MVC中配置的defaultLocale
        request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME,
                (locale != null ? locale : determineDefaultLocale(request)));
        request.setAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME,
                (timeZone != null ? timeZone : determineDefaultTimeZone(request)));
    }
}

// 设置Locale
@Override
public void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale) {
    setLocaleContext(request, response, (locale != null ? new SimpleLocaleContext(locale) : null));
}

// 主要是把Locale信息写回客户端
@Override
public void setLocaleContext(HttpServletRequest request, @Nullable HttpServletResponse response,
        @Nullable LocaleContext localeContext) {

    Assert.notNull(response, "HttpServletResponse is required for CookieLocaleResolver");

    Locale locale = null;
    TimeZone timeZone = null;
    if (localeContext != null) {
        locale = localeContext.getLocale();
        if (localeContext instanceof TimeZoneAwareLocaleContext) {
            timeZone = ((TimeZoneAwareLocaleContext) localeContext).getTimeZone();
        }
        addCookie(response,
                (locale != null ? toLocaleValue(locale) : "-") + (timeZone != null ? " " + timeZone.getID() : ""));
    }
    else {
        removeCookie(response);
    }
    request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME,
            (locale != null ? locale : determineDefaultLocale(request)));
    request.setAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME,
            (timeZone != null ? timeZone : determineDefaultTimeZone(request)));
}
实战

项目结构

参考上一章https://segmentfault.com/a/1190000014797899中的项目结构,本章与其一致。

配置文件

在Spring MVC配置文件中配置资源加载以及CookieLocaleResolver Bean,配置如下:



    
    
    
    
    



    
    
    
    
    




属性文件

参考上一章https://segmentfault.com/a/1190000014797899中的项目结构,本章与其一致。

控制器

编写Controller控制器,以便测试,代码如下:

/**
 * 通过Controller修改系统Locale信息
 */
@GetMapping(value = "/setCookieLocale" , produces = "text/html;charset=UTF-8")
@ResponseBody
public String cookieLocaleResolver(HttpServletRequest request , HttpServletResponse response) {

    LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
    String locale = (String)request.getParameter("locale");
    localeResolver.setLocale(request , response , parseLocaleValue(locale));
    return "设置Locale成功";
}

/**
 * 查看Locale信息
 */
@GetMapping(value = "/getCookieLocale" , produces = "text/html;charset=UTF-8")
@ResponseBody
public String cookieLocaleResolver2(HttpServletRequest request , HttpServletResponse response) {

    String clientLocale = "";
    Cookie[] cookies = request.getCookies();
    if(cookies != null){
        for(Cookie cookie : cookies){
            clientLocale +=cookie.getName()+"="+cookie.getValue()+",";
        }
    }
    System.out.println(clientLocale);
    RequestContext requestContext = new RequestContext(request);
    String value = requestContext.getMessage("message.locale");
    return "客户端发送的Cookie有:"+clientLocale+" 
当前使用的Locale是:" + requestContext.getLocale() + "
使用的资源Locale文件是:" + value ; }

测试

以chrome为客户端,首先清除浏览器cookie,可在设置--内容管理--Cookie--查看所有Cookie和网站数据中查看是,如下图:

我们的浏览器客户端中的Cookie为空,我们还没有到调用设置Locale的方法,此时我们访问http://localhost:8089/getCookieLocale查看系统的Locale信息,如下图:

由此可见,系统使用的在Spring MVC中配置的Locale信息(详见上面的配置),并且请求头和返回头中都没有Cookie数据(服务器没有回写Cookie给客户端),接着我们调用http://localhost:8089/setCookieLocale?locale=en_US,此时,查看该请求的响应头,如下图:

由此可见,服务器端已经把Locale设置成功,并且通过response回写给客户端,当然也可查询下浏览器中已有的Cookie,如下图:

再次调用http://localhost:8089/getCookieLocale查看系统的Locale信息,如下图:

当然可以把语言环境设置为了中文,如调用http://localhost:8089/setCookieLocale?locale=zh_CN即可。

至此,我们简单分析了CookieLocaleResolver的核心源码、实现以及验证,此例仅仅是作为学习LocaleResolver,真实项目中可通过拦截器来实现,Spring提供了LocaleChangeInterceptor,也可自定义实现,其实就是重写LocaleResolver接口setLocale方法。

总结

CookieLocaleResolver可用于没有用户会话的无状态应用程序

可与拦截器结合使用实现应用的国际化

最后创建了qq群方便大家交流,可扫描加入,同时也可加我qq:276420284,共同学习、共同进步,谢谢!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69341.html

相关文章

  • SpringMVC源码分析--LocaleResolver(三)

    摘要:概述我们继续分析学习,本节我们分析使用的是。与类似,运用用户会话实现功能。最后创建了群方便大家交流,可扫描加入,同时也可加我,共同学习共同进步,谢谢 概述 我们继续分析学习Spring MVC LocaleResolver,本节我们分析使用的是SessionLocaleResolver。SessionLocaleResolver与CookieLocaleResolver类似,运用用户会...

    VishKozus 评论0 收藏0
  • SpringMVC源码分析--LocaleResolver和ThemeResolver应用

    摘要:需求根据客户端环境,界面显示不同的国旗图案。选择的技术方案可利用提供的国际化和主题定制来解决。注意此时返回的中没有国际化及主题相关的信息。修改请求参数的值为荷兰,即后再发起请求,结果如下与预期一致,测试通过。 概述 以上分析了Spring MVC的LocaleResolver和ThemeResolver两个策略解析器,在实际项目中很少使用,尤其是ThemeResolver,花精力去分析...

    qpal 评论0 收藏0
  • SpringMVC源码分析--LocaleResolver(一)

    摘要:概述为我们提供国际化支持,通过设置系统的环境,根据运行环境使用不同的语言显示。提供接口的作用是解析客户端使用的地区,目的是为了根据这些信息实现视图多语言即国际化。接口继承接口,增加时区支持。 概述 Spring MVC为我们提供国际化支持,通过设置系统的环境,根据运行环境使用不同的语言显示。Spring提供LocaleResolver接口的作用是解析客户端使用的地区(Locale),目...

    HtmlCssJs 评论0 收藏0
  • SpringMVC源码分析--ThemeResolver(一)

    摘要:此解析器不能动态设置主题。实战目标练习使用解析器,最终效果如下项目结构在下创建了主题文件夹及主题文件,下创建了静态资源文件。是默认的解析器,再此配置是为了自定义属性值,即属性文件名称。其实此解析器与的实现原理基本相同。 概述 主题就是系统的整体样式或风格,可通过Spring MVC框架提供的主题(theme)设置应用的整体样式风格,提高用户体验。Spring MVC的主题就是一些静态资...

    Ocean 评论0 收藏0
  • SpringMVC源码分析--ThemeResolver(三)

    摘要:类继承关系如下该类实现接口,实现解析设置主题功能继承类,以具备操作功能。新增并更换一张不同的图片。配置文件只要替换即可,代码如下配置默认的主题文件视图和控制器视图和控制器代码与上一章一致,参考上章代码。 概述 上节介绍了SessionThemeResolver解析器,本章分析下CookieThemeResolver,两个解析器实现的功能是一样的,只是使用的主题载体有区别而已,Sessi...

    OldPanda 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<