溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java Spring項(xiàng)目國(guó)際化的示例分析

發(fā)布時(shí)間:2021-06-16 15:07:04 來(lái)源:億速云 閱讀:179 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要介紹了Java Spring項(xiàng)目國(guó)際化的示例分析,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

Spring國(guó)際化概述

國(guó)際化基本規(guī)則

國(guó)際化信息”也稱為“本地化信息”,一般需要兩個(gè)條件才可以確定一個(gè)特定類型的本地化信息,它們分別是“語(yǔ)言類型”和“國(guó)家/地區(qū)的類型”。如中文本地化信息既有中國(guó)大陸地區(qū)的中文,又有中國(guó)臺(tái)灣、中國(guó)香港地區(qū)的中文,還有新加坡地區(qū)的中文。Java通過(guò)java.util.Locale類表示一個(gè)本地化對(duì)象,它允許通過(guò)語(yǔ)言參數(shù)和國(guó)家/地區(qū)參數(shù)創(chuàng)建一個(gè)確定的本地化對(duì)象。

語(yǔ)言參數(shù)使用ISO標(biāo)準(zhǔn)語(yǔ)言代碼表示,這些代碼是由ISO-639標(biāo)準(zhǔn)定義的,每一種語(yǔ)言由兩個(gè)小寫字母表示。在許多網(wǎng)站上都可以找到這些代碼的完整列表,下面的網(wǎng)址是提供了標(biāo)準(zhǔn)語(yǔ)言代碼的信息:http://www.loc.gov/standards/iso639-2/php/English_list.php。

國(guó)家/地區(qū)參數(shù)也由標(biāo)準(zhǔn)的ISO國(guó)家/地區(qū)代碼表示,這些代碼是由ISO-3166標(biāo)準(zhǔn)定義的,每個(gè)國(guó)家/地區(qū)由兩個(gè)大寫字母表示。用戶可以從以下網(wǎng)址查看ISO-3166的標(biāo)準(zhǔn)代碼:http://www.iso.ch/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html,部分語(yǔ)言和國(guó)家/地區(qū)的標(biāo)準(zhǔn)代碼如下所示:

語(yǔ)言簡(jiǎn)稱
簡(jiǎn)體中文(中國(guó))zh_CN
繁體中文(中國(guó)臺(tái)灣)zh_TW
繁體中文(中國(guó)香港)zh_HK
英語(yǔ)(中國(guó)香港)en_HK
英語(yǔ)(美國(guó))en_US
英語(yǔ)(英國(guó))en_GB
英語(yǔ)(全球)en_WW
英語(yǔ)(加拿大)en_CA
英語(yǔ)(澳大利亞)en_AU
英語(yǔ)(愛爾蘭)en_IE
英語(yǔ)(芬蘭)en_FI
芬蘭語(yǔ)(芬蘭)fi_FI
英語(yǔ)(丹麥)en_DK
丹麥語(yǔ)(丹麥)da_DK
英語(yǔ)(以色列)en_IL
希伯來(lái)語(yǔ)(以色列)he_IL
英語(yǔ)(南非)en_ZA
英語(yǔ)(印度)en_IN
英語(yǔ)(挪威)en_NO
英語(yǔ)(新加坡)en_SG
英語(yǔ)(新西蘭)en_NZ
英語(yǔ)(印度尼西亞)en_ID
英語(yǔ)(菲律賓)en_PH
英語(yǔ)(泰國(guó))en_TH
英語(yǔ)(馬來(lái)西亞)en_MY
英語(yǔ)(阿拉伯)en_XA
韓文(韓國(guó))ko_KR
日語(yǔ)(日本)ja_JP
荷蘭語(yǔ)(荷蘭)nl_NL
荷蘭語(yǔ)(比利時(shí))nl_BE
葡萄牙語(yǔ)(葡萄牙)pt_PT
葡萄牙語(yǔ)(巴西)pt_BR
法語(yǔ)(法國(guó))fr_FR
法語(yǔ)(盧森堡)fr_LU
法語(yǔ)(瑞士)fr_CH
法語(yǔ)(比利時(shí))fr_BE
法語(yǔ)(加拿大)fr_CA
西班牙語(yǔ)(拉丁美洲)es_LA
西班牙語(yǔ)(西班牙)es_ES
西班牙語(yǔ)(阿根廷)es_AR
西班牙語(yǔ)(美國(guó))es_US
西班牙語(yǔ)(墨西哥)es_MX
西班牙語(yǔ)(哥倫比亞)es_CO
西班牙語(yǔ)(波多黎各)es_PR
德語(yǔ)(德國(guó))de_DE
德語(yǔ)(奧地利)de_AT
德語(yǔ)(瑞士)de_CH
俄語(yǔ)(俄羅斯)ru_RU
意大利語(yǔ)(意大利)it_IT
希臘語(yǔ)(希臘)el_GR
挪威語(yǔ)(挪威)no_NO
匈牙利語(yǔ)(匈牙利)hu_HU
土耳其語(yǔ)(土耳其)tr_TR
捷克語(yǔ)(捷克共和國(guó))cs_CZ
斯洛文尼亞語(yǔ)sl_SL
波蘭語(yǔ)(波蘭)pl_PL
瑞典語(yǔ)(瑞典)sv_SE
西班牙語(yǔ)(智利)es_CL

