spring的国际化

本文深入分析了Spring框架中如何通过Cookie、请求参数和session来传递和存储客户端的locale信息,详细解释了CookieLocaleResolver、SessionLocaleResolver等类的作用,并探讨了如何在请求拦截器中获取并应用locale,以及如何通过ThreadLocale来保持locale值的一致性。

一般客户端的语言特性,是通过cookie来传递的,也可以通过request的请求中获得locale的值。

先看CookieGenerator.java

public void addCookie(HttpServletResponse response, String cookieValue) {
		Assert.notNull(response, "HttpServletResponse must not be null");
		Cookie cookie = createCookie(cookieValue);
		Integer maxAge = getCookieMaxAge();
		if (maxAge != null) {
			cookie.setMaxAge(maxAge);
		}
		if (isCookieSecure()) {
			cookie.setSecure(true);
		}
		if (isCookieHttpOnly()) {
			cookie.setHttpOnly(true);
		}
		response.addCookie(cookie);
		if (logger.isDebugEnabled()) {
			logger.debug("Added cookie with name [" + getCookieName() + "] and value [" + cookieValue + "]");
		}
	}

这个地方就是response中回写cookie来存储locale的值。cookieName代表的是cookie的key值。如果我们采用的CookieLocaleResolver.java是本地的locale解析器。默认设置的cookieName是

public static final String DEFAULT_COOKIE_NAME = CookieLocaleResolver.class.getName() + ".LOCALE";

继承自LocaleResolver的两个方法实现如下:

public Locale resolveLocale(HttpServletRequest request) {
		// Check request for pre-parsed or preset locale.
		Locale locale = (Locale) request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
		if (locale != null) {
			return locale;
		}

		// Retrieve and parse cookie value.
		Cookie cookie = WebUtils.getCookie(request, getCookieName()); --批量在cookie中匹配对应key值的cookie
		if (cookie != null) {
			locale = StringUtils.parseLocaleString(cookie.getValue());
			if (logger.isDebugEnabled()) {
				logger.debug("Parsed cookie value [" + cookie.getValue() + "] into locale '" + locale + "'");
			}
			if (locale != null) {
				request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME, locale);--设置到request请求中,在spring的拦截器会使用时,拦截request时使用。
				return locale;
			}
		}

		return determineDefaultLocale(request); --如果前面的cookie没有读取出来的话,读取的是request中包含的locale信息。
	}

	public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
		if (locale != null) {
			// Set request attribute and add cookie.
			request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME, locale); --设置请求中的locale信息
			addCookie(response, locale.toString()); --添加cookie到response中,设置到客户端中。
		}
		else {
			// Set request attribute to fallback locale and remove cookie.
			request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME, determineDefaultLocale(request));
			removeCookie(response);
		}
	}
看一下拦截器对request的操作,是在类LocaleChangeInterceptor中引用:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws ServletException {

		String newLocale = request.getParameter(this.paramName); --查看请求参数中是否有locale的参数名,感觉spring这个地方的处理略显粗糙了点
		if (newLocale != null) {
			LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request); --从spring的容器中获取localeResolver的实现
			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;
	}
接下来查看的是:
public static LocaleResolver getLocaleResolver(HttpServletRequest request) {
		return (LocaleResolver) request.getAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE); --在请求的属性中是否有localeResolver的实现
	}

调用方法是DispatcherServlet.java中:

public static final String LOCALE_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".LOCALE_RESOLVER";
这里指定的是locale的解析类的key值。 DispatcherServlet也包含其他的如上下文和主题等的生成。

初始化的时候指定对应的key值,对应到调用的地方是:

protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context); --初始化localeResolver
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context); }

初始化本地化解析的方法调用如下:

private void initLocaleResolver(ApplicationContext context) {
		try {
			this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);//bean的值是localeResolver,定义bean值的时候需要bean的id为localeResolver.
			if (logger.isDebugEnabled()) {
				logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
			}
		}
		catch (NoSuchBeanDefinitionException ex) {
			// We need to use the default.
			this.localeResolver = getDefaultStrategy(context, LocaleResolver.class); //没找到时候采取的默认策略的localeResolver为org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
			if (logger.isDebugEnabled()) {
				logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
						"': using default [" + this.localeResolver + "]");
			}
		}
	}

spring的mvc拦截器会拦截客户端的请求来抓取到合适的locale解析器来获得locale的属性,从而通过resourceBundle来获得对应的属性文件里面的值。需要注意的点是bean的id需要设置成localeResolver

分析一下i18n包下的几个类:

AcceptHeaderLocaleResolver --是获取请求头中的locale对象

CookieLocaleResolver --获取的是cookie中传递的locale对象,如果cookie 不存在,获取的也是请求头中的locale对象。其中默认的cookieName是:


public static final String DEFAULT_COOKIE_NAME = CookieLocaleResolver.class.getName() + ".LOCALE";
SessionLocaleResolver --是从session中来获取的locale值,用会话来保持。默认的key值是:



public static final String LOCALE_SESSION_ATTRIBUTE_NAME = SessionLocaleResolver.class.getName() + ".LOCALE";
FixedLocaleResolver -- 是获取请求头中的locale对象,不同点是可以通过java代码来写入想要的locale对象。


上面只是spring的保持和传递locale对象的方式,也可以通过线程的方式来将locale绑定到ThreadLocale上面。来保持在一次请求过程中locale的值。取值的方式也可以参照前面的几种。

后续会加上ResourceBundle中调用的逻辑处理。







转载于:https://my.oschina.net/zooy/blog/552907

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值