JSP 標(biāo)準(zhǔn)標(biāo)記庫(kù)(JSP Standard Tag Library,JSTL)fmt 庫(kù)通過(guò)一組頗受關(guān)注的定制標(biāo)記提供了用于訪問(wèn)所有 Java 編程語(yǔ)言國(guó)際化功能的便利方式。Mark Kolb 研究了用于對(duì)數(shù)據(jù)進(jìn)行格式化和國(guó)際化的 fmt 標(biāo)記。
在本系列的前幾篇文章中,我們討論了 JSTL 及其表達(dá)式語(yǔ)言(EL)。我們還研究了由 core
庫(kù)定義的定制標(biāo)記。具體而言,在“ JSTL 入門:表達(dá)式語(yǔ)言”中我們指出 EL 提供了一種簡(jiǎn)化語(yǔ)言,用于在 JSP 應(yīng)用程序中訪問(wèn)和操作數(shù)據(jù)并使該數(shù)據(jù)可被 JSTL 定制標(biāo)記用作動(dòng)態(tài)屬性值。 core
庫(kù)包含了一些定制標(biāo)記,用于管理限定了作用域的變量、顯示 EL 值、實(shí)現(xiàn)迭代內(nèi)容和條件內(nèi)容以及與 URL 進(jìn)行交互,這是“ JSTL 入門:探討 core”的主題。
我們接下來(lái)將討論的 JSTL 庫(kù)是 fmt
庫(kù)。 fmt
庫(kù)中的定制標(biāo)記支持通過(guò)資源束對(duì)文本內(nèi)容進(jìn)行本地化,并支持對(duì)數(shù)字和日期的顯示和解析。這些標(biāo)記利用在 java.util
和 java.text
包中實(shí)現(xiàn)的 Java 語(yǔ)言的國(guó)際化 API,因此如果您已經(jīng)很熟悉諸如 ResourceBundle
、 Locale
、 MessageFormat
和 DateFormat
這樣的類,那么您將發(fā)現(xiàn) fmt
庫(kù)中有很多方面值得稱道。如果您不熟悉這些類,那么 fmt
庫(kù)的標(biāo)記用直觀的方式來(lái)封裝國(guó)際化 API,這種方式使您能夠很容易將本地化功能合并到 JSP 應(yīng)用程序中。
在 Java 語(yǔ)言國(guó)際化 API 中,影響數(shù)據(jù)本地化方式的因素主要有兩個(gè)。一個(gè)是用戶的 語(yǔ)言環(huán)境,另一個(gè)是用戶的 時(shí)區(qū)。語(yǔ)言環(huán)境表示某一特定區(qū)域或文化的語(yǔ)言習(xí)慣,包括日期、數(shù)字和貨幣金額的格式。一個(gè)語(yǔ)言環(huán)境始終會(huì)有一種相關(guān)聯(lián)的語(yǔ)言,在許多情況下這種語(yǔ)言是由多個(gè)語(yǔ)言環(huán)境共享的某種語(yǔ)言的方言。例如,美國(guó)英語(yǔ)、英國(guó)英語(yǔ)、澳大利亞英語(yǔ)和加拿大英語(yǔ)都具有不同的英語(yǔ)語(yǔ)言環(huán)境,而法國(guó)、比利時(shí)、瑞士和加拿大所用的法語(yǔ)方言則都具有不同的法語(yǔ)語(yǔ)言環(huán)境。
![]() |
|
時(shí)區(qū)是數(shù)據(jù)本地化中的第二個(gè)因素,這僅僅是因?yàn)橐恍┱Z(yǔ)言環(huán)境分布的地理區(qū)域很廣。當(dāng)您顯示有關(guān)跨洲語(yǔ)言環(huán)境(比如澳大利亞英語(yǔ))的時(shí)間信息時(shí),針對(duì)用戶時(shí)區(qū)定制數(shù)據(jù)與對(duì)其進(jìn)行正確格式化一樣重要。
但是這就有了一個(gè)問(wèn)題:應(yīng)用程序如何確定用戶的語(yǔ)言環(huán)境和時(shí)區(qū)?在 Java 應(yīng)用程序的情況下,JVM 能夠通過(guò)與本地操作系統(tǒng)進(jìn)行交互來(lái)設(shè)置缺省語(yǔ)言環(huán)境和時(shí)區(qū)。雖然這種方法對(duì)于桌面應(yīng)用程序而言可以正常工作,但是它實(shí)際上并不適合于服務(wù)器端的 Java 應(yīng)用程序,因?yàn)檫@種應(yīng)用程序所處理的請(qǐng)求,可能來(lái)自于距離該應(yīng)用程序所駐留的服務(wù)器萬(wàn)里之遙的地方。
幸運(yùn)的是,HTTP 協(xié)議通過(guò) Accept-Language
請(qǐng)求頭將本地化信息從瀏覽器傳遞至服務(wù)器。許多 Web 瀏覽器允許用戶定制他們的語(yǔ)言首選項(xiàng),如圖 1 所示。通常,那些沒(méi)有為一種或多種首選語(yǔ)言環(huán)境提供顯式設(shè)置的瀏覽器會(huì)詢問(wèn)操作系統(tǒng)以確定在 Accept-Language
頭中發(fā)送哪個(gè)值(或哪些值)。servlet 規(guī)范通過(guò) javax.servlet.ServletRequest
類的 getLocale()
和 getLocales()
方法自動(dòng)地利用 HTTP 協(xié)議的這一功能。JSTL fmt
庫(kù)中的定制標(biāo)記又會(huì)利用這些方法來(lái)自動(dòng)地確定用戶的語(yǔ)言環(huán)境,從而相應(yīng)地調(diào)整它們的輸出。
圖 1. 通過(guò)設(shè)置瀏覽器的語(yǔ)言首選項(xiàng)來(lái)選擇語(yǔ)言環(huán)境