語(yǔ)言類型判斷

1)基于瀏覽器語(yǔ)言

根據(jù)Request Headers中的Accept-language來(lái)判斷。

2)基于客戶端傳參

要求客戶端第一次(或者每次)傳遞的自定義參數(shù)值來(lái)判斷,如規(guī)定傳locale,值為zh-cn、en-us等內(nèi)容,如果只在第一次傳入則local以及timeZone先關(guān)信息要存入session或者cookie中,后面的請(qǐng)求語(yǔ)言方式則直接從兩者中取,其有效時(shí)間與session和cookie設(shè)置的生命周期關(guān)聯(lián)。

3)基于默認(rèn)配置

當(dāng)獲取語(yǔ)言類型時(shí)沒(méi)有找到對(duì)應(yīng)類型時(shí),會(huì)使用默認(rèn)的語(yǔ)言類型。

語(yǔ)言類型保存

<!-- 定義本地化變更攔截器 -->
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
<!-- 定義注解URL映射處理器,所有的請(qǐng)求映射關(guān)聯(lián)本地化攔截器,或者也可自定義該攔截器路徑映射-->
<bean id="urlMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
 <property name="interceptors" ref=" localeChangeInterceptor " />
 <property name="order" value="1"></property>
</bean>

基于url

該種方式需要每次都在請(qǐng)求的url上帶上local參數(shù),指定該次需要的語(yǔ)言類型,并且該方式的local解析器需要配置,如下:

<a href="xxx.do?locale=zh_CN" rel="external nofollow" >中文</a>或<a href="xxx.do?locale=en" rel="external nofollow" >英文</a>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"/>

但在該配置下使用會(huì)拋Cannot change HTTP accept header - use a different locale resolution strategy異常,這是因?yàn)閟pring source做了限制,無(wú)法對(duì)本地的local賦值修改,解決辦法如下,新建一個(gè)類MyLocaleResolver繼承AcceptHeaderLocaleResolver,重寫resolveLocale和setLocale方法,并將上面的localeResolver的class指向如下MyLocaleResolver類:

public class MyLocaleResolver extends AcceptHeaderLocaleResolver {
 private Locale myLocal;
 
public Locale resolveLocale(HttpServletRequest request) {
 return myLocal == null ? request.getLocale() : myLocal;
}
 
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
 myLocal = locale;
 }
}

基于session

基于session的狀態(tài)保存方式只需要在第一次請(qǐng)求的時(shí)候指定語(yǔ)言類型,localResolver會(huì)將該屬性保存到session中,后面的請(qǐng)求直接從session中獲取該語(yǔ)言類型,該種方式的localResolver對(duì)應(yīng)的類為SessionLocaleResolver,如下配置:

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

