【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>