但遺憾的是,不存在將用戶的時(shí)區(qū)從瀏覽器傳輸?shù)椒?wù)器的標(biāo)準(zhǔn) HTTP 請(qǐng)求頭。因此,那些希望自己的 Web 應(yīng)用程序?qū)r(shí)間數(shù)據(jù)進(jìn)行本地化的用戶,將需要實(shí)現(xiàn)他們自己的機(jī)制,用來(lái)確定和跟蹤特定于用戶的時(shí)區(qū)。例如,在本系列文章第 2 部分“ JSTL 入門:探討 core”中所介紹的 Weblog 應(yīng)用程序包含了一種將用戶的時(shí)區(qū)首選項(xiàng)存儲(chǔ)在 cookie 中的方式。
![]() ![]() |
![]()
|
JSTL fmt
庫(kù)中的定制標(biāo)記主要分成四組。第一組允許您設(shè)置本地化上下文,其它標(biāo)記將在其中進(jìn)行操作。換句話說(shuō),這組標(biāo)記允許頁(yè)面作者顯式地設(shè)置其它 fmt
標(biāo)記在格式化數(shù)據(jù)時(shí)將要使用的語(yǔ)言環(huán)境和時(shí)區(qū)。第二組和第三組標(biāo)記分別支持對(duì)日期和數(shù)字進(jìn)行格式化和解析。最后一組標(biāo)記側(cè)重于對(duì)文本消息進(jìn)行本地化。
既然我們已經(jīng)有了些基本了解,那就讓我們集中精力逐個(gè)研究這四組標(biāo)記,并演示其用法。
正如我們已經(jīng)討論過(guò)的那樣,JSTL 標(biāo)記在格式化數(shù)據(jù)時(shí)所使用的語(yǔ)言環(huán)境往往是通過(guò)查看用戶瀏覽器發(fā)送的每個(gè) HTTP 請(qǐng)求所包含的 Accept-Language
頭來(lái)確定的。如果沒(méi)有提供這樣的頭,那么 JSTL 提供一組 JSP 配置變量,您可以設(shè)置這些變量以指定缺省的語(yǔ)言環(huán)境。如果尚未設(shè)置這些配置變量,那么就使用 JVM 的缺省語(yǔ)言環(huán)境,該缺省語(yǔ)言環(huán)境是從 JSP 容器所運(yùn)行的操作系統(tǒng)中獲取的。
fmt
庫(kù)提供了其自身的定制標(biāo)記,以覆蓋這個(gè)確定用戶語(yǔ)言環(huán)境的過(guò)程: <fmt:setLocale>
。正如下面的代碼片段所示, <fmt:setLocale>
操作支持三個(gè)屬性:
|
其中只有一個(gè)屬性是必需的: value
屬性。該屬性的值應(yīng)當(dāng)是命名該語(yǔ)言環(huán)境的一個(gè)字符串或者是 java.util.Locale
類的一個(gè)實(shí)例。語(yǔ)言環(huán)境名稱是這樣組成的:小寫的兩字母 ISO 語(yǔ)言代碼,可選地,后面可以跟下劃線或連字符以及大寫的兩字母 ISO 國(guó)家或地區(qū)代碼。
例如, en
是英語(yǔ)的語(yǔ)言代碼, US
是美國(guó)的國(guó)家或地區(qū)代碼,因此 en_US
(或 en-US
)將是美式英語(yǔ)的語(yǔ)言環(huán)境名稱。類似的, fr
是法語(yǔ)的語(yǔ)言代碼, CA
是加拿大的國(guó)家或地區(qū)代碼,因此 fr_CA
(或 fr-CA
)是加拿大法語(yǔ)的語(yǔ)言環(huán)境名稱(請(qǐng)參閱 參考資料以獲取所有有效的 ISO 語(yǔ)言和國(guó)家或地區(qū)代碼的鏈接)。當(dāng)然,由于國(guó)家或地區(qū)代碼是可選的,因此 en
和 fr
本身就是有效的語(yǔ)言環(huán)境名稱,適用于不區(qū)別這些相應(yīng)語(yǔ)言特定方言的應(yīng)用程序。
<fmt:setLocale>
的可選屬性 scope
用來(lái)指定語(yǔ)言環(huán)境的作用域。 page
作用域指出這項(xiàng)設(shè)置只適用于當(dāng)前頁(yè),而 request
作用域?qū)⑺鼞?yīng)用于請(qǐng)求期間訪問(wèn)的所有 JSP 頁(yè)面。如果將 scope
屬性設(shè)置成 session
,那么指定的語(yǔ)言環(huán)境被用于用戶會(huì)話期間訪問(wèn)的所有 JSP 頁(yè)面。值 application
指出該語(yǔ)言環(huán)境適用于該 Web 應(yīng)用程序所有 JSP 頁(yè)面的全部請(qǐng)求和該應(yīng)用程序所有用戶的全部請(qǐng)求。
variant
屬性(也是可選的)允許您進(jìn)一步針對(duì)特定的 Web 瀏覽器平臺(tái)或供應(yīng)商定制語(yǔ)言環(huán)境。例如, MAC
和 WIN
分別是 Apple Macintosh 和 Microsoft Windows 平臺(tái)的變體名。
下面的代碼片段說(shuō)明了如何使用 <fmt:setLocale>
標(biāo)記來(lái)顯式指定用戶會(huì)話的語(yǔ)言環(huán)境設(shè)置:
|
JSP 容器處理完該 JSP 代碼段之后,將忽略用戶瀏覽器設(shè)置中所指定的語(yǔ)言首選項(xiàng)。
<fmt:setTimeZone>
操作像 <fmt:setLocale>
一樣,可以用來(lái)設(shè)置其它 fmt
定制標(biāo)記所使用的缺省時(shí)區(qū)值。它的語(yǔ)法如下所示:
|
和 <fmt:setLocale>
一樣,只有 value
屬性是必需的,但是在本例中它應(yīng)當(dāng)是時(shí)區(qū)名或 java.util.TimeZone
類的實(shí)例。
遺憾的是,對(duì)于時(shí)區(qū)命名目前還沒(méi)有任何被廣泛接受的標(biāo)準(zhǔn)。因此您可以用于 <fmt:setTimezone>
標(biāo)記的 value
屬性的時(shí)區(qū)名是特定于 Java 平臺(tái)的。您可以通過(guò)調(diào)用 java.util.TimeZone
類的 getAvailableIDs()
靜態(tài)方法來(lái)檢索有效的時(shí)區(qū)名列表。示例包括 US/Eastern
、 GMT+8
和 Pacific/Guam
。
和 <fmt:setLocale>
的情況一樣,您可以使用可選的 scope
屬性來(lái)指出時(shí)區(qū)設(shè)置的作用域。下面的代碼演示了 <fmt:setTimeZone>
的用法,它用來(lái)指定適用于單個(gè)用戶會(huì)話的時(shí)區(qū):
|
您還可以使用 <fmt:setTimeZone>
操作將 TimeZone
實(shí)例的值存儲(chǔ)在限定了作用域的變量中。在本例中,您可以使用 var
屬性來(lái)命名限定了作用域的變量,用 scope
屬性來(lái)指定該變量的作用域(例如,就象這兩個(gè)屬性用在 <c:set>
和 <c:if>
操作中)。請(qǐng)注意,當(dāng)您以這種方式使用 <fmt:setTimeZone>
操作時(shí),它唯一的副作用就是設(shè)置指定的變量。當(dāng)指定 var
屬性時(shí),對(duì)于任何其它 JSTL 標(biāo)記使用什么時(shí)區(qū),不會(huì)對(duì) JSP 環(huán)境作任何更改。
這組中的最后一個(gè)標(biāo)記是 <fmt:timeZone>
操作:
|
和 <fmt:setTimeZone>
一樣,您可以使用該標(biāo)記來(lái)指定將由其它 JSTL 標(biāo)記使用的時(shí)區(qū)。但是, <fmt:timeZone>
操作的作用域僅限于其標(biāo)記體內(nèi)容。在 <fmt:timeZone>
標(biāo)記體中,由標(biāo)記的 value
屬性指定的時(shí)區(qū)覆蓋了 JSP 環(huán)境中現(xiàn)有的任何其它時(shí)區(qū)設(shè)置。
和 <fmt:setTimeZone>
的情況一樣, <fmt:timeZone>
標(biāo)記的 value
屬性應(yīng)當(dāng)是時(shí)區(qū)名或者是 java.util.TimeZone
實(shí)例。后面的 清單 1 中提供了一個(gè)如何使用 <fmt:timeZone>
的示例。
fmt
庫(kù)包含了用來(lái)與日期和時(shí)間進(jìn)行交互的兩個(gè)標(biāo)記: <fmt:formatDate>
和 <fmt:parseDate>
。顧名思義, <fmt:formatDate>
用來(lái)格式化和顯示日期和時(shí)間(數(shù)據(jù) 輸出),而 <fmt:parseDate>
用來(lái)解析日期和時(shí)間值(數(shù)據(jù) 輸入)。
<fmt:formatDate>
的語(yǔ)法如下所示:
|
只有 value
屬性才是必需的。其值應(yīng)當(dāng)是 java.util.Date
類的實(shí)例,指定要進(jìn)行格式化和顯示的日期和/或時(shí)間數(shù)據(jù)。
可選的 timeZone
屬性指出將要顯示哪個(gè)時(shí)區(qū)的日期和/或時(shí)間。如果沒(méi)有顯式地指定 timeZone
屬性,那么就使用周圍任何 <fmt:timeZone>
標(biāo)記所指定的時(shí)區(qū)。如果 <fmt:timeZone>
標(biāo)記的主體部分沒(méi)有包含 <fmt:formatDate>
操作,那么就使用任何適用的 <fmt:setTimeZone>
操作所設(shè)置的時(shí)區(qū)。如果沒(méi)有相關(guān)的 <fmt:setTimeZone>
操作,那么就使用 JVM 的缺省時(shí)區(qū)(也就是,專為本地操作系統(tǒng)而設(shè)置的時(shí)區(qū))。
type
屬性指出要顯示指定的 Date
實(shí)例的哪些字段,應(yīng)當(dāng)是 time
、 date
或 both
。該屬性的缺省值是 date
,因此如果沒(méi)有給出 type
屬性,那么 <fmt:formatDate>
標(biāo)記(名符其實(shí))將只顯示與 Date
實(shí)例相關(guān)的日期信息,這個(gè)信息用該標(biāo)記的 value
屬性指定。
dateStyle
和 timeStyle
屬性分別指出應(yīng)當(dāng)如何格式化日期和時(shí)間信息。有效的樣式有 default
、 short
、 medium
、 long
和 full
。缺省值自然是 default
,指出應(yīng)當(dāng)使用特定于語(yǔ)言環(huán)境的樣式。其它四個(gè)樣式值的語(yǔ)義與 java.text.DateFormat
類定義的一樣。
可以使用 pattern
屬性來(lái)指定定制樣式,而不必依賴于內(nèi)置樣式。給出定制樣式后,該模式屬性的值應(yīng)當(dāng)是符合 java.text.SimpleDateFormat
類約定的模式字符串。這些模式基于用對(duì)應(yīng)的日期和時(shí)間字段代替模式內(nèi)指定的字符。例如,模式 MM/dd/yyyy
表明應(yīng)當(dāng)顯示用正斜杠分隔的兩位數(shù)的月份和日期值以及四位數(shù)的年份值。
如果指定了 var
屬性,那就把包含格式化日期的 String
值指派給指定的變量。否則, <fmt:formatDate>
標(biāo)記將寫出格式化結(jié)果。當(dāng)指定了 var
屬性后, scope
屬性指定所生成變量的作用域。
清單 1(它是本系列 第 2 部分清單 8 的擴(kuò)展)包含了 <fmt:formatDate>
標(biāo)記的兩種用法。在第一種用法中, <fmt:formatDate>
只用來(lái)顯示第一個(gè) weblog 項(xiàng)的創(chuàng)建時(shí)間戳記的日期部分。此外,為 dateStyle
屬性指定了一個(gè) full
值,這樣一來(lái)所有的日期字段就將用一種特定于語(yǔ)言環(huán)境的格式進(jìn)行顯示。
清單 1. 使用 <fmt:formatDate> 標(biāo)記來(lái)顯示日期和時(shí)間值
|
在 <c:forEach>
循環(huán)體中,第二個(gè) <fmt:formatDate>
操作只用來(lái)顯示每個(gè)項(xiàng)的創(chuàng)建日期的時(shí)間部分。在本例中, pattern
屬性用來(lái)控制時(shí)間值的格式化、并控制指定一位數(shù)的小時(shí)顯示(如果可能的話)、12 小時(shí)的時(shí)鐘和縮寫時(shí)區(qū)的輸出。輸出如圖 2 所示:
圖 2. 清單 1 中 en_US 語(yǔ)言環(huán)境的輸出