基于cookie

與session的機(jī)制類似,差異在于兩者的存儲(chǔ)和周期,鑒于安全、大小以及體驗(yàn)等因素的影響,實(shí)際使用中使用者更傾向于前者,該種cookie保存方式的localResolver為

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

文案數(shù)據(jù)來(lái)源

對(duì)于語(yǔ)言類型的資源文件,需要開發(fā)者對(duì)文案進(jìn)行搜集整理,并翻譯成相應(yīng)的語(yǔ)言確定關(guān)鍵字key,目前大多數(shù)情況是將這些信息置于.properties文件中,在使用的時(shí)候直接訪問(wèn)獲取,當(dāng)然也可置于數(shù)據(jù)庫(kù)中,但頻繁的文案獲取會(huì)影響服務(wù)器性能及產(chǎn)品體驗(yàn),可結(jié)合數(shù)據(jù)字典以及緩存工具使用。

數(shù)據(jù)庫(kù)

1)spring 配置方式

<!-- 默認(rèn)的注解映射的支持 -->
<mvc:annotation-driven validator="validator" conversion-service="conversionService" />
<!-- 資源文件 -->
<bean id="propertiesMessageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
 <property name="basenames">
 <list>
 <value>resource</value>
 <value>validation</value>
 </list>
 </property>
</bean>
 
<bean id="databaseMessageSource" class="com.obs2.util.MessageResource">
 <property name="parentMessageSource" ref="propertiesMessageSource"/>
</bean>
 
<bean id="messageInterpolator" class="com.obs2.util.MessageResourceInterpolator">
 <property name="messageResource" ref="databaseMessageSource"/>
</bean>
 
<!-- 驗(yàn)證器 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
 <property name="messageInterpolator" ref="messageInterpolator"/>
</bean>

這里定義了一個(gè)propertiesMessageSource,一個(gè)databaseMessageSourcer,和一個(gè)messageInterpolator。propertiesMessageSource用于讀取properties文件databaseMessageSourcer用于讀取數(shù)據(jù)庫(kù)的數(shù)據(jù)配置,其中,有一個(gè)屬性設(shè)置它的父MessageSource為propertiesMessageSource。意思是如果數(shù)據(jù)庫(kù)找不到對(duì)應(yīng)的數(shù)據(jù),到properties文件當(dāng)中查找。messageInterpolator是個(gè)攔截器。

2)數(shù)據(jù)庫(kù)的POJO定義

@Entity
@SuppressWarnings("serial")
@Table(name="resource")
 
public class Resource implements Serializable {
 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 @Column(name="resource_id")
 private long resourceId;
 
 @Column(name="name", length=50, nullable=false)
 private String name;
 
 @Column(name="text", length=1000, nullable=false)
 private String text;
 
 @Column(name="language", length=5, nullable=false)
 private String language;
 
 public long getResourceId() {
 return resourceId;
 }
 
 public void setResourceId(long resourceId) {
 this.resourceId = resourceId;
 }
 
 public String getName() {
 return name;
 }
 
 public void setName(String name) {
 this.name = name;
 }
 
 public String getText() {
 return text;
 }
 
 public void setText(String text) {
 this.text = text;
}
 
 public String getLanguage() {
 return language;
 }
 
 public void setLanguage(String language) {
 this.language = language;
 }
}

定義了一張表[resource],字段有:[resource_id]、[name]、[text]、[language]。

3)讀取數(shù)據(jù)庫(kù)的MessageResource類

/**
* 取得資源數(shù)據(jù)
* @author Robin
*/
public class MessageResource extends AbstractMessageSource implements ResourceLoaderAware {
 
 @SuppressWarnings("unused")
 private ResourceLoader resourceLoader;
 
