1. 程式人生 > >【spring系列】- springmvc國際化的工作原理

【spring系列】- springmvc國際化的工作原理

國際化:頁面響應式佈局一個頁面針對不同的裝置進行相應的顯示,國際化則是也個頁面針對不同的地區/語言進行相應的自適應的顯示

SpringMVC支援的國際化的三個類:
ResourceBundleMessageSource:

國際化訊息資源的封裝類,主要配置不同地區和國家相應物件的表示內容,一般使用properties檔案進行封裝

SessionLocaleResolver:

Locale物件的解析器,主要用於解析Locale物件以及負責Locale物件在Session中的儲存

LocaleChangeInterceptor:

Locale物件改變攔截器(可以理解成Tomcat的監聽器:區別在於前者Servlet採用Servlet容器實現,Spring採用IOC容器實現),當頁面的locale物件發生改變時,該攔截器會進行相應的處理,否則不處理

SpringMVC國際化的工作原理圖:
這裡寫圖片描述

工作流程:核心類:LocaleChangeInterceptor
核心原始碼:

@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) {
					throw new IllegalStateException(
							"No LocaleResolver found: not in a DispatcherServlet request?");
				}
				try {
					localeResolver.setLocale(request, response, parseLocaleValue(newLocale));
				}
				catch (IllegalArgumentException ex) {
					if (isIgnoreInvalidLocale()) {
						logger.debug("Ignoring invalid locale value [" + newLocale + "]: " + ex.getMessage());
					}
					else {
						throw ex;
					}
				}
			}
		}
		return true;
	}

public String getParamName() {
		return this.paramName;
	}

public static final String DEFAULT_PARAM_NAME = "locale";

private String paramName = DEFAULT_PARAM_NAME;

preHandle:HandlerInterceptor介面的標準方法,主要用於Handler處理前的攔截處理,從LocaleChangeInterceptor的原始碼可以看出,當頁面請求引數包含locale的引數時,內部會自動建立和DispatherServlet繫結的localeResolver物件(例如SessionLocaleResolver),然後呼叫

localeResolver.setLocale(request, response, parseLocaleValue(newLocale))

進行Locale物件的設定,這裡我們檢視setLocale方法在SessionLocaleResolver中的實現:

@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);
	}

從原始碼中可以看出,SessionLocaleResolver主要完成Locale和TimeZone物件在Session中的儲存,這樣通過SpringMVC國際化整個流程的Locale和TimeZone的設定就全部完成了,當客戶端訪問對應的資源時IOC容器內部的ResourceBundleMessageSource會自動根據Locale物件去獲取不同的頁面顯示的資原始檔,達到不同的語言/地區頁面不同的顯示的效果

注意:

①:一個DispatcherServlet只會與LocaleResolver繫結
②:客戶端訪問SpringMVC時,首先LocaleResolver判斷是否在Session中設定Locale/TimeZone物件,如果未設定則採取預設的Locale和TimeZone的獲取流程獲取
③:Locale預設物件獲取流程:首先從LocaleResolver註冊到IOC容器的初始化引數獲取(可選:設定defaultLocale屬性),如果未配置則從客戶端的request中讀取Locale(請求頭)

SpringMVC國際化的配置:
①:配置ResourceBundleMessageSource:國際化資源:

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
	    <property name="defaultEncoding" value="UTF-8" />
        <property name="useCodeAsDefaultMessage" value="true" />
	    <property name="basenames">    
	       <list>  
	          <value>config/i18n</value>  
	       </list>  
	    </property>  
	</bean>

目錄結構:
這裡寫圖片描述

i18n_en_US.properties:

user.name=name
user.passwd=passwd
page.language:English
page.description:Page Language
i18n.tile:Internationization

i18n_zh_CN.properties:

user.name:\u7528\u6237\u540D
user.passwd:\u5BC6\u7801
page.language:Simple Chinese
page.description:\u9875\u9762\u8BED\u8A00
i18n.tile:\u56FD\u9645\u5316

②:配置LocaleResolver

<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/>

③:配置LocaleChangeInterceptor:

<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
</mvc:interceptors>