更準(zhǔn)確地說(shuō),用戶瀏覽器設(shè)置指定首選項(xiàng)是英語(yǔ)時(shí),就會(huì)產(chǎn)生圖 2 中所示的輸出。但是由于 <fmt:formatDate>
對(duì)用戶語(yǔ)言環(huán)境敏感,所以瀏覽器首選項(xiàng)的改變將導(dǎo)致生成不同的內(nèi)容。例如,當(dāng)給定的首選項(xiàng)是法語(yǔ)語(yǔ)言環(huán)境時(shí),則結(jié)果會(huì)如圖 3 所示:
圖 3. 清單 1 中 fr_CA 語(yǔ)言環(huán)境的輸出

<fmt:formatDate>
生成了 java.util.Date
實(shí)例的本地化字符串表示,而 <fmt:parseDate>
操作執(zhí)行相反的操作:給定一個(gè)表示日期和/或時(shí)間的字符串,它將生成相應(yīng)的 Date
對(duì)象。 <fmt:parseDate>
操作有兩種格式,如下所示:
|
對(duì)于第一種格式,只有 value
屬性才是必需的,它的值應(yīng)當(dāng)是指定日期、時(shí)間或這兩者組合的字符串。對(duì)于第二種格式,沒(méi)有必需的屬性,表示要解析的值的字符串被指定為 <fmt:parseDate>
標(biāo)記必需的標(biāo)記體內(nèi)容。
type
、 dateStyle
、 timeStyle
、 pattern
和 timeZone
屬性對(duì) <fmt:parseDate>
和對(duì) <fmt:formatDate>
起一樣的作用,不同之處僅在于對(duì)于前者,它們控制日期值的解析而非顯示。 parseLocale
屬性用來(lái)指定一種語(yǔ)言環(huán)境,將根據(jù)這種語(yǔ)言環(huán)境來(lái)解析該標(biāo)記的值,它應(yīng)當(dāng)是語(yǔ)言環(huán)境的名稱或 Locale
類的實(shí)例。
var
和 scope
屬性用來(lái)指定限定了作用域的變量(作為 <fmt:parseDate>
的結(jié)果),將把 Date
對(duì)象賦給該變量。如果沒(méi)有給出 var
屬性,則使用 Date
類的 toString()
方法將結(jié)果寫到 JSP 頁(yè)面中。清單 2 顯示了 <fmt:parseDate>
操作的一個(gè)示例:
清單 2. 使用 <fmt:parseDate> 標(biāo)記來(lái)解析日期和時(shí)間
|
清單 2 的輸出如圖 4 所示。
圖 4. 清單 2 的輸出