 @Resource
 private ResourceService resourceService;
 /**
 * Map切分字符
 */
 protected final String MAP_SPLIT_CODE = "|";
 protected final String DB_SPLIT_CODE = "_";
 
 private final Map<String, String> properties = new HashMap<String, String>();
 
 public MessageResource() {
 reload();
 }
 
 public void reload() {
 properties.clear();
 properties.putAll(loadTexts());
 }
 
 protected Map<String, String> loadTexts() {
 Map<String, String> mapResource = new HashMap<String, String>();
 List<com.obs2.service.bean.Resource> resources = resourceService.findAll();
 for (com.obs2.service.bean.Resource item : resources) {
 String code = item.getName() + MAP_SPLIT_CODE + item.getLanguage();
 mapResource.put(code, item.getText());
 }
 
 return mapResource;
 }
 
 private String getText(String code, Locale locale) {
 String localeCode = locale.getLanguage() + DB_SPLIT_CODE + locale.getCountry();
 String key = code + MAP_SPLIT_CODE + localeCode;
 String localeText = properties.get(key);
 String resourceText = code;
 if(localeText != null) {
  resourceText = localeText;
 }else {
  localeCode = Locale.ENGLISH.getLanguage();
  key = code + MAP_SPLIT_CODE + localeCode;
  localeText = properties.get(key);
  if(localeText != null) {
  resourceText = localeText;
  }else {
  try {
   if(getParentMessageSource() != null) {
   resourceText = getParentMessageSource().getMessage(code, null, locale);
   }
  } catch (Exception e) {
   logger.error("Cannot find message with code: " + code);
  }
  }
 }
 return resourceText;
 }
 
 @Override
 public void setResourceLoader(ResourceLoader resourceLoader) {
 this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader());
 }
 
 @Override
 protected MessageFormat resolveCode(String code, Locale locale) {
 String msg = getText(code, locale);
 MessageFormat result = createMessageFormat(msg, locale);
 return result;
 }
 
 @Override
 protected String resolveCodeWithoutArguments(String code, Locale locale) {
 String result = getText(code, locale);
 return result;
 }
}

主要是重載AbstractMessageSource和ResourceLoaderAware,以實(shí)現(xiàn)Spring MVC的MessageSource國(guó)際化調(diào)用。類中的reload()方法,我把它寫到了一個(gè)ServletListener當(dāng)中,讓項(xiàng)目啟動(dòng)時(shí),自動(dòng)加載數(shù)據(jù)到static的map中。

4)Listener

/**
* 系統(tǒng)啟動(dòng)監(jiān)聽
* @author Robin
*/
public class SystemListener implements ServletContextListener {
/**
* context初始化時(shí)激發(fā)
*/
@Override
public void contextInitialized(ServletContextEvent e) {
// 取得ServletContext
ServletContext context = e.getServletContext();
WebApplicationContext applicationContext = WebApplicationContextUtils .getWebApplicationContext(context);
// 設(shè)置國(guó)際化多語(yǔ)言
MessageResource messageSource = applicationContext.getBean(MessageResource.class);
 messageSource.reload();
}
 
/**
* context刪除時(shí)激發(fā)
*/
@Override
public void contextDestroyed(ServletContextEvent e) {
}
 
/**
* 創(chuàng)建一個(gè) session時(shí)激發(fā)
* @param e
*/
 
public void sessionCreated(HttpSessionEvent e) {
}
 
/**
* 當(dāng)一個(gè) session失效時(shí)激發(fā)
* @param e
*
public void sessionDestroyed(HttpSessionEvent e) {
}
/**
* 設(shè)置 context的屬性,它將激發(fā)attributeReplaced或attributeAdded方法
* @param e
*/
public void setContext(HttpSessionEvent e) {
}
 
/**
* 增加一個(gè)新的屬性時(shí)激發(fā)
* @param e
*/
public void attributeAdded(ServletContextAttributeEvent e) {
}
 
/**
*刪除一個(gè)新的屬性時(shí)激發(fā)
* @param e
*/
 
public void attributeRemoved(ServletContextAttributeEvent e) {
 
}
 
/*
* 屬性被替代時(shí)激發(fā)
* @param e
*/
public void attributeReplaced(ServletContextAttributeEvent e) {
}
}

