總覽
許多剛剛學(xué)習(xí)Struts的程序員在使用Struts的MessageResources特性的時候會遭遇很多困難。本文將試圖闡述MessageResources特性的優(yōu)點并給出了具體的例子說明它的用法。
作者: Nick Heudecker, System Mobile Inc.
概述
類MessageResources可以使開發(fā)者方便地支持多語言,包括支持多時間格式和數(shù)字格式。使用資源包的另一個好處是允許開發(fā)者將標簽字符串集中存儲在一個位置,而不是分散在不同的JSP頁面里。例如,對于每個用戶的名字的標簽"First Name" ,我們可以將它寫在資源包中,在適當?shù)牡胤酵ㄟ^Struts標簽簡單的進行引用:
<bean:write key="label.first.name"/>
這樣做將會讓你對程序的更改變的簡單容易,你不必在每一個JSP頁面里更改標簽的內(nèi)容了。
用法
使用消息資源包需要你做下面的事情:
1. 為你想要支持的地方創(chuàng)建一個消息資源包。
2. 配置WEB應(yīng)用,加載消息資源包。
3. 使用相應(yīng)的JSP標簽加載資源或者...
4. ...在一個Action類中加載資源。
創(chuàng)建資源包
MessageResources 類的默認的實現(xiàn)是一個包含"key=value" 對的文件,下面的一個消息資源包文件的例子。
label.username=Username
label.password=Password
label.first.name=First Name
label.last.name=Last Name
label.email=Email Address
label.phone.number=Phone Number
label.welcome=Welcome back {0} {1}!
error.min.length=The input must be at least {0} characters in length.
error.max.length=The input cannot be longer than {0} characters in length.
大括號包圍的整數(shù)是對java.text.MessageFormat 類的支持,程序員可以向value字符串中傳遞參數(shù),對每個value字符串你最多可以傳遞4個參數(shù)。
配置
有兩種途徑通知Struts你的資源包的位置:web.xml 文件或者struts-config.xml 文件。首先來看web.xml 文件的配置:
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>
org.apache.struts.action.ActionServlet
</servlet-class>
<init-param>
<param-name>
application
</param-name>
<param-value>
com.systemmobile.example.ApplicationResources
</param-value>
</init-param>
</servlet>
這個配置說明你的資源包的名字是ApplicationResources.properties,它位于com.systemmobile.example 包中。后綴".properties" 是隱含的,你不必顯式地寫出來。如果你還有另一個資源文件在相同的包中,例如ApplicationResources_fr.properties ,用來支持法語,你只需要象上面定義的那樣列出文件名字即可。
定義資源文件的第二中方法(上面已經(jīng)提到),是在struts-config.xml 文件中配置:
<message-resources parameter="com.systemmobile.example.ApplicationResources"/>
屬性parameter 是必須的。和在web.xml文件中配置一樣, 需要注意的是文件在包中的位置。
使用struts-config.xml 文件來配置消息資源文件是推薦的做法,因為它更有可擴展性,更靈活。
你可以使用message-resources 標簽從不同的資源文件取不同的消息,前提是在配置的時候為不同的資源文件給出不同的key 屬性的值。例如: <message-resources key="myResources" parameter="com.systemmobile.example.
ApplicationResources"/>
<message-resources key="moreResources" parameter="com.systemmobile.example.
MoreApplicationResources"/> 然后你必須這樣使用bean:message 標簽: <bean:message bundle="moreResources" key="some.message.key"/> 設(shè)置屬性null 的值為"false" 后,如果某個資源字符串不存在將返回???key??? 而不是僅僅顯示null。這樣很容易在JSP頁面中看到你沒有定義的資源,使得內(nèi)部測試的速度更快。(關(guān)于如何從資源文件中獲得消息的詳細內(nèi)容參見國際化 一節(jié)) <message-resources parameter="com.systemmobile.example.ApplicationResources" null="false"/> 另外,message-resources 標簽允許你使用自己實現(xiàn)的MessageResourcesFactory 接口,這不在本文的討論范圍。
資源文件放在哪里
關(guān)于資源文件最常見的問題是將資源文件放在WAR文件的哪里。簡單的回答是該文件必須放在你的classpath下面,這意味著將資源文件放在一個JAR 文件中,或者放在/WEB-INF/classes 目錄極其子目錄下。下表給出了資源文件的位置,在message-resources 標簽中"parameter" 屬性的值以及簡短的說明。
Resources Location parameter Value Description
/WEB-INF/classes/ApplicationResources.properties ApplicationResources 文件放在classes 目錄下, 該目錄在web應(yīng)用的classpath中.
/WEB-INF/classes/resources/ApplicationResources.properties resources.ApplicationResources 該文件放在"resources" 目錄下, 所以包名也就是路徑名要給出。
In the app.jar file, in the com.systemmobile.example package/directory. com.systemmobile.example.ApplicationResources 文件在JAR文件中的全路徑。
Tags
最常用Struts 標簽是bean:message 標簽。使用這個標簽的"key" 可以從資源文件中讀特定的消息資源。你還可以傳入四個參數(shù)中的一個或全部:
<bean:message key="label.password"/>
<bean:message key="error.min.length" arg0="6"/>
<bean:message key="label.welcome" arg0="Ralph" arg1="Nader"/>
html:message 可以讓你向用戶顯示錯誤信息(默認)或消息信息,而html:errors 只顯示錯誤信息。很明顯,錯誤信息或消息信息一定要保存在request里,否則就什么也不會顯示。這里有一個顯示消息信息的例子:
<logic:messagesPresent message="true">
<html:messages id="msg" message="true">
<div class="success">
<bean:write name="msg"/>
</div><br/>
</html:messages>
</logic:messagesPresent>
還有一些標簽也有限地支持消息資源,比如html:link。html:link標簽通過定義"titleKey" 屬性來顯示標題文本。許多html 使用 "altKey" 屬性從資源文件里獲得alternate(替代)文本。
Actions
你還可以在Action 類中使用消息資源文件。Action 類有兩個方法得到一個MessageResource 類的實例:
// 返回一個request里的資源文件
protected MessageResources getResources(HttpServletRequest request);
// 返回一個request里的資源文件,
// 該資源文件的標志上<message-resources/> 元素的內(nèi)容
protected MessageResources getResources(javax.servlet.http.HttpServletRequest request,
java.lang.String key);
MessageResources類可以讓你從資源文件中得到本地化的消息。The API for MessageResources 可以在資源中找到。比較常用的方法有:
// these methods load a resources key for the given locale
public String getMessage(java.util.Locale locale, java.lang.String key);
public String getMessage(java.util.Locale locale, java.lang.String key,
java.lang.Object arg0);
public String getMessage(java.util.Locale locale, java.lang.String key,
java.lang.Object[] args);
public String getMessage(java.util.Locale locale, java.lang.String key,
java.lang.Object arg0, java.lang.Object arg1)
public String getMessage(java.util.Locale locale, java.lang.String key,
java.lang.Object arg0, java.lang.Object arg1, java.lang.Object arg2);
public String getMessage(java.util.Locale locale, java.lang.String key, java.lang.Object arg0,
java.lang.Object arg1, java.lang.Object arg2, java.lang.Object arg3);
// these methods load a resources key for the locale retrieved
// from the HttpServletRequest
public String getMessage(java.lang.String key);
public String getMessage(java.lang.String key, java.lang.Object arg0);
public String getMessage(java.lang.String key, java.lang.Object[] args);
public String getMessage(java.lang.String key, java.lang.Object arg0,
java.lang.Object arg1);
public String getMessage(java.lang.String key, java.lang.Object arg0,
java.lang.Object arg1, java.lang.Object arg2);
public String getMessage(java.lang.String key, java.lang.Object arg0,
java.lang.Object arg1, java.lang.Object arg2, java.lang.Object arg3);
這些返回的字符串可以被設(shè)置成request 或 session 的參數(shù)并串會表現(xiàn)層。你可能注意到了一些重載方法getMessage(...) 選擇了參數(shù)Object,而另外一些采用了參數(shù)arg0...arg3。這和 bean:message arg0...arg3 屬性等價。
除了MessageResources 類,還有一些類使用了資源文件。ActionMessage類被用來從action 向JSP之間傳遞消息資源中的keys 。消息被用來作為bean 的屬性。ActionError, ActionMessage的子類,使用消息資源中的keys 存儲驗證失敗后的錯誤信息。
國際化
從資源文件中提取一個本地化信息可以由類MessageResources 來處理,或者由它的直接子類PropertyMessageResources類處理。既然類PropertyMessageResources 等經(jīng)常地被用到,那么我們就來看看它是怎樣使用getMessage(Locale, String) 方法來從資源文件中讀取消息的。
舉例說明:
1. 如果你在ApplicationResources_pt_br.properties (Brazilian Portuguese)中沒有發(fā)現(xiàn)消息的定義,系統(tǒng)將在ApplicationResources_pt.properties 文件中找,如果ApplicationResources_pt.properties 文件不存在或者也沒有該消息,那就去ApplicationResources.properties 文件里查找了。
2. 如果消息找到了,它就被加到本地化的緩存中并返回java.lang.String型數(shù)據(jù)。
3. 如果消息沒有找到,此時如果returnNull 屬性被為默認的true,將返回 null。 否則將返回類似 ???key??? 的字符串,key 就是那個被傳遞的參數(shù)。
JSTL
JSTL (JavaServer Pages Standard Tag Library) 的fmt標簽最近開始流行起來,用來向JSP中顯示資源文件的信息。它能很好地和Struts結(jié)合在一起。使用它非常簡單,只要下載JSTL 的jar 文件和TLDs 并把它們拷貝到你的應(yīng)用的正確的位置,然后在web.xml文件中加入下面的內(nèi)容:
<context-param>
<param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
<param-value>ApplicationResources</param-value>
</context-param>
上面的配置是假定你的ApplicationResources.properties文件是放在/WEB-INF/classes 目錄下的。 參見above 更多情況。
然后將這個標簽庫直接放在你的JSP中:
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>
最后,下面的標簽將顯示資源文件的內(nèi)容:
<fmt:message key="label.first.name"/>
還有一個使用fmt 標簽獲得資源的例子。(注意: 該段程序取自Jakarta JSTL examples。)
// loading a resource from a specific bundle and populating a parameter
<fmt:message key="currentTime" bundle="${deBundle}">
<fmt:param value="${currentDateString}"/>
</fmt:message>
// using the forEach iterator to populate paramters
<fmt:message key="serverInfo" bundle="${deBundle}">
<c:forEach var="arg" items="${serverInfoArgs}">
<fmt:param value="${arg}"/>
</c:forEach>
</fmt:message>
結(jié)論
在向JSP文件方便地傳遞消息的同時,Struts使用消息資源文件還幫助我們創(chuàng)建國際化的Web應(yīng)用。我們既可以使用正在快速發(fā)展中的JSTL標簽,也可以使用Struts標簽,或直接在action中得到一條具體的消息。我希望這篇文章為您闡明了一些Struts中常用的但有時會混淆的東西。
關(guān)于作者
Nick Heudecker 是一位軟件開發(fā)人員,具有6年的企業(yè)應(yīng)用的開發(fā)經(jīng)驗。 他所在的公司, System Mobile, Inc.,專門從事應(yīng)用集成,定制軟件開發(fā)和無線應(yīng)用。 他還是Sun認證JAVA程序員,現(xiàn)在居住在Ann Arbor, Michigan。
資源
下面的資源也許對您了解更多的關(guān)于Struts資源文件有幫助:
JavaDoc for the classes of interest:
java.util.ResourceBundlejava.util.Localeorg.apache.struts.util.MessageResourcesorg.apache.struts.action.ActionErrororg.apache.struts.action.ActionMessageTed Husted‘s Struts Tips: Very handy advice, especially for resource bundle usage.
Struts Home PageStruts-User Mailing List Archive: Many people use Struts, so there is a very good chance that your question has be answered already. Please use all available resources before asking your question on the mailing list.
JSTL Homepage and the
Jakarta JSTL Implementation注意事項
Packages are just directory structures used to avoid naming conflicts. If you put a message bundle in a directory named resources under /WEB-INF/classes, this is the equivalent of putting the file in a package named resrouces. While basic, this point seems to trip up many new programmers.