由 <fmt:parseDate>
所執(zhí)行的解析非常嚴(yán)格,注意這一點(diǎn)很重要。正如清單 2 所暗示的那樣,要解析的值必須嚴(yán)格符合特定(特定于語(yǔ)言環(huán)境)的樣式或模式。這當(dāng)然更加受限制。另一方面,數(shù)據(jù)的解析并不是一個(gè)非常適合于表示層的任務(wù)。對(duì)于生產(chǎn)代碼,文本輸入的驗(yàn)證和轉(zhuǎn)換最好由后端代碼(比如 servlet)來(lái)處理,而不是通過(guò) JSP 定制標(biāo)記來(lái)處理。
就象 <fmt:formatDate>
和 <fmt:parseDate>
標(biāo)記用于格式化和解析日期一樣, <fmt:formatNumber>
和 <fmt:parseNumber>
標(biāo)記對(duì)數(shù)字?jǐn)?shù)據(jù)執(zhí)行類似的功能。
<fmt:formatNumber>
標(biāo)記用來(lái)以特定于語(yǔ)言環(huán)境的方式顯示數(shù)字?jǐn)?shù)據(jù),包括貨幣和百分?jǐn)?shù)。 <fmt:formatNumber>
操作由語(yǔ)言環(huán)境確定,例如,使用句點(diǎn)還是使用逗號(hào)來(lái)定界數(shù)字的整數(shù)和小數(shù)部分。下面是它的語(yǔ)法:
|
如 <fmt:formatDate>
的情況一樣,只有 value
屬性才是必需的。它用來(lái)指定將被格式化的數(shù)值。 var
和 scope
屬性對(duì) <fmt:formatNumber>
操作所起的作用,如它們?cè)?<fmt:formatDate>
中所起的作用一樣。
type
屬性的值應(yīng)當(dāng)是 number
、 currency
或 percentage
,并指明要對(duì)哪種類型的數(shù)值進(jìn)行格式化。該屬性的缺省值是 number
。 pattern
屬性優(yōu)先于 type
屬性,允許對(duì)遵循 java.text.DecimalFormat
類模式約定的數(shù)值進(jìn)行更精確的格式化。
當(dāng) type
屬性的值為 currency
時(shí), currencyCode
屬性可以用來(lái)顯式地指定所顯示的數(shù)值的貨幣單位。與語(yǔ)言和國(guó)家或地區(qū)代碼一樣,貨幣代碼也是由 ISO 標(biāo)準(zhǔn)管理的(請(qǐng)參閱 參考資料以獲取所有有效的 ISO 貨幣符號(hào)代碼的鏈接)。該代碼用來(lái)確定作為已格式化值的一部分顯示的貨幣符號(hào)。
另外,您可以使用 currencySymbol
屬性來(lái)顯式地指定貨幣符號(hào)。請(qǐng)注意,由于 JDK 1.4 和相關(guān)的 java.util.Currency
類的引入, <fmt:formatNumber>
操作的 currencyCode
屬性優(yōu)先權(quán)超過(guò) currencySymbol
屬性。但是對(duì)于較老版本的 JDK 而言, currencySymbol
屬性具有優(yōu)先權(quán)。
maxIntegerDigits
、 minIntegerDigits
、 maxFractionDigits
和 minFractionDigits
屬性用來(lái)控制小數(shù)點(diǎn)前后所顯示的有效數(shù)字的個(gè)數(shù)。這些屬性要求是整數(shù)值。
groupingUsed
屬性帶有布爾值并控制是否要對(duì)小數(shù)點(diǎn)前面的數(shù)字分組。例如,在英語(yǔ)語(yǔ)言環(huán)境中,將較大數(shù)的每三個(gè)數(shù)字分為一組,每組用逗號(hào)定界。其它語(yǔ)言環(huán)境用句點(diǎn)或空格來(lái)定界這樣的分組。該屬性的缺省值為 true
。
清單 3 顯示了一個(gè)簡(jiǎn)單的貨幣示例,它本身是 清單 1 的擴(kuò)展。在本例中,不指定 currencyCode
或 currencySymbol
屬性。而貨幣是由語(yǔ)言環(huán)境設(shè)置確定的。
清單 3. 使用 <fmt:formatNumber> 標(biāo)記顯示貨幣值
|
en_US
語(yǔ)言環(huán)境的輸出如圖 5 所示:
圖 5. 清單 3 的 en_US 語(yǔ)言環(huán)境的輸出