該Listener需要加入到web.xml當(dāng)中:

<!-- 系統(tǒng)啟動(dòng)監(jiān)聽 -->
<listener>
 <listener-class>com.obs2.util.SystemListener</listener-class>
</listener>

5)Interceptor攔截器

/**
* 攔截Annotation驗(yàn)證信息
* @author Robin
*
*/
 
public class MessageResourceInterpolator implements MessageInterpolator {
@Resource
private MessageResource messageResource;
 
public void setMessageResource(MessageResource messageResource) {
 this.messageResource = messageResource;
}
 
@Override
public String interpolate(String messageTemplate, Context context) {
 
String messageTemp = null;
 if(messageTemplate.startsWith("{") && messageTemplate.endsWith("}")) {
 messageTemp = messageTemplate.substring(1, messageTemplate.length() - 1);
 }else {
 return messageTemplate;
 }
 
 String[] params = (String[]) context.getConstraintDescriptor().getAttributes().get("params");
 MessageBuilder builder = new MessageBuilder().code(messageTemp);
 
 if (params != null) {
 for (String param : params) {
 builder = builder.arg(param);
 }
 
 }
 
 String result = builder.build().resolveMessage(messageResource, Locale.ENGLISH).getText();
 return result;
 
 }
 
@Override
public String interpolate(String messageTemplate, Context context, Locale locale) {
 
 String messageTemp = null;
 if(messageTemplate.startsWith("{") && messageTemplate.endsWith("}")) {
 messageTemp = messageTemplate.substring(1, messageTemplate.length() - 1);
 }else {
 return messageTemplate;
 }
 
 String[] params = (String[]) context.getConstraintDescriptor().getAttributes().get("params");
 
 MessageBuilder builder = new MessageBuilder().code(messageTemp);
 if (params != null) {
 builder = builder.args(params);
 }
 
 String result = builder.build().resolveMessage(messageResource, locale).getText();
 
 return result
 }
 
}

靜態(tài)資源

<!-- 資源文件綁定器,文件名稱:messages.properties(沒(méi)有找到時(shí)的默認(rèn)文件), messages_en.properties(英文),messages_zh_CN.properties(中文),等等-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
 <property name="basename" value="config.messages.messages" />
 <property name="defaultEncoding" value="UTF-8"/>
 <property name="basename" value="i18n.messages"/>
 <property name="useCodeAsDefaultMessage" value="true" />
</bean>

文案獲取

資源獲取接口

MessageSource詳解

Spring定義了訪問(wèn)國(guó)際化信息的MessageSource接口,并提供了幾個(gè)易用的實(shí)現(xiàn)類。首先來(lái)了解一下該接口的幾個(gè)重要方法:

1)String getMessage(String code, Object[] args, String defaultMessage, Locale locale) code

表示國(guó)際化資源中的屬性名;args用于傳遞格式化串占位符所用的運(yùn)行期參數(shù);當(dāng)在資源找不到對(duì)應(yīng)屬性名時(shí),返回defaultMessage參數(shù)所指定的默認(rèn)信息;locale表示本地化對(duì)象;

2)String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException

與上面的方法類似,只不過(guò)在找不到資源中對(duì)應(yīng)的屬性名時(shí),直接拋出NoSuchMessageException異常;

3)String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException

MessageSourceResolvable 將屬性名、參數(shù)數(shù)組以及默認(rèn)信息封裝起來(lái),它的功能和第一個(gè)接口方法相同。

MessageSource類結(jié)構(gòu)

MessageSource分別被HierarchicalMessageSource和ApplicationContext接口擴(kuò)展,這里我們主要看一下HierarchicalMessageSource接口的幾個(gè)實(shí)現(xiàn)類

Java Spring項(xiàng)目國(guó)際化的示例分析

