springMVC源码分析--国际化LocaleResolver(一)
springMVC给我们提供了国际化支持,简单来说就是设置整个系统的运行语言,然后根据系统的运行语言来展示对应语言的页面,一般我们称之为多语言。springMVC国际化机制就是可以设置整个系统的运行语言,其定义了一个国际化支持接口LocaleResolver,提供的默认实现类如下图。
springMVC国际化提供了四个默认实现的类AcceptHeaderLocaleResolver,FixedLocaleResolver、CookieLocaleResolver和SessionLocaleResolver。接下来我们简单介绍一下这四个实现类的源码。
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");
}
}
FixedLocaleResolver:设置固定的语言信息,这样整个系统的语言是一成不变的,用处不大。
public class FixedLocaleResolver extends AbstractLocaleContextResolver {
public FixedLocaleResolver() {
setDefaultLocale(Locale.getDefault());
}
public FixedLocaleResolver(Locale locale) {
setDefaultLocale(locale);
}
public FixedLocaleResolver(Locale locale, TimeZone timeZone) {
setDefaultLocale(locale);
setDefaultTimeZone(timeZone);
}
@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");
}
}
CookieLocaleResolver:将语言信息设置到Cookie中,这样整个系统就可以获得语言信息
public class CookieLocaleResolver extends CookieGenerator implements LocaleContextResolver {
//多语言cookie名称
public static final String LOCALE_REQUEST_ATTRIBUTE_NAME = CookieLocaleResolver.class.getName() + ".LOCALE";
//多语言时区cookie名称
public static final String TIME_ZONE_REQUEST_ATTRIBUTE_NAME = CookieLocaleResolver.class.getName() + ".TIME_ZONE";
//默认的多语言cookie名称
public static final String DEFAULT_COOKIE_NAME = CookieLocaleResolver.class.getName() + ".LOCALE";
private Locale defaultLocale;
private TimeZone defaultTimeZone;
public CookieLocaleResolver() {
setCookieName(DEFAULT_COOKIE_NAME);
}
public void setDefaultLocale(Locale defaultLocale) {
this.defaultLocale = defaultLocale;
}
protected Locale getDefaultLocale() {
return this.defaultLocale;
}
public void setDefaultTimeZone(TimeZone defaultTimeZone) {
this.defaultTimeZone = defaultTimeZone;
}
protected TimeZone getDefaultTimeZone() {
return this.defaultTimeZone;
}
@Override
public Locale resolveLocale(HttpServletRequest request) {
parseLocaleCookieIfNecessary(request);
return (Locale) request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
}
@Override
public LocaleContext resolveLocaleContext(final HttpServletRequest request) {
parseLocaleCookieIfNecessary(request);
return new TimeZoneAwareLocaleContext() {
@Override
public Locale getLocale() {
return (Locale) request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
}
@Override
public TimeZone getTimeZone() {
return (TimeZone) request.getAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME);
}
};
}
private void parseLocaleCookieIfNecessary(HttpServletRequest request) {
if (request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME) == null) {
// Retrieve and parse cookie value.
Cookie cookie = WebUtils.getCookie(request, getCookieName());
Locale locale = null;
TimeZone timeZone = null;
if (cookie != null) {
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);
}
locale = (!"-".equals(localePart) ? StringUtils.parseLocaleString(localePart) : null);
if (timeZonePart != null) {
timeZone = StringUtils.parseTimeZoneString(timeZonePart);
}
if (logger.isDebugEnabled()) {
logger.debug("Parsed cookie value [" + cookie.getValue() + "] into locale '" + locale +
"'" + (timeZone != null ? " and time zone '" + timeZone.getID() + "'" : ""));
}
}
request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME,
(locale != null ? locale: determineDefaultLocale(request)));
request.setAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME,
(timeZone != null ? timeZone : determineDefaultTimeZone(request)));
}
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
setLocaleContext(request, response, (locale != null ? new SimpleLocaleContext(locale) : null));
}
@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();
}
addCookie(response, (locale != null ? 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)));
}
protected Locale determineDefaultLocale(HttpServletRequest request) {
Locale defaultLocale = getDefaultLocale();
if (defaultLocale == null) {
defaultLocale = request.getLocale();
}
return defaultLocale;
}
protected TimeZone determineDefaultTimeZone(HttpServletRequest request) {
return getDefaultTimeZone();
}
}
SessionLocaleResolver:与CookieLocaleResolver类似将语言信息放到Session中,这样整个系统就可以从Session中获得语言信息。
public class SessionLocaleResolver extends AbstractLocaleContextResolver {
//语言信息放到session中的名称
public static final String LOCALE_SESSION_ATTRIBUTE_NAME = SessionLocaleResolver.class.getName() + ".LOCALE";
public static final String TIME_ZONE_SESSION_ATTRIBUTE_NAME = SessionLocaleResolver.class.getName() + ".TIME_ZONE";
@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 LocaleContext resolveLocaleContext(final HttpServletRequest request) {
return new TimeZoneAwareLocaleContext() {
@Override
public Locale getLocale() {
Locale locale = (Locale) WebUtils.getSessionAttribute(request, LOCALE_SESSION_ATTRIBUTE_NAME);
if (locale == null) {
locale = determineDefaultLocale(request);
}
return locale;
}
@Override
public TimeZone getTimeZone() {
TimeZone timeZone = (TimeZone) WebUtils.getSessionAttribute(request, TIME_ZONE_SESSION_ATTRIBUTE_NAME);
if (timeZone == null) {
timeZone = determineDefaultTimeZone(request);
}
return timeZone;
}
};
}
@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);
}
protected Locale determineDefaultLocale(HttpServletRequest request) {
Locale defaultLocale = getDefaultLocale();
if (defaultLocale == null) {
defaultLocale = request.getLocale();
}
return defaultLocale;
}
protected TimeZone determineDefaultTimeZone(HttpServletRequest request) {
return getDefaultTimeZone();
}
}
通过源码我们可以了解到springMVC对多语言的支持就是设置Locale的语言信息来实现的,只不过是设置了通过cookie、session等方式设置而已,接下来我们会通过demo来进一步介绍这几种实现方式。
springMVC源码分析--国际化LocaleResolver(一)的更多相关文章
- springMVC源码分析--国际化实现Session和Cookie(二)
上一篇博客springMVC源码分析--国际化LocaleResolver(一)中我们介绍了springMVC提供的国际化的解决方案,接下来我们根据springMVC提供的解决方案来简单的实现一个多语 ...
- springMVC源码分析--HandlerInterceptor拦截器(一)
对SpringMVC有所了解的人肯定接触过HandlerInterceptor拦截器,HandlerInterceptor接口给我们提供了3个方法: (1)preHandle: 在执行controll ...
- springMVC源码分析--DispatcherServlet请求获取及处理
在之前的博客springMVC源码分析--容器初始化(二)DispatcherServlet中我们介绍过DispatcherServlet,是在容器初始化过程中出现的,我们之前也说过Dispatche ...
- SpringMVC源码分析--容器初始化(五)DispatcherServlet
上一篇博客SpringMVC源码分析--容器初始化(四)FrameworkServlet我们已经了解到了SpringMVC容器的初始化,SpringMVC对容器初始化后会进行一系列的其他属性的初始化操 ...
- SpringMVC源码分析(3)DispatcherServlet的请求处理流程
<springmvc源码分析(2)dispatcherservlet的初始化>初始化DispatcherServlet的多个组件. 本文继续分析DispatcherServlet解析请求的 ...
- springMVC源码分析--视图View(一)
之前的博客springMVC源码分析--HttpMessageConverter数据转化(一)中我们已经介绍了数据返回值的处理,在博客springMVC源码分析--ViewResolver视图解析器( ...
- 8、SpringMVC源码分析(3):分析ModelAndView的形成过程
首先,我们还是从DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response) throw ...
- 7、SpringMVC源码分析(2):分析HandlerAdapter.handle方法,了解handler方法的调用细节以及@ModelAttribute注解
从上一篇 SpringMVC源码分析(1) 中我们了解到在DispatcherServlet.doDispatch方法中会通过 mv = ha.handle(processedRequest, res ...
- springMVC源码分析--ViewNameMethodReturnValueHandler返回值处理器(三)
之前两篇博客springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)和springMVC源码分析--HandlerMethodReturnValu ...
随机推荐
- What's New In MySQL 8.0
由于8.0内有很多C++11特性.需要gcc4.8版本以上.Rhel6系列默认gcc是4.7.在安装gcc6.1之后仍然检查不过. 原因可能是6.1版本不一定高于4.7,暂不讨论.鉴于升级gc ...
- 数据结构之B树、B+树(二)---代码实现
B-Tree | Set 1 (construct) Following is an example B-Tree of minimum degree 3. Note that in practica ...
- json字符串转json对象,json对象转换成java对象
@RequestMapping(value = "updateInvestorApplyAccountNo", method = RequestMethod.POST) @Resp ...
- Elasticsearch 学习(一):入门
一.概念 Elasticsearch 是一个实时分布式搜索和分析引擎.它用于全文搜索.结构化搜索.分析以及将这三者混合使用. 维基百科.英国卫报.StackOverflow.Github 等公司都在使 ...
- git修改远程仓库地址
方法有三种: 1.修改命令 git remote set-url origin [url] 例如: git remote set-url origin gitlab@gitlab.chumob.com ...
- idea-JSP out.println报错问题
<%! out.println("xxxx");%> 上面是错误的,<%!%>是声明变量是使用,而不是进行逻辑输出! <% out.println(x ...
- 消息中间件--ActiveMQ&JMS消息服务
### 消息中间件 ### ---------- **消息中间件** 1. 消息中间件的概述 2. 消息中间件的应用场景 * 异步处理 * 应用解耦 * 流量削峰 * 消息通信 --------- ...
- API说明书规范
目录 1 前言 1.1 编写目的 1.2 预期读者 1.3 关于API设计开发 2 API公共说明 3 文档API索引 ...
- String字符串的操作
字符串的常用操作 # Author:nadech name = "my name is nadech" print(name.count("a")) print ...
- MongoDB 原子操作
mongodb不支持事务,所以,在你的项目中应用时,要注意这点.无论什么设计,都不要要求mongodb保证数据的完整性. 但是mongodb提供了许多原子操作,比如文档的保存,修改,删除等,都是原子操 ...