fr_CA
語(yǔ)言環(huán)境的輸出如圖 6 所示:
圖 6. 清單 3 的 fr_CA 語(yǔ)言環(huán)境的輸出

如下所示, <fmt:parseNumber>
操作解析了一個(gè)數(shù)值,該數(shù)值是通過(guò) value
屬性或該操作的標(biāo)記體內(nèi)容以特定于語(yǔ)言環(huán)境的方式提供的,將結(jié)果作為 java.lang.Number
類的實(shí)例返回。 type
和 pattern
屬性對(duì) <fmt:parseNumber>
和對(duì) <fmt:formatNumber>
起一樣的作用。同樣, parseLocale
、 var
和 scope
屬性對(duì) <fmt:parseNumber>
起與 <fmt:parseDate>
一樣的作用。
|
先前有關(guān) <fmt:parseDate>
的說(shuō)明同樣適用于 <fmt:parseNumber>
:解析數(shù)據(jù)并不是一項(xiàng)非常適合于表示層的任務(wù)。如果解析和驗(yàn)證數(shù)據(jù)作為應(yīng)用程序業(yè)務(wù)邏輯的一部分實(shí)現(xiàn),那么軟件維護(hù)將會(huì)得到簡(jiǎn)化。由于這個(gè)原因,通常建議大家在產(chǎn)品 JSP 頁(yè)面中避免同時(shí)使用 <fmt:parseDate>
和 <fmt:parseNumber>
。
只有 integerOnly
屬性才是 <fmt:parseNumber>
所獨(dú)有的。該屬性獲取一個(gè)布爾值,指出是否應(yīng)當(dāng)只解析所給值的整數(shù)部分。如果該屬性的值為 true
,那么就忽略要被解析的字符串中跟在小數(shù)點(diǎn)后面的任何數(shù)字。該屬性的缺省值為 false
。
在 JSTL 中用 <fmt:message>
標(biāo)記實(shí)現(xiàn)文本的本地化。該標(biāo)記允許您從特定于語(yǔ)言環(huán)境的資源束中檢索文本消息并顯示在 JSP 頁(yè)面上。而且,由于該操作利用 java.text.MessageFormat
類所提供的功能,所以可以將參數(shù)化的值替換進(jìn)這樣的文本消息,以便動(dòng)態(tài)地定制本地化內(nèi)容。
用于存儲(chǔ)特定于語(yǔ)言環(huán)境消息的資源束采用類或特性文件的形式,這些類或特性文件符合標(biāo)準(zhǔn)命名約定,在這種命名約定中基名和語(yǔ)言環(huán)境名組合在一起。例如,請(qǐng)研究名為 Greeting.properties
的特性文件,它駐留在我們的 weblog 應(yīng)用程序的類路徑中,該類路徑位于與 com.taglib.weblog
包相對(duì)應(yīng)的子目錄中。您可以通過(guò)在同一目錄下指定兩個(gè)新的特性文件,從而將該特性文件所描述的資源束本地化為英語(yǔ)和法語(yǔ),通過(guò)追加相應(yīng)的語(yǔ)言代碼來(lái)命名。具體而言,這兩個(gè)文件應(yīng)當(dāng)分別命名為 Greeting_en.properties
和 Greeting_fr.properties
。如果希望另一個(gè)本地化為加拿大法語(yǔ),您可以引入第三個(gè)特性文件,在其名稱中包含了相應(yīng)的國(guó)家或地區(qū)代碼(比如 Greeting_fr_CA.properties
)。
這些文件都可以定義相同的特性,但是應(yīng)當(dāng)將這些特性的值定制成對(duì)應(yīng)的語(yǔ)言或方言。這種方法如清單 4 和清單 5 所示,它們給出了 Greeting_en.properties
和 Greeting_fr.properties
文件的樣本內(nèi)容。在這些示例中,定義了兩個(gè)已本地化的消息。它們可以通過(guò) com.taglib.weblog.Greeting.greeting
和 com.taglib.weblog.Greeting.return
鍵識(shí)別。但是已經(jīng)將與這些鍵相關(guān)聯(lián)的值本地化為文件名中所確定的語(yǔ)言。請(qǐng)注意,出現(xiàn)在 com.taglib.weblog.Greeting.greeting
消息的兩個(gè)值中的 {0}
模式使已參數(shù)化的值能夠在內(nèi)容生成期間動(dòng)態(tài)地插入到消息中。
清單 4. Greeting_en.properties 本地化資源束的內(nèi)容
|
清單 5. Greeting_fr.properties 本地化資源束的內(nèi)容
|
用 JSTL 顯示這樣的本地化內(nèi)容,第一步就是指定資源束。 fmt
庫(kù)為完成這一任務(wù)提供了兩個(gè)定制標(biāo)記: <fmt:setBundle>
和 <fmt:bundle>
,它們的行為和前面介紹的 <fmt:setTimeZone>
和 <fmt:timeZone>
標(biāo)記相似。 <fmt:setBundle>
操作設(shè)置了一個(gè)缺省資源束,供 <fmt:message>
標(biāo)記在特定作用域內(nèi)使用,而 <fmt:bundle>
指定了為嵌套在其標(biāo)記體內(nèi)容中的全部和任意 <fmt:message>
操作所用的資源束。
下面的代碼片段顯示了 <fmt:setBundle>
標(biāo)記的語(yǔ)法。 basename
屬性是必需的,它標(biāo)識(shí)了設(shè)為缺省值的資源束。請(qǐng)注意, basename
屬性的值不應(yīng)當(dāng)包含任何本地化后綴或文件擴(kuò)展名。清單 4 和清單 5 中給出的示例資源束的基名為 com.taglib.weblog.Greeting
。
|
可選的 scope
屬性指明缺省資源束設(shè)置所應(yīng)用的 JSP 作用域。如果沒(méi)有顯式地指定該屬性,就假定為 page
作用域。
如果指定了可選的 var
屬性,那么將把由 basename
屬性所標(biāo)識(shí)的資源束賦給該屬性值所命名的變量。在這種情況下, scope
屬性指定變量的作用域;沒(méi)有將缺省資源束賦給相應(yīng)的 JSP 作用域。
您使用 <fmt:bundle>
標(biāo)記(其語(yǔ)法如下所示)在其標(biāo)記體內(nèi)容的作用域內(nèi)設(shè)置缺省資源束。和 <fmt:setBundle>
一樣,只有 basename
屬性才是必需的。您可以使用可選的 prefix
屬性來(lái)為任何嵌套的 <fmt:message>
操作的 key
值指定缺省前綴。
|
一旦設(shè)置了資源束,真正起到顯示本地化消息作用的是 <fmt:message>
標(biāo)記。該操作支持兩種不同的語(yǔ)法,這取決于是否需要任何嵌套的 <fmt:param>
標(biāo)記:
|
對(duì)于 <fmt:message>
,只有 key
屬性才是必需的。 key
屬性的值用來(lái)確定要顯示在資源束中定義的哪些消息。
您可以使用 bundle
屬性來(lái)指定一個(gè)顯式的資源束,用來(lái)查找由 key
屬性標(biāo)識(shí)的消息。請(qǐng)注意,該屬性的值必須是實(shí)際的資源束,比如當(dāng)指定 <fmt:setBundle>
操作的 var
屬性時(shí)由該操作所賦予的資源束。 <fmt:message>
的 bundle
屬性不支持字符串值(比如 <fmt:bundle>
和 <fmt:setBundle>
的 basename
屬性)。
如果指定了 <fmt:message>
的 var
屬性,那么將由該標(biāo)記所生成的文本消息賦給指定的變量,而不是寫到 JSP 頁(yè)面。通常,可選的 scope
屬性用來(lái)指定由 var
屬性指定的變量的作用域。
需要的時(shí)候您可以通過(guò)使用 <fmt:param>
標(biāo)記的 value
屬性來(lái)提供文本消息的參數(shù)化值。或者,可以將該值指定為 <fmt:param>
標(biāo)記體內(nèi)容,在這種情況下省略該屬性。無(wú)論參數(shù)化值模式出現(xiàn)在消息文本中的什么地方,由 <fmt:param>
標(biāo)記指定的值都將合并到從資源束檢索的消息,這與 java.text.MessageFormat
類的行為一致。因?yàn)閰?shù)化值可以通過(guò)其下標(biāo)進(jìn)行標(biāo)識(shí),因此嵌套的 <fmt:param>
標(biāo)記的順序很重要。
<fmt:bundle>
、 <fmt:message>
和 <fmt:param>
標(biāo)記的交互作用如清單 6 所示。此處, <fmt:bundle>
標(biāo)記通過(guò)兩個(gè)嵌套的 <fmt:message>
標(biāo)記指定了要在其中檢索本地化消息的資源束。這兩個(gè) <fmt:message>
標(biāo)記的第一個(gè)對(duì)應(yīng)于帶有一個(gè)參數(shù)化值的消息,還出現(xiàn)了對(duì)應(yīng)的用于該值的 <fmt:param>
標(biāo)記。
清單 6. 使用 <fmt:message> 標(biāo)記顯示本地化消息
|
清單 7 演示了 <fmt:bundle>
的 prefix
屬性的用法;為 prefix
屬性提供的值在嵌套的 <fmt:message>
操作中自動(dòng)地預(yù)先添加到所有 key
值上。因此清單 7 相當(dāng)于清單 6,只是清單 7 利用了這一便利的特性,使得能夠在兩個(gè) <fmt:message>
標(biāo)記中使用縮略的 key
值。
清單 7. <fmt:bundle> 的 prefix 屬性對(duì) <fmt:message> 標(biāo)記的影響
|
圖 7 和圖 8 演示了正在工作的 fmt
庫(kù)與消息相關(guān)的標(biāo)記,顯示了由清單 7 中代碼所產(chǎn)生的輸出,以及 清單 4和 清單 5中的本地化資源束。圖 7 顯示了當(dāng)瀏覽器首選項(xiàng)為英語(yǔ)語(yǔ)言環(huán)境時(shí)的結(jié)果。
圖 7. 清單 7 中 en_US 語(yǔ)言環(huán)境的輸出