HierarchicalMessageSource接口添加了兩個(gè)方法,建立父子層級(jí)的MessageSource結(jié)構(gòu),類似于前面我們所介紹的HierarchicalBeanFactory。該接口的setParentMessageSource (MessageSource parent)方法用于設(shè)置父MessageSource,而getParentMessageSource()方法用于返回父MessageSource。

HierarchicalMessageSource接口最重要的兩個(gè)實(shí)現(xiàn)類是ResourceBundleMessageSource和ReloadableResourceBundleMessageSource。它們基于Java的ResourceBundle基礎(chǔ)類實(shí)現(xiàn),允許僅通過(guò)資源名加載國(guó)際化資源。ReloadableResourceBundleMessageSource提供了定時(shí)刷新功能,允許在不重啟系統(tǒng)的情況下,更新資源的信息。StaticMessageSource主要用于程序測(cè)試,它允許通過(guò)編程的方式提供國(guó)際化信息。而DelegatingMessageSource是為方便操作父MessageSource而提供的代理類。

ResourceBundleMessageSource與ReloadableResourceBundleMessageSource對(duì)比

1)通過(guò)ResourceBundleMessageSource配置資源

<bean id=" messageSource "
class="org.springframework.context.support.ResourceBundleMessageSource">
 <!--①通過(guò)基名指定資源,相對(duì)于類根路徑-->
 <property name="basenames">
 <list>
 <value>com/baobaotao/i18n/fmt_resource</value>
 </list>
 </property>
 </bean>

2)通過(guò)ReloadableResourceBundleMessageSource配置資源

<bean id="messageSource "
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
 <property name="basenames">
 <list>
 <value>com/baobaotao/i18n/fmt_resource</value>
 </list>
 </property>
 <!--①刷新資源文件的周期,以秒為單位-->
 <property name="cacheSeconds" value="5"/>
</bean>

3)對(duì)比

兩者都是利用資源名通過(guò)getMessage()接口就可以加載整套的國(guó)際化資源文件,唯一區(qū)別在于ReloadableResourceBundleMessageSource可以定時(shí)刷新資源文件,以便在應(yīng)用程序不重啟的情況下感知資源文件的變化。很多生產(chǎn)系統(tǒng)都需要長(zhǎng)時(shí)間持續(xù)運(yùn)行,系統(tǒng)重啟會(huì)給運(yùn)行帶來(lái)很大的負(fù)面影響,這時(shí)通過(guò)該實(shí)現(xiàn)類就可以解決國(guó)際化信息更新的問(wèn)題。上面的配置中cacheSeconds屬性讓ReloadableResourceBundleMessageSource每5秒鐘刷新一次資源文件(在真實(shí)的應(yīng)用中,刷新周期不能太短,否則頻繁的刷新將帶來(lái)性能上的負(fù)面影響,一般不建議小于30分鐘)。cacheSeconds默認(rèn)值為-1表示永不刷新,此時(shí),該實(shí)現(xiàn)類的功能就蛻化為ResourceBundleMessageSource的功能。

頁(yè)面獲取文案

利用Spring標(biāo)簽獲取

引入標(biāo)簽庫(kù):

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>

獲取文案:

<s:message code="test.app"/>
<spring:message code="main.title" />

利用JSTL標(biāo)簽獲取

引入標(biāo)簽庫(kù):

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt"%>

獲取文案:

<fmt:message key="test.app"/>

Java代碼中獲取文案

利用MessageSource接口獲取

1)自動(dòng)注入

@Autowired
private MessageSource messageSource;
String s = messageSource.getMessage("SystemError", new Object[]{}, Locale.US);

2)手動(dòng)bean獲取

a. 獲取容器

容器已經(jīng)初始化:

WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();

容器沒(méi)有初始化:

String[] configs = {"com/baobaotao/i18n/beans.xml"};
ApplicationContext ctx = new ClassPathXmlApplicationContext(configs);

