了解服務(wù)器端應(yīng)用程序所面臨的獨(dú)特挑戰(zhàn)
![]() |
級(jí)別: 初級(jí) 2005 年 3 月 29 日 為國(guó)際客戶設(shè)計(jì) Java Server Pages(JSP)應(yīng)用程序更像是一門藝術(shù),而不像是科學(xué),但所涉及的內(nèi)容不僅僅能滿足眼球。成功的關(guān)鍵是理解與國(guó)際化有關(guān)的獨(dú)一無二的服務(wù)器端問題。Java 開發(fā)人員 Sing Li 將闡述這個(gè)重要問題,并給出兩個(gè)經(jīng)過考驗(yàn)確實(shí)有效的解決方案。 世界經(jīng)濟(jì)日益全球化推動(dòng)了人們對(duì)基于 Web 的軟件的需求,因?yàn)樵S多國(guó)家的用戶都能訪問 Web 軟件。這些用戶使用的語(yǔ)言、顯示、數(shù)據(jù)錄入、表示和文化需求等都可能存在很大的差異。國(guó)際化(縮寫為 i18n)是一種創(chuàng)建為分散用戶群工作的應(yīng)用程序的藝術(shù)。 也許有點(diǎn)讓人感到驚訝,當(dāng)不作任何定制修改就在服務(wù)器端使用時(shí),J2SE 對(duì)國(guó)際化的內(nèi)建支持會(huì)表現(xiàn)出一些不足。一般來說,服務(wù)器端的國(guó)際化仍然是一門藝術(shù),而不是一項(xiàng)科學(xué),它常常涉及一些專用的或用戶自主開發(fā)的解決方案。 本文把服務(wù)器端基于 JSP 的應(yīng)用程序的國(guó)際化需求與 J2SE 應(yīng)用程序的國(guó)際化需求區(qū)別開來。本文將介紹導(dǎo)致服務(wù)器端需求明顯不同的各種客戶機(jī)/服務(wù)器技術(shù)。然后,還將查看實(shí)際代碼,這些代碼展示了用來解決基本問題的、廣泛采用的兩個(gè)解決方案。 J2SE 用地區(qū)(locale) 的概念(請(qǐng)參閱Notation for a locale)進(jìn)行國(guó)際化。在一臺(tái)機(jī)器上,地區(qū)代表用戶選擇的顯示語(yǔ)言(例如,英語(yǔ)或西班牙語(yǔ)),以及日期、時(shí)間、貨幣等方面的格式化約定。通常,由底層操作系統(tǒng)管理地區(qū)選項(xiàng)設(shè)置,并在運(yùn)行的時(shí)候把它傳遞給 J2SE。 如果運(yùn)行的服務(wù)器在本地機(jī)器上,或者是在局域網(wǎng)上,那么特定于機(jī)器的地區(qū)的概念就很好用。包含的所有客戶機(jī)和服務(wù)器都在同一地區(qū),所以它們都使用相同的顯示語(yǔ)言、日期約定等。這些場(chǎng)景都不會(huì)帶來麻煩的國(guó)際化問題。但是如果想用同一臺(tái)服務(wù)器為多個(gè)國(guó)際位置上的用戶提供服務(wù)的話,那么情況就變得很復(fù)雜。 當(dāng)為了進(jìn)行國(guó)際化訪問而部署服務(wù)器應(yīng)用程序時(shí),該應(yīng)用程序必須同時(shí)為不同的地區(qū)提供支持。圖 1 顯示了一種可能的場(chǎng)景。每臺(tái)機(jī)器 —— 服務(wù)器以及可在任何時(shí)間訪問服務(wù)器的客戶機(jī) —— 都可能有自己的地區(qū)設(shè)置,而這些地區(qū)是不同的。
圖 1. 為不同地區(qū)的用戶提供服務(wù)的服務(wù)器 ![]() 在圖 1 中,服務(wù)器機(jī)器位于 San Francisco,特定于機(jī)器的地區(qū)是 en_US(美國(guó)英語(yǔ))。來自紐約和達(dá)拉斯的用戶都使用 en_US 地區(qū),所以沒有額外的國(guó)際化需求。但是,來自漢城的用戶期望看到用韓語(yǔ)表示的應(yīng)用程序提示,他們的地區(qū)是 ko_KR。同時(shí),來自上海的用戶想看到中文表示的應(yīng)用程序文本,他們的地區(qū)是 zh_CN。來自東京的用戶期望用日語(yǔ)顯示應(yīng)用程序,他們的地區(qū)是 ja_JP。所有這些用戶的需求都必須通過運(yùn)行在 San Francisco 服務(wù)器上的 JSP 應(yīng)用程序來得到滿足。 在服務(wù)器端,您對(duì)于服務(wù)器機(jī)器自己的地區(qū)擁有全部控制權(quán),但您無法改變客戶機(jī)的地區(qū)或強(qiáng)行將它轉(zhuǎn)換成某個(gè)特定地區(qū)。相反,應(yīng)用程序必須識(shí)別出用戶的地區(qū),并保證 JSP 頁(yè)面以正確的本地化形式出現(xiàn)(請(qǐng)參閱 Detecting client locale)。
就在您以為可以安全地判斷客戶機(jī)地區(qū),并據(jù)此呈現(xiàn) JSP 時(shí),新的問題出現(xiàn)了。請(qǐng)考慮以下這些非常現(xiàn)實(shí)的場(chǎng)景。 來自東京的一位訪問人員工正在使用位于中國(guó)上海的銷售辦公室的機(jī)器,機(jī)器的地區(qū)是 zh_CN。因?yàn)椴皇煜嬷形模运胗萌照Z(yǔ)訪問 Web 應(yīng)用程序。關(guān)于這種情況的說明,參見圖 2(a)。 圖 2. 用戶期望的地區(qū)與客戶端機(jī)器上的地區(qū)不同 ![]() 在圖 2(a),San Francisco 服務(wù)器的地區(qū)是 en_US。客戶端機(jī)器在上海,地區(qū)是 zh_CN。但是 JSP 應(yīng)用程序需要用 ja_JP 地區(qū)顯示,對(duì)用戶才有用。 再看另外一個(gè)更加怪異但并非不可能的場(chǎng)景。國(guó)際化 JSP 應(yīng)用程序的開發(fā)人員正在一項(xiàng)調(diào)試。在一個(gè)地區(qū)為 en_US 的客戶端系統(tǒng)上,打開了三個(gè)運(yùn)行 JSP 應(yīng)用程序的瀏覽器實(shí)例。服務(wù)器機(jī)器在局域網(wǎng)上,地區(qū)也是 en_US。但是,現(xiàn)在要為中文和日語(yǔ)用戶測(cè)試應(yīng)用程序的處理能力。所以在一臺(tái) en_US 客戶端機(jī)器上,一個(gè)瀏覽器實(shí)例用的是英文(en_US),一個(gè)用的是日語(yǔ)(ja_JP),還有一個(gè)用的是中文(zh_CN)。圖 2(b)演示了這種情況。 目前為止,基本的國(guó)際化問題應(yīng)當(dāng)很清楚了:在處理顯示國(guó)際化應(yīng)用程序的任意特殊實(shí)例所需的實(shí)際地區(qū)時(shí),客戶機(jī)地區(qū)和服務(wù)器地區(qū)都有些力不從心。只有用戶才能說清要用哪個(gè)地區(qū)顯示頁(yè)面。 但是謝天謝地,通常可以肯定地假設(shè)在使用應(yīng)用程序期間,用戶不會(huì)改變顯示語(yǔ)言。所以通常可以把地區(qū)與會(huì)話關(guān)聯(lián)起來。
對(duì)于 JSP 應(yīng)用程序,至少有兩種處理不同語(yǔ)言的顯示問題的普遍接受方法可以使用:
本文提供了示例代碼的兩個(gè)版本,分別對(duì)應(yīng)上面的兩種方法。示例應(yīng)用程序是一個(gè)叫做 developerWorks Email 的虛構(gòu)的電子郵件服務(wù)的登錄屏幕。首先,會(huì)用語(yǔ)言選擇屏幕提示電子郵件系統(tǒng)的用戶,讓他確定所需的當(dāng)前會(huì)話地區(qū)。可以進(jìn)行的選擇包括英語(yǔ)、韓語(yǔ)、日語(yǔ)和中文,如圖 3 所示。如果想試試代碼的效果,請(qǐng)用 http://<server address>/dwi18n/multdir/index.jsp 這個(gè) URL 訪問該頁(yè)面。
圖 3. 進(jìn)行顯式地區(qū)選擇的語(yǔ)言選擇屏幕 ![]() 在圖 3 中,語(yǔ)言選擇屏幕用 4 個(gè)圖片表示 4 個(gè)地區(qū)選擇(請(qǐng)參閱 Using images for initial language selection)。登錄屏幕使用用戶在這里選擇的語(yǔ)言進(jìn)行顯示。圖 4 顯示了日語(yǔ)的登錄屏幕。 圖 4. 日語(yǔ)登錄屏幕 ![]()
示例的第一個(gè)版本位于示例代碼發(fā)行包的 webapps/dwi18n/multdir/ 目錄中,它運(yùn)用了多組 JSP 頁(yè)面。圖 5 顯示了這個(gè)應(yīng)用程序的目錄結(jié)構(gòu)。 圖 5. dwi18n/multdir 的目錄結(jié)構(gòu)顯示了特定于地區(qū)的目錄 ![]() 在圖 5 中,每個(gè)地區(qū)都有對(duì)應(yīng)的子目錄。與 en_EN 地區(qū)對(duì)應(yīng)的用英文編碼的 JSP 在 en 子目錄中。與 ko_KR 地區(qū)對(duì)應(yīng)的用韓語(yǔ)編碼的 JSP 在 ko 子目錄中。對(duì)于 ja_JP 地區(qū),用日語(yǔ)編碼的 JSP 在 ja 子目錄中。zh_CN 地區(qū)則用 zh 子目錄中用中文編碼的 JSP 表示。每個(gè)子目錄都既包含登錄屏幕的 JSP(login.jsp),也包含數(shù)據(jù)確認(rèn) JSP(confirm.jsp)。 數(shù)據(jù)確認(rèn) JSP 只顯示在這個(gè)簡(jiǎn)單的示例中輸入的數(shù)據(jù)。例如,如果在中文登錄屏幕中輸入了信息,然后單擊按鈕,那么數(shù)據(jù)確認(rèn) JSP 就會(huì)顯示輸入的數(shù)據(jù),如圖 6 所示。 圖 6. 中文的確認(rèn)頁(yè)面 ![]() 地區(qū)選擇 JSP 叫做 index.jsp,它直接鏈接到特定于語(yǔ)言的一組 JSP。這個(gè)版本的 index.jsp 的代碼在清單 1 中: 清單 1. 地區(qū)選擇 JSP 直接鏈接到特定于語(yǔ)言的頁(yè)面
注意,清單 1 中使用了來自 JSP 標(biāo)準(zhǔn)標(biāo)簽庫(kù)(JSTL)的 每組 login.jsp 和 confirm.jsp 都用特定于地區(qū)的語(yǔ)言編寫代碼。清單 2 顯示了 ja_JP 地區(qū)的 login.jsp(與 圖 4 對(duì)應(yīng)): 清單 2. ja_JP 地區(qū)的登錄頁(yè)面(login.jsp)
與此類似,對(duì)于 zh_CN 地區(qū),confirm.jsp(與 圖 6 對(duì)應(yīng))是用中文編碼的,如清單 3 所示: 清單 3. zh_CN 地區(qū)的數(shù)據(jù)確認(rèn)頁(yè)面(confirm.jsp)
前面介紹的多冗余集(multiple-redundant-set)方法對(duì)于以下這類應(yīng)用程序是一種可行的解決方案:
前面一節(jié) Using multiple redundant sets of language-specific JSPs 中的解決方案的最大不足在于:當(dāng)需要更新特定于語(yǔ)言的 JSP 集時(shí),所有冗余編碼的 JSP 集都必須同時(shí)更新。對(duì)于一個(gè)中等規(guī)模的項(xiàng)目而言,這會(huì)造成冗長(zhǎng)的、容易出錯(cuò)的更新。 而現(xiàn)在要介紹的解決方案的外觀和作用都與前一個(gè)類似,但是在這個(gè)案例中,只有一套 login.jsp 和 confirm.jsp。這個(gè)解決方案利用了 J2SE 在資源綁定中對(duì)地區(qū)的支持,只在需要的時(shí)候才采用特定于地區(qū)的文本字符串(請(qǐng)參閱參考資料,以了解更多關(guān)于 J2SE 資源綁定的信息)。這個(gè)解決方案的示例代碼位于 webapps\dwi18n\javares 目錄中。如果部署了示例代碼,那么請(qǐng)使用 http://<server address>/dwi18n/javares/index.jsp 這個(gè) URL。 圖 7 顯示了運(yùn)行在同一臺(tái)客戶端機(jī)器上的 4 個(gè)瀏覽器會(huì)話,每個(gè)會(huì)話請(qǐng)求的都是不同的地區(qū)。 圖 7. 同一臺(tái)機(jī)器上的 4 個(gè)不同地區(qū) ![]() 在圖 7 中,可以清楚地看到國(guó)際化的 JSP 應(yīng)用程序可以同時(shí)處理多個(gè)地區(qū)。 在這個(gè)案例中,index.jsp 略有不同,因?yàn)樗F(xiàn)在鏈接到單獨(dú)的 login.jsp。清單 4 顯示了這個(gè)版本的 index.jsp 的代碼: 清單 4. 鏈接到單獨(dú) login.jsp 的地區(qū)選擇頁(yè)面
注意,在清單 4 中,使用 JSTL 的 清單 5. 使用 J2SE 資源綁定的登錄頁(yè)面(login.jsp)
清單 5 使用了 JSTL 國(guó)際化輔助標(biāo)簽庫(kù)(請(qǐng)參閱 參考資料)。如果傳入的 完成地區(qū)設(shè)置之后,
作為示例,清單 6 顯示了 清單 6. 資源綁定中的 app_ko.properties 文件
注意,在清單 6 中,所有的 Unicode 字符均被轉(zhuǎn)義。必須這么做,因?yàn)?Java 的資源綁定機(jī)制只接受用 ASCII 編碼的屬性文件。要?jiǎng)?chuàng)建這個(gè)文件,既可以使用 IDE 中的字符串資源編輯器,也可以使用 Unicode 編輯器創(chuàng)建一個(gè) Unicode 文件,然后用 JDK 的
在設(shè)置國(guó)際化 JSP 應(yīng)用程序時(shí),需要了解它的獨(dú)特需求。應(yīng)用程序必須做好準(zhǔn)備,支持具有不同地區(qū)需求的用戶的多個(gè)并發(fā)訪問。本文介紹了用特定于地區(qū)的語(yǔ)言文本顯示國(guó)際化應(yīng)用程序這個(gè)問題的兩個(gè)解決方案。但我也僅僅是觸及到創(chuàng)建國(guó)際化服務(wù)器端應(yīng)用程序的迷人藝術(shù)的表面。其他重要的問題包括處理不同的日期和貨幣格式、管理 GUI 布局和使用專門的輸入法編輯器(IME,輸入外國(guó)字符的實(shí)用軟件)。請(qǐng)參閱參考資料,以獲得有助于進(jìn)一步了解國(guó)際化的信息。
|
用struts框架嘗試國(guó)際化程序?qū)崿F(xiàn)
|
struts是一個(gè)MVC框架,據(jù)說struts可以輕松實(shí)現(xiàn)國(guó)際化;于是根據(jù)網(wǎng)上的資料,做了一個(gè)嘗試,因?yàn)榈谝淮巫龆嗾Z(yǔ)言程序,還是拐了很多彎路;但所幸,經(jīng)過不斷的嘗試,終于成功的實(shí)現(xiàn)多語(yǔ)言版本的簡(jiǎn)單頁(yè)面; 因?yàn)槌绦蚍浅:?jiǎn)單,所以在整個(gè)嘗試過程中,全部使用手工編碼,沒有使用任何輔助工具; 1、 建立服務(wù)器 我使用Tomcat4作為測(cè)試環(huán)境,建立過程(略); 2、 下載struts 可以到http://jakarta.apache.org/struts/index.html下載,下載后解壓,把其中的.war文件拷貝到Tomcat的webapps目錄下,啟動(dòng)Tomcat,如果http://localhost:8080/struts-example/ 運(yùn)行沒有問題,說明環(huán)境建立成功;這些.war文件在Tomcat啟動(dòng)后會(huì)自動(dòng)展開成文件,里面有源代碼,可以作為源碼研究; 3、 建立工程 在webapps目錄下建立一個(gè)international文件夾,再在international目錄下建立WEB-INF文件夾和WEB-INF/classes文件夾,這些都是一個(gè)JSP工程必須的; 4、 加了struts的類 在WEB-INF目錄下建立一個(gè)lib子目錄,把struts-example\WEB-INF\lib目錄下將所有.jar文件拷貝到該目錄下;這些文件是struts的控制類庫(kù)和標(biāo)簽類庫(kù)等;
5、 加入struts標(biāo)簽定義文件 從struts-example\WEB-INF目錄下,把.TLD文件拷貝到international的WEB-INF目錄下,這些文件標(biāo)簽庫(kù)的定義文件;
6、 建立struts的config文件 建立struts的config文件的struts-config.xml,內(nèi)容如下:
message-resources標(biāo)簽是指message資源的文件,就是我們存放我們的多種語(yǔ)言的提示信息的文件,resources.application表是classes目錄下的resources目錄用來存放資源文件,默認(rèn)語(yǔ)言文件名為application.properties,中文為application_zh_CN.properties,其他語(yǔ)言類似; 7、 建立web.xml文件
上面的web.xml定義了struts的控制類、config文件和標(biāo)簽,因?yàn)楸容^簡(jiǎn)單,所以不做解釋; 8、 建立資源文件 在classes目錄下,建立一個(gè)resources目錄,用來存放資源文件; 先建立默認(rèn)的資源文件application.properties和英文(美國(guó))的資源文件application_en_US.properties,內(nèi)容為:
先建立這兩個(gè)文件,中文的等下一步建立 9、建立jsp文件 在international目錄下,建立index.jsp文件,內(nèi)容為:
在這里 啟動(dòng)Tomcat,在瀏覽器里輸入http://localhost:8080/international/,查看效果,如果瀏覽器標(biāo)題顯示international application test,頁(yè)面里顯示This is a international application test則說明你的程序成功了;下面只要增加資源文件,你就可以在多種語(yǔ)言的系統(tǒng)里看了; 10、 建立簡(jiǎn)體中文的資源文件 在resources目錄下建立一個(gè)application_cn.properties,輸入內(nèi)容:
因?yàn)閖ava的國(guó)際化是通過unicode碼來實(shí)現(xiàn),所以要把代碼轉(zhuǎn)為unicode碼;在Dos下,轉(zhuǎn)到resources目錄,執(zhí)行:
轉(zhuǎn)換后的application_zh_CN.properties文件內(nèi)容為:
這就是上面的中文的unicode碼; 重新啟動(dòng)Tomcat, 在瀏覽器里輸入http://localhost:8080/international/,你看,標(biāo)題和內(nèi)容是不是變成中文了; 11、 建立繁體中文的資源文件 在resources目錄下建立一個(gè)application_tw.properties,輸入內(nèi)容:
因?yàn)閖ava的國(guó)際化是通過unicode碼來實(shí)現(xiàn),所以要把代碼轉(zhuǎn)為unicode碼;在Dos下,轉(zhuǎn)到resources目錄,執(zhí)行:
轉(zhuǎn)換后的application_zh_TW.properties文件內(nèi)容為:
這就是上面的繁體中文的unicode碼; 12、 測(cè)試多語(yǔ)言 打開IE的“工具”->“Internet選項(xiàng)”菜單,“常規(guī)”選項(xiàng)卡,點(diǎn)擊其中的“語(yǔ)言”按鈕,添加“英語(yǔ)(美國(guó))-[en-us]”語(yǔ)言,將其他的語(yǔ)言刪除,重新啟動(dòng)IE后,輸入http://localhost:8080/international/index.jsp,你會(huì)發(fā)現(xiàn)內(nèi)容已經(jīng)變成英文; 用同樣的方法,可以測(cè)試簡(jiǎn)體中文和繁體中文。 |
function Calculator() {} |
var myCalculator = new Calculator(); |
Calculator.prototype._prop = 0; |
function Calculator() {}; with (Calculator) { prototype._prop = 0; prototype.setProp = function(p) {_prop = p}; prototype.getProp = function() {return _prop}; } |
Calculator.iCount=0; |
function Calculator() {Calculator.iCount++;}; |
function Calculator() { var _prop = 0; this.setProp = function (p){_prop = p}; this.getProp = function() {return _prop}; }; |
function ArithmeticCalculator() { }; with (ArithmeticCalculator) { ArithmeticCalculator .prototype = new Calculator();//第一行 prototype.constructor = ArithmeticCalculator;//第二行 } |
var c = new ArithmeticCalculator; |
function Calculator(ops) { ...}; with (Calculator) { prototype.Calculator=Calculator;} |
function ArithmeticCalculator(ops) { this.Calculator(ops);}; with (ArithmeticCalculator) { ArithmeticCalculator .prototype = new Calculator; prototype.constructor = ArithmeticCalculator; prototype.ArithmeticCalculator = ArithmeticCalculator; } |
var e = new ArithmeticCalcuator([2,2,5,"add","mul"]); alert(e.evaluate()); |
<checkbox id="cbx_1" value="N" labelonleft="true" label="Show Details:" onValue="Y" offValue="N"/> |
<PUBLIC:COMPONENT NAME="cbx" tagName="CHECKBOX"> <PROPERTY NAME="value" GET="getValue" PUT="putValue" /> //我們把組件的所有另外的屬性放在這里 <METHOD NAME="show" /> //我們把組件的所有另外的方法放在這里 <EVENT NAME="onItemChanging" ID="onItemChanging"/> //我們把組件將向應(yīng)用程序激活的所有另外的事件放在這里 <ATTACH EVENT="oncontentready" HANDLER="constructor" /> //我們把組件自己處理的另外的事件放在這里 <SCRIPT> //我們把所有的方法,屬性getters和setters和事件處理器放在這里 </SCRIPT> </PUBLIC:COMPONENT> |
<HTML xmlns:myns> <?IMPORT namespace="myns" implementation="checkbox.htc" > <BODY> <myns:checkbox id='cbx_1' label='Hello'/> </BODY> </HTML> |
<ATTACH EVENT="oncontentready" HANDLER="constructor" /> |
function constructor() { //我們將把一個(gè)HTML復(fù)選框和標(biāo)簽添加到元素體 //詳細(xì)情形見列表2 } |
<PROPERTY NAME="labelonleft" VALUE="true"/> |
<PROPERTY NAME="onValue" VALUE="true"/> <PROPERTY NAME="offValue" VALUE="false" /> |
<PROPERTY NAME="checked" GET="getChecked" PUT="putChecked" /> |
var _value; function putChecked( newValue ) { value = (newValue?onValue:offValue); } function getChecked(){ return ( _value == onValue); } |
cbx_1::onItemChanging() { . . . . . if (canNotBeAllowed) { event.returnValue=false; . . . . . } |
<LABEL for=cb_{uniqueID}>Show Details:</LABEL> <INPUT id=cb_{uniqueID} type=checkbox /> |
<PUBLIC:DEFAULTS viewLinkContent/> |
eval( 'cb_'+uniqueID).checked = ( _value == onValue ); |
cb.checked = ( _value == onValue ); |
Zip:<input id="zipcode" type="text" maxlength="5" onKeyUp="zipChanged()" style="width:60"/> City: <input id="city" disabled maxlength="32" style="width:160"/> State:<input id="state" disabled maxlength="2" style="width:30"/> <script src="xmlhttp.js"></script> <script> var zipField = null; function zipChanged(){ zipField = document.getElementById("zipcode") var zip = zipField.value; zip.length == 3?updateState(zip):zip.length == 5?updateCity(zip):""; } function updateState(zip) { var stateField = document.getElementById("state"); ask("resolveZip.jsp?lookupType=state&zip="+zip, stateField, zipField); } function updateCity(zip) { var cityField = document.getElementById("city"); ask("resolveZip.jsp? lookupType=city&zip="+zip, cityField, zipField); } </script> |
HTTPRequest = function () { var xmlhttp=null; try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (_e) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (_E) { } } if (!xmlhttp && typeof XMLHttpRequest != 'undefined') { try { xmlhttp = new XMLHttpRequest(); } catch (e) { xmlhttp = false; } } return xmlhttp; } function ask(url, fieldToFill, lookupField) { var http = new HTTPRequest(); http.open("GET", url, true); http.onreadystatechange = function (){ handleHttpResponse(http, fieldToFill,lookupField)}; http.send(null); } function handleHttpResponse(http, fieldToFill, lookupField) { if (http.readyState == 4) { result = http.responseText; if ( -1 != result.search("null") ) { lookupField.style.borderColor = "red"; fieldToFill.value = ""; } else { lookupField.style.borderColor = ""; fieldToFill.value = result; } } } |
Zip:<input id="zipcode" type="text" maxlength="5" onKeyUp="zipChanged()" style="width:60" size="20"/> City: <input id="city" disabled maxlength="32" style="width:160" size="20"/> State:<input id="state" disabled maxlength="2" style="width:30" size="20"/> <iframe id="controller" style="visibility:hidden;width:0;height:0"></iframe> |
function ask(url, fieldToFill, lookupField){ var controller = document.getElementById("controller"); controller.src= url+"&field="+fieldToFill.id+"&zip="+lookupField.id; } |
![]() 圖1.HelloSession EJB的接口。 |
![]() 圖2.所有的Web層的servlet都使用該User POJO。 |
drop table if exists TABLE_USER_FILE; create table TABLE_USER_FILE ( USER_ID int auto_increment not null, USER_USERNAME text, USER_FILENAME text, USER_FILETYPE text, USER_FILESIZE text, USER_FILEBIN longblob, primary key (USER_ID) ) type = MyISAM; |
... <form-beans> <form-bean name="uploadFileForm" type="org.apache.struts.action.DynaActionForm" dynamic="true"> <form-property name="myFile" type="org.apache.struts.upload.FormFile"/> <form-property name="myName" type="java.lang.String"/> </form-bean> </form-beans> ... <action-mappings> <action path="/UploadFile" type="com.prokhorenko.web.UploadFileAction" name="uploadFileForm"> ... |
... User per = new User(); DynaActionForm df = (DynaActionForm) form; FormFile myFile = (FormFile) df.get("myFile"); ... per.setFilebin ( Hibernate.createBlob (myFile.getInputStream()) ); ... |
... User per = bd.getUser( new Long((String)request.getParameter("id")) ); ... |
... ServletOutputStream outStream = response.getOutputStream(); InputStream in = per.getFilebin().getBinaryStream(); byte[] buffer = new byte[32768]; int n = 0; while ( ( n = in.read(buffer)) != -1) { outStream.write(buffer, 0, n); } in.close(); outStream.flush(); ... |