圖 8 顯示了指定法語(yǔ)的語(yǔ)言環(huán)境的輸出。
圖 8. 清單 7 的 fr_CA 語(yǔ)言環(huán)境的輸出

![]() ![]() |
![]()
|
JSTL fmt
庫(kù)的定制標(biāo)記為 JSP 開發(fā)人員提供了一種對(duì) Java 平臺(tái)的國(guó)際化 API 的簡(jiǎn)單訪問(wèn)。文本消息、數(shù)值和日期都可以用對(duì)語(yǔ)言環(huán)境敏感的方式進(jìn)行顯示,還可以將時(shí)間調(diào)整到特定的時(shí)區(qū)。可以從用戶的瀏覽器設(shè)置自動(dòng)確定特定用戶的語(yǔ)言環(huán)境,或者由頁(yè)面作者顯式指定特定用戶的語(yǔ)言環(huán)境。最后,除了提供用于生成和顯示格式化數(shù)據(jù)的操作之外, fmt
庫(kù)還包含了用于解析面向數(shù)字和時(shí)間數(shù)據(jù)的定制標(biāo)記。
![]() ![]() |
![]()
|
- 您可以參閱本文在 developerWorks 全球站點(diǎn)上的 英文原文.
- 下載 Weblog 示例應(yīng)用程序的 源代碼。
- Sun 的 JSP 標(biāo)準(zhǔn)標(biāo)記庫(kù) 產(chǎn)品頁(yè)是學(xué)習(xí)有關(guān) JSTL 的更多內(nèi)容的良好起點(diǎn)。
- JSTL 1.0 規(guī)范是有關(guān) EL 和四個(gè) JSTL 標(biāo)記庫(kù)的最終權(quán)威文本。
- Jakarta Taglibs項(xiàng)目是 JSTL 1.0 參考實(shí)現(xiàn)的起源。
- Shawn Bayern 所著的 JSTL in Action(Manning,2002)精彩地概述了所有的 JSTL 特性,作者是參考實(shí)現(xiàn)的主管。
- 廣受歡迎的 Java 編程作者 David Geary 也撰寫了有關(guān) JSTL 的書籍,書名為 Core JSTL。
- JSPTags.com是 JSP 參考資料的目錄,它尤其著重定制標(biāo)記庫(kù)方面的內(nèi)容。
- Sun 的 Java Web Services Tutorial中概述了 JSTL。
- Mark Davis 和 Helena Shih 在“ The Java International API: Beyond JDK 1.1”( developerWorks,1998 年 10 月)中廣泛地概述了 Java 平臺(tái)的國(guó)際化特性。
- 如果您對(duì)國(guó)際化感興趣,您可能不希望錯(cuò)過(guò) Joe Sam Shirah 的綜合性教程: java國(guó)際化基礎(chǔ)知識(shí) ( developerWorks,2002 年 4 月)。
- ISO 639 規(guī)范定義了有效的語(yǔ)言代碼,而 ISO 3166 規(guī)范定義了有效的國(guó)家或地區(qū)代碼。
- 與此類似, ISO 4217 規(guī)范定義了貨幣代碼。
- “ VisualAge for Java 版本 3.5.3/WebSphere Studio 3.5.2 ― JSP 1.1 開發(fā)”( WebSphere 開發(fā)者園地)是 WBOnline 實(shí)戰(zhàn)篇,它演示了 servlet、JSP 頁(yè)面和定制標(biāo)記庫(kù)的用法。
- 通過(guò) Jeff Wilson 的優(yōu)秀論文“ 使用定制標(biāo)記控制 JSP 頁(yè)面”( developerWorks,2002 年 1 月)全面了解定制標(biāo)記庫(kù)。
- Noel Bergman 的文章“ JSP 標(biāo)記庫(kù):著意設(shè)計(jì)的更好的可用性”( developerWorks,2001 年 12 月)向您說(shuō)明了聲明性標(biāo)記如何有助于提高 JSP 頁(yè)面的可用性。
- 請(qǐng)?jiān)?developerWorksJava 技術(shù)專區(qū) 查找大量的 Java 技術(shù)參考資料。
![]() ![]() |
![]()
|
![]() | ||
![]() | Mark Kolb 是一位在德克薩斯州奧斯汀工作的軟件工程師。他經(jīng)常就服務(wù)器端 Java 平臺(tái)主題在業(yè)界發(fā)表演講,他還與人合著了 Web Development with JavaServer Pages,第二版。可以通過(guò) mak@taglib.com與 Mark 聯(lián)系。 |