b. 獲取bean跟文案

MessageSource ms = (MessageSource) wac.getBean("myResource");
Object[] params = {"John", new GregorianCalendar().getTime()};
String str1 = ms.getMessage("greeting.common",params,Locale.US);

利用Spring容器獲取

在前面的MessageSource類圖結(jié)構(gòu)中我們發(fā)現(xiàn)ApplicationContext實(shí)現(xiàn)了MessageSource的接口,也就是說(shuō)ApplicationContext的實(shí)現(xiàn)類本身也是一個(gè)MessageSource對(duì)象。

將ApplicationContext和MessageSource整合起來(lái), Spring此處的設(shè)計(jì)人為:在一般情況下,國(guó)際化信息資源應(yīng)該是容器級(jí)。我們一般不會(huì)將MessageSource作為一個(gè)Bean注入到其他的Bean中,相反MessageSource作為容器的基礎(chǔ)設(shè)施向容器中所有的Bean開放。只要我們考察一下國(guó)際化信息的實(shí)際消費(fèi)場(chǎng)所就更能理解Spring這一設(shè)計(jì)的用意了。國(guó)際化信息一般在系統(tǒng)輸出信息時(shí)使用,如Spring MVC的頁(yè)面標(biāo)簽,控制器Controller等,不同的模塊都可能通過(guò)這些組件訪問(wèn)國(guó)際化信息,因此Spring就將國(guó)際化消息作為容器的公共基礎(chǔ)設(shè)施對(duì)所有組件開放。

既然一般情況下我們不會(huì)直接通過(guò)引用MessageSource Bean使用國(guó)際信息,那如何聲明容器級(jí)的國(guó)際化信息呢? Spring容器啟動(dòng)過(guò)程時(shí),在初始化容器的時(shí)候通過(guò)initMessageSource()方法所執(zhí)行的工作就是初始化容器中的國(guó)際化信息資源,它根據(jù)反射機(jī)制從BeanDefinitionRegistry中找出名稱為“messageSource”且類型為org.springframework.context.MessageSource的Bean,將這個(gè)Bean定義的信息資源加載為容器級(jí)的國(guó)際化信息資源。請(qǐng)看下面的配置:

<!--注冊(cè)資源Bean,其Bean名稱只能為messageSource -->
<bean id="messageSource"
 class="org.springframework.context.support.ResourceBundleMessageSource">
 <property name="basenames">
 <list>
 <value>com/baobaotao/i18n/fmt_resource</value>
 </list>
 </property>
</bean>

然后通過(guò)ApplicationContext直接訪問(wèn)國(guó)際化信息:

a. 獲取容器

容器已經(jīng)初始化:

WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();

容器沒(méi)有初始化:

String[] configs = {"com/baobaotao/i18n/beans.xml"};
ApplicationContext ctx = new ClassPathXmlApplicationContext(configs);

b. 獲取bean跟文案

Object[] params = {"John", new GregorianCalendar().getTime()};
String str1 = ctx.getMessage("greeting.common",params,Locale.US);

注意事項(xiàng)

1)編碼問(wèn)題

a. 改變properties文件編碼為UTF-8/GBK,然而ResourceBundleMessageSource的默認(rèn)編碼defaultEncoding是ISO-8859-1,需要在xml中增加一個(gè)相應(yīng)屬性將其改變?yōu)槟阈枰腢TF-8/GBK之類。

b. 如果資源文件想統(tǒng)一使用ISO-8859-1格式,可以將原本用UTF-8寫好的中文資源文件使用jdk自帶的工具native2ascii將UTF-8文件和內(nèi)容轉(zhuǎn)為ISO-8859-1文件,其中的中文內(nèi)容會(huì)使用16進(jìn)制unicode編碼為\u****格式:

cmd命令:

JAVA_HOME\bin\native2ascii -encoding UTF-8 messages_zh_CN.properties messages_zh_C1N.properties

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“Java Spring項(xiàng)目國(guó)際化的示例分析”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI