鳳凰涅磐,浴火重生!

          超越他人的期望,才能讓人感動(dòng)!

          DOJO + JSON

          曾幾何時(shí)ajax已經(jīng)遍布大江南北,然而單純的js難于閱讀和debug,dojo的出現(xiàn),無(wú)疑部分地解決了這個(gè)問(wèn)題,加上ide的支持,更是如虎添翼了!引用一篇IBM的文章,看看dojo的應(yīng)用吧。

          以下是引用內(nèi)容:

          使用 Dojo 工具包和 JSON-RPC 構(gòu)建企業(yè) SOA Ajax 客戶端

          developerWorks
          文檔選項(xiàng)
          將此頁(yè)作為電子郵件發(fā)送

          將此頁(yè)作為電子郵件發(fā)送

          樣例代碼


          拓展 Tomcat 應(yīng)用

          下載 IBM 開(kāi)源 J2EE 應(yīng)用服務(wù)器 WAS CE 新版本 V1.1


          級(jí)別: 中級(jí)

          Roland Barcia (barcia@us.ibm.com), IT 咨詢專家, IBM WebSphere 軟件服務(wù)部

          2006 年 8 月 21 日

          了解如何使用 Dojo 工具包為 Java? Platform Extended Edition (Java EE) 應(yīng)用程序構(gòu)建企業(yè) SOA 客戶端,以及如何使用 JavaScript Object Notation–RPC (JSON-RPC) 來(lái)調(diào)用服務(wù)器端 Java 對(duì)象。

          引言

          異步 JavaScript 和 XML (Ajax) 是使用本機(jī)瀏覽器技術(shù)構(gòu)建富 Web 應(yīng)用程序的新方法。對(duì)于編寫(xiě)需要某些類型的“活動(dòng)”用戶界面的復(fù)雜應(yīng)用程序的開(kāi)發(fā)人員,JavaScript 在這方面已經(jīng)做得很好。不過(guò),JavaScript 難于編碼、調(diào)試、移植和維護(hù)。使用 Ajax 工具包有助于最大程度地減少使用 JavaScript 和 Ajax 帶來(lái)的許多常見(jiàn)問(wèn)題。優(yōu)秀的 Ajax 工具包提供了一組可重用的小部件、用于擴(kuò)展和創(chuàng)建小部件的框架、事件系統(tǒng)、JavaScript 實(shí)用工具和增強(qiáng)的異步服務(wù)器調(diào)用支持。在本文中,我們將討論如何使用 Dojo 工具包為 Java EE 應(yīng)用程序構(gòu)建企業(yè) SOA 客戶端。我們還將使用 JSON (JavaScript Object Notation)–RPC 來(lái)調(diào)用服務(wù)器端 Java 對(duì)象。

          在本文中,我們還將向您提供以下內(nèi)容的簡(jiǎn)要說(shuō)明:Ajax、Dojo、JSON 和 JSON-RPC,以及一些設(shè)計(jì) Ajax 應(yīng)用程序的設(shè)計(jì)原則和您可以下載并親自嘗試運(yùn)行的簡(jiǎn)短示例。





          回頁(yè)首


          Ajax 概述

          有許多關(guān)于 Ajax 的論文、文章和書(shū)籍。我不打算對(duì) Ajax 進(jìn)行深入介紹。有關(guān)詳細(xì)信息,請(qǐng)查閱參考資料

          Ajax 可作為使用本機(jī)瀏覽器組件構(gòu)建網(wǎng)站的體系結(jié)構(gòu)樣式。Ajax 的關(guān)鍵部分有:

          • JavaScript,它可以編排頁(yè)面元素,從而獲得最佳 Ajax 用戶體驗(yàn)。
          • Cascading Style Sheets (CSS),它可以定義頁(yè)面元素的可視樣式。
          • 文檔對(duì)象模型(Document Object Model,DOM),它將網(wǎng)頁(yè)結(jié)構(gòu)作為一組可以使用 JavaScript 操作的可編程對(duì)象提供。
          • XMLHttpRequest,它支持以后臺(tái)活動(dòng)的形式從 Web 資源檢索數(shù)據(jù)。

          XMLHttpRequest 對(duì)象是關(guān)鍵部分。

          XMLHttpRequest 對(duì)象

          XMLHttpRequest 對(duì)象是 Ajax 用于進(jìn)行異步請(qǐng)求的機(jī)制。圖 1 說(shuō)明了該流程:


          圖 1. XMLHttpRequest 對(duì)象進(jìn)行異步請(qǐng)求的流程圖
          XMLHttpRequest 對(duì)象進(jìn)行異步請(qǐng)求的流程圖。

          XMLHttpRequest 對(duì)象是瀏覽器中提供的 JavaScript 對(duì)象。(Microsoft? 和 Mozilla 瀏覽器各有自已的版本)。該流程如下所示:

          1. 頁(yè)面調(diào)用某個(gè) JavaScript。
          2. JavaScript 函數(shù)創(chuàng)建 XMLHttpRequest 對(duì)象。這包括設(shè)置要調(diào)用的 URL 和 HTTP 請(qǐng)求參數(shù)。
          3. JavaScript 函數(shù)注冊(cè)回調(diào)處理程序。HTTP 響應(yīng)調(diào)用此回調(diào)處理程序。
          4. JavaScript 函數(shù)調(diào)用 XMLHttpRequest 對(duì)象上的 send 方法,該方法接著將 HTTP 請(qǐng)求發(fā)送到服務(wù)器。
          5. XMLHttpRequest 對(duì)象立即將控制返回到 JavaScript 方法。此時(shí),用戶可以繼續(xù)使用該頁(yè)面。
          6. 稍后,HTTP 服務(wù)器通過(guò)調(diào)用回調(diào)處理程序返回 HTTP 響應(yīng)。
          7. 回調(diào)處理程序可以訪問(wèn) HTML DOM 對(duì)象。它可以動(dòng)態(tài)更新頁(yè)面元素,而無(wú)需中斷用戶(除非您碰巧更新用戶正在使用的 DOM 對(duì)象)。

          通過(guò)異步更新頁(yè)面的 DOM,還可以在本地進(jìn)行異步請(qǐng)求。





          回頁(yè)首


          Dojo 工具包概述

          Dojo 使您能夠方便地構(gòu)建動(dòng)態(tài)站點(diǎn)。它提供一個(gè)豐富的小部件庫(kù),您可以使用它組成頁(yè)面。您可以使用基于 Dojo 方面的事件系統(tǒng)將事件附加到組件,以創(chuàng)建豐富的交互體驗(yàn)。此外,您可以使用幾個(gè) Dojo 庫(kù)進(jìn)行異步服務(wù)器請(qǐng)求、添加動(dòng)畫(huà)效果和瀏覽存儲(chǔ)實(shí)用工具等等。

          Dojo 小部件

          Dojo 提供了您可以用于構(gòu)建頁(yè)面的一組豐富的小部件。您可以使用多個(gè)方法創(chuàng)建 Dojo 小部件。Dojo 的眾多優(yōu)點(diǎn)之一是它允許您使用標(biāo)準(zhǔn)的 HTML 標(biāo)記。然后,可以將這些標(biāo)記用于小部件。這樣,HTML 開(kāi)發(fā)人員就可以方便地使用 Dojo,如清單 1 所示:


          清單 1. 在 HTML 標(biāo)記中使用 Dojo
          <div dojoType="FloatingPane" class="stockPane" title="Stock Form" id="pane" 
                                           constrainToContainer="true" displayMaximizeAction="true">
                 <h2>Stock Service</h2>
                 Enter symbol: <input dojoType="ValidationTextBox" required="true"
                                                    id="stockInput">
                 <p />
                 <button dojoType="Button2" widgetId="stockButton">
                         Get Stock Data
                 </button>
                 <div id="resultArea" />
          </div>
          

          您可以使用 div 標(biāo)記來(lái)定義小部件的位置,而在頁(yè)面加載或?qū)κ录M(jìn)行響應(yīng)時(shí) Dojo 可以在這些地方放置小部件。您還可以使用更具體的標(biāo)記,如 <dojo:widget>,并向其中添加 Dojo 小部件屬性。在清單 1 中,我們將 dojoType 屬性添加到 button 標(biāo)記。在設(shè)置了標(biāo)記之后,您需要在一些 JavaScript 內(nèi)部加載小部件,如清單 2 所示。您可以將標(biāo)記嵌入到頁(yè)面內(nèi)部,但是我們建議將其放置在單獨(dú)的 JS 文件中。在本文的稍后部分中,我們將闡明一些 MVC 設(shè)計(jì)原則。


          清單 2. 在 HTML 標(biāo)記中使用 Dojo
          //require statements
          dojo.require("dojo.widget.*" );
          dojo.require("dojo.event.*");
          dojo.require("dojo.widget.Button2");
          dojo.require("dojo.widget.FloatingPane" );
          
          //all dojo.require above this line
          dojo.hostenv.writeIncludes(); 
          dojo.require();	
          	

          您可以在 JavaScript 中創(chuàng)建、訪問(wèn)、修改和刪除小部件,從而實(shí)現(xiàn)動(dòng)態(tài)行為。在我們的示例中,您將看到在 JavaScript 中訪問(wèn)小部件的示例。

          Dojo 事件系統(tǒng)

          Dojo 事件系統(tǒng)使用面向方面的技術(shù)將事件附加到小部件。這可以將小部件與實(shí)際的事件處理分離。Dojo 不是將硬代碼 JavaScript 事件添加到 html 標(biāo)記上,而是提供允許您將事件附加到小部件的 API,如清單 3 所示。


          清單 3. 使用 Dojo 將事件處理程序附加到小部件
          function submitStock()
          	{
          		...
          	}
          function init()
          	{
          		var stockButton = dojo.widget.byId('stockButton');
          		dojo.event.connect(stockButton, 'onClick', 'submitStock');
          	}
          dojo.addOnLoad(init);
          	

          通過(guò)使用 connect 方法,您可將 JavaScript 方法連接到小部件。您還可以在 div 節(jié)點(diǎn)上附加 dojoAttachEvent,如下所示。某些 HTML 標(biāo)記沒(méi)有定義事件,所以這是一個(gè)方便的擴(kuò)展。


          清單 4. 使用 Dojo 將事件附加到 HTML 標(biāo)記
          <div dojoAttachPoint="divNode"
              dojoAttachEvent="onClick; onMouseOver: onFoo;">
          	

          Dojo 事件系統(tǒng)還允許多個(gè)高級(jí)功能,如:

          • 聲明在現(xiàn)有的事件處理程序之前或之后插入事件處理程序的建議。
          • 允許小部件在瀏覽器中訂閱或發(fā)布主題。
          • 添加事件回調(diào)。
          • 可用于表示事件的 event 規(guī)范化對(duì)象。

          有關(guān)詳細(xì)信息,請(qǐng)參見(jiàn) http://dojo.jot.com/EventExamples

          Dojo 異步服務(wù)器請(qǐng)求

          Dojo 通過(guò)抽象特定于瀏覽器的詳細(xì)信息,提供了對(duì)服務(wù)器進(jìn)行異步請(qǐng)求的簡(jiǎn)單方法。Dojo 允許您創(chuàng)建數(shù)據(jù)結(jié)構(gòu)來(lái)隱藏詳細(xì)信息,如清單 5 所示。


          清單 5. 使用 Dojo 進(jìn)行異步請(qǐng)求
          var bindArgs = {
              url:        "/DojoJ2EE/MyURI",
              mimetype:   "text/javascript",
              error:      function(type, errObj){
                  // handle error here 
              },
              load:      function(type, data, evt){
                  // handle successful response here
              }
          };
          // dispatch the request
          var requestObj = dojo.io.bind(bindArgs);
          	

          此外,Dojo 使用 JSON-RPC 標(biāo)準(zhǔn)支持 RPC。在接下來(lái)的部分中,我們將看一看 Dojo 對(duì) JSON 的支持。

          附加的 Dojo 功能

          Dojo 是一個(gè)具有許多功能的豐富庫(kù),包括:

          • 處理 html、字符串、樣式、dom、正則表達(dá)式和若干其他實(shí)用工具的通用庫(kù)。
          • 包括字典、ArraryLists、隊(duì)列、SortedList、設(shè)置和堆棧的數(shù)據(jù)結(jié)構(gòu)。
          • 用于添加動(dòng)畫(huà)效果、驗(yàn)證、拖放和若干其他功能的可視化 Web 實(shí)用工具。
          • 數(shù)學(xué)和加密庫(kù)。
          • 存儲(chǔ)組件。
          • XML 解析

          有關(guān)詳細(xì)信息,請(qǐng)參見(jiàn) http://manual.dojotoolkit.org/index.html





          回頁(yè)首


          JSON 概述

          JSON 是 JavaScript 的對(duì)象文字符號(hào)的子集,它是在 JavaScript 中表示數(shù)據(jù)結(jié)構(gòu)的常用方法。JSON 是一種完全與語(yǔ)言無(wú)關(guān)的文本格式,但使用編程人員熟悉的與 C 語(yǔ)言家族(包括 C、C++、C#、Java、JavaScript、Perl、Python 和許多其他語(yǔ)言)類似的約定。這些屬性使 JSON 成為 Ajax 客戶端的理想數(shù)據(jù)交換語(yǔ)言。

          JSON 構(gòu)建在兩種結(jié)構(gòu)的基礎(chǔ)上:

          1. 名稱/值對(duì)的集合。在不同的語(yǔ)言中,它被實(shí)現(xiàn)為對(duì)象、記錄、結(jié)構(gòu)、字典、哈希表、有鍵列表或者關(guān)聯(lián)數(shù)組。
          2. 值的有序列表。在大多數(shù)語(yǔ)言中,它被實(shí)現(xiàn)為數(shù)組、向量、列表或序列。

          JSON 對(duì)象的示例如下:

          var myJSONObject = {"id": 4, "name": "Roland Barcia", "pets": ["dog","cat","fish"]};
          	

          在示例中,我們對(duì)值對(duì)進(jìn)行了命名。括號(hào)中的任何內(nèi)容都是一個(gè)列表。在不同的編程語(yǔ)言中都有一組豐富的實(shí)現(xiàn)。有關(guān)詳細(xì)信息,請(qǐng)參見(jiàn) http://json.org/

          JSON-RPC

          JSON-RPC 是一種輕量級(jí)遠(yuǎn)程過(guò)程調(diào)用協(xié)議,在此協(xié)議中,JSON 可以連續(xù)請(qǐng)求和響應(yīng)。向遠(yuǎn)程服務(wù)發(fā)送請(qǐng)求可以調(diào)用遠(yuǎn)程方法。該請(qǐng)求是具有三個(gè)屬性的單個(gè)對(duì)象:

          • method - 包含要調(diào)用的方法名稱的字符串。
          • params - 作為參數(shù)傳遞到方法的對(duì)象數(shù)組。
          • id - 請(qǐng)求 ID。它可以屬于任何類型。它用于將響應(yīng)與其應(yīng)答的請(qǐng)求相匹配。

          當(dāng)方法調(diào)用完成時(shí),服務(wù)必須對(duì)響應(yīng)進(jìn)行應(yīng)答。此響應(yīng)是具有三個(gè)屬性的單個(gè)對(duì)象:

          • result - 被調(diào)用方法返回的對(duì)象。它必須為 null,以避免在調(diào)用該方法時(shí)發(fā)生錯(cuò)誤。
          • error - error 對(duì)象(如果在調(diào)用方法時(shí)發(fā)生錯(cuò)誤)。它必須為 null(如果不存在任何錯(cuò)誤)。
          • id - 它必須是與響應(yīng)的請(qǐng)求相同的 ID。

          通知是沒(méi)有響應(yīng)的特殊請(qǐng)求。它與帶有一個(gè)異常的請(qǐng)求對(duì)象具有相同的屬性:

          • id - 必須為 null

          JSON 與 XML

          XML 是一種用于面向服務(wù)的體系結(jié)構(gòu) (SOA) 和數(shù)據(jù)傳輸?shù)某R?jiàn)傳輸。當(dāng)然,目前許多服務(wù)以 SOAP 格式存在。不過(guò),何時(shí)將其用于數(shù)據(jù)傳輸在 Ajax 社區(qū)中存在分岐。JSON 有以下幾個(gè)優(yōu)點(diǎn):

          • 瀏覽器解析 JSON 的速度比 XML 快。
          • JSON 構(gòu)造是友好的編程語(yǔ)言,并容易轉(zhuǎn)換為后端編程語(yǔ)言(如 Java)。
          • JSON 相當(dāng)穩(wěn)定。JSON 的附加內(nèi)容將成為超集。

          XML 有以下優(yōu)點(diǎn):

          • 調(diào)用將 XML 用作傳輸?shù)默F(xiàn)有服務(wù)。
          • 使用 XSLT 可以動(dòng)態(tài)轉(zhuǎn)換 XML。這是企業(yè)服務(wù)總線 (ESB) 方案中的理想功能。

          用于 Dojo 的 JSON-RPC

          Dojo 為調(diào)用 JSON-RPC 請(qǐng)求提供了抽象層。用于 Dojo 的 JSON-RPC 引入了標(biāo)準(zhǔn)方法描述(Standard Method Description,SMD)的概念。SMD 文件是 JSON-RPC 服務(wù)的描述。它允許您以中立方式描述 JSON 調(diào)用。清單 6 提供了此類 JSON 調(diào)用的示例:


          清單 6. Dojo 中的 SON 調(diào)用
          {"SMDVersion":".1",
           "objectName":"StockService",
           "serviceType":"JSON-RPC",
           "serviceURL":"/DojoJ2EE/JSON-RPC",
           "methods":[
          		{"name":"getStockData",
          		"parameters":[
          			{"name":"symbol",
          			"type":"STRING"}
          		 ]
              }
            ]
           }
          	

          您可以使用 Dojo API 調(diào)用服務(wù):

          var StockService = new dojo.rpc.JsonService("/path/to/StockService.smd"); StockService.getStockData("IBM",stockResultCallback);

          這將通過(guò)網(wǎng)絡(luò)發(fā)送此結(jié)構(gòu):

          {"id": 2, "method": "getStockData", "params": ["IBM"]}

          JSON-RPC Java ORB

          JSON-RPC 為遠(yuǎn)程過(guò)程調(diào)用定義標(biāo)準(zhǔn)格式,但是不存在對(duì)后端技術(shù)的標(biāo)準(zhǔn)映射。JSON-RPC Java Orb 提供了這樣一種機(jī)制:注冊(cè) Java 對(duì)象,并將它們公開(kāi)為 JSON-PRC 服務(wù)。它還在 JavaScript 中提供客戶端 API,以調(diào)用服務(wù)。

          如果您選擇使用 Dojo,則可以編寫(xiě)自已的綁定代碼。用于 Java 的 JSON API 可以提供幫助。有關(guān)詳細(xì)信息,請(qǐng)參見(jiàn) (http://developer.berlios.de/projects/jsontools/)。在我們的示例中,我們將使用 JSON-RPC Java ORB 進(jìn)行異步請(qǐng)求,以利用服務(wù)器端綁定代碼。

          JSON-RPC Java Orb 允許您在一種 Servlet 范圍(請(qǐng)求、會(huì)話、應(yīng)用程序)內(nèi)注冊(cè) Java 對(duì)象。然后,它可以使用 JSON-RPC 請(qǐng)求來(lái)調(diào)用 Java 對(duì)象。為此,可以將對(duì)象類型放在 JSON 對(duì)象之前。由于 Dojo API 不執(zhí)行此操作,所以用于 JSON-RPC 的 Dojo 客戶端 API 與用于 Java 的 JSON-RPC 不兼容。

          清單 7 提供了如何向 HttpSession 注冊(cè) Java 對(duì)象的示例:


          清單 7. 注冊(cè) Java 對(duì)象的 HttpSession
          HttpSession session = sessionEvent.getSession();
          JSONRPCBridge json_bridge = null;
          json_bridge = (JSONRPCBridge) session.getAttribute("JSONRPCBridge");
          if(json_bridge == null) {
          		json_bridge = new JSONRPCBridge();
          		session.setAttribute("JSONRPCBridge", json_bridge);
          }
          json_bridge.registerObject
          ("StockService",StockServiceImpl.getStockService());

          您可以在 Servlet 或 HttpListener 中執(zhí)行此操作。然后將 JavaScript 客戶端寫(xiě)入到 Java 服務(wù),如清單 8 所示。


          清單 8. 連接 Java 服務(wù)的 JSONRpcClient
          jsonrpc = new JSONRpcClient("/DojoJ2EE/JSON-RPC");
          var stockButton = dojo.byId('stockInput');
          jsonrpc.StockService.getStockData(stockResultCallBack,stockButton.value);
          	

          此請(qǐng)求會(huì)發(fā)送以下有效負(fù)載:

          {"id": 2, "method": "StockService.getStockData", "params": ["IBM"]}

          響應(yīng)與以下所示類似:

          {"result":{"javaClass":"com.ibm.issw.json.service.StockData","price":100, "companyName":"International Business Machine","symbol":"IBM"},"id":2}

          用于 Java 客戶端的 JSON-RPC 將處理此響應(yīng),并向您提供一個(gè)靜態(tài)接口。

          為了支持請(qǐng)求,您需要注冊(cè)特殊的 Servlet。稍后,我將向您介紹如何執(zhí)行此操作。

          JSON-RPC Java ORB 的一個(gè)缺點(diǎn)是只有單個(gè) URL,這導(dǎo)致使用 Java EE 安全來(lái)保護(hù) URL 非常困難。作為一種變通方法,您可以在 HTTP 會(huì)話層注冊(cè)服務(wù),并根據(jù)安全需要添加它們。





          回頁(yè)首


          為企業(yè)應(yīng)用程序構(gòu)建企業(yè)客戶端

          在此部分中,我將討論一些設(shè)計(jì)原則,然后詳細(xì)講解一個(gè)示例。您可以下載完整的 WAR 文件,并親自嘗試該應(yīng)用程序。

          模型-視圖-控制器

          在 Java EE 領(lǐng)域中,模型-視圖-控制器 (MVC) 已經(jīng)變得非常成熟,這歸功于 Struts 和 JavaServer Faces 之類的框架。使用 Ajax 可以進(jìn)行正確的 MVC 設(shè)計(jì),這對(duì)成功的 Web 應(yīng)用程序至關(guān)重要。此外,SOA 允許直接從 Ajax 應(yīng)用程序調(diào)用服務(wù)。這樣做有幾個(gè)優(yōu)點(diǎn),如 WebSphere 期刊文章 "AJAX Requests – Data or Markup?" 中所述。

          圖 2 提供了 Ajax 客戶端和 Java EE 應(yīng)用程序之間理想生態(tài)系統(tǒng)的簡(jiǎn)要概述。


          圖 2. Ajax 客戶端和 Java EE 應(yīng)用程序之間的理想生態(tài)系統(tǒng)
          Ajax 客戶端和 Java EE 應(yīng)用程序之間的理想生態(tài)系統(tǒng)。

          在服務(wù)器端,業(yè)務(wù)和門戶功能現(xiàn)在被公開(kāi)為某一類型的服務(wù)接口。在服務(wù)的形式下,應(yīng)遵循正確的服務(wù)器端最佳實(shí)踐。服務(wù)器應(yīng)用程序應(yīng)公開(kāi)過(guò)程粒度服務(wù)。JavaServer Faces 之類的框架現(xiàn)在負(fù)責(zé)執(zhí)行初始呈現(xiàn);不過(guò),對(duì)于客戶端 Ajax 工具包,這是可選的。

          在瀏覽器上,分離關(guān)注的內(nèi)容非常重要。圖 3 突出顯示了 Java 服務(wù)器文件結(jié)構(gòu):


          圖 3. Java 服務(wù)器文件結(jié)構(gòu)
          Java 服務(wù)器文件結(jié)構(gòu)。

          您可以選擇每頁(yè)有一個(gè) JavaScript 控制器。不過(guò),對(duì)于復(fù)雜的門戶頁(yè),您可以將相關(guān)事件分組成小型的控制器集。

          控制器文件應(yīng):

          1. 向小部件加載網(wǎng)絡(luò)請(qǐng)求處理程序,如圖 4 所示:

            圖 4. 將請(qǐng)求處理程序附加到小部件
            將請(qǐng)求處理程序附加到小部件。

          2. 實(shí)現(xiàn)請(qǐng)求處理程序。請(qǐng)求處理程序不應(yīng)有太多的邏輯。它們應(yīng)委派給服務(wù) Facade,以便與后端交互。
          3. 實(shí)現(xiàn)回調(diào)處理程序方法。回調(diào)應(yīng)將呈現(xiàn)委派給獨(dú)立 JS 文件。此外,它們應(yīng)將存儲(chǔ)中間狀態(tài)的工作委派給獨(dú)立 Java 服務(wù)器文件。對(duì)于無(wú)狀態(tài)交互,可以直接將結(jié)果傳遞到 rendering.js 文件。

          圖 5 說(shuō)明了組件之間的流:


          圖 5. 從客戶端到請(qǐng)求處理程序,再到回調(diào)處理程序的信息流
          從客戶端到請(qǐng)求處理程序,再到回調(diào)處理程序的信息流。

          呈現(xiàn)文件包含呈現(xiàn)組件的邏輯或基于事件結(jié)果的用戶界面。

          Business Facades 應(yīng)包含代理服務(wù)器請(qǐng)求的方法。DataCopy 應(yīng)維護(hù)需要本地保存在瀏覽器中的本地視圖對(duì)象。

          為 Dojo 設(shè)置 Java EE 應(yīng)用程序

          對(duì)于 Dojo,您必須添加 JavaScript 文件作為 Web 應(yīng)用程序的一部分。您可以將 dojo 文件夾復(fù)制到 Web 應(yīng)用程序文件夾,如圖 6 所示:


          圖 6. 添加使用 Dojo 所必需的 JavaScript 文件
          添加使用 Dojo 所必需的 JavaScript 文件。

          為 JSON-RPC Java Orb 設(shè)置 Java EE 應(yīng)用程序

          為了在應(yīng)用程序中使用 JSON-RPC Java Orb,您需要在 Web 應(yīng)用程序的 lib 目錄中添加 json-rpc-1.0.jar。還需要將單個(gè) jsonrpc.js 文件添加到 Web 內(nèi)容文件夾中,如圖 7 所示:


          圖 7. 添加使用 JSON-RPC Java Orb 所必需的 JavaScript 文件
          添加使用 JSON-RPC Java Orb 所必需的 JavaScript 文件。

          為了使 Java EE 應(yīng)用程序能夠接收用于 Java 請(qǐng)求的 JSON-RPC,您必須添加 JSONRPCServlet,如清單 9 所示:


          清單 9. 使用 JSONRPCServlet 所需的代碼
          <servlet>
          	<servlet-name>
          		com.metaparadigm.jsonrpc.JSONRPCServlet
          	</servlet-name>
          	<servlet-class>
          		com.metaparadigm.jsonrpc.JSONRPCServlet
          	</servlet-class>
          </servlet>
          
          <servlet-mapping>
          	<servlet-name>
          		com.metaparadigm.jsonrpc.JSONRPCServlet
          	</servlet-name>
          	<url-pattern>/JSON-RPC</url-pattern>
          </servlet-mapping>
          	

          對(duì)于 SOA

          Ajax 使 SOA 客戶端更完美。在我們的示例中,我們使用了一個(gè)簡(jiǎn)單的 Java 服務(wù)。

          Java 服務(wù)

          圖 8 是基于 Java 的服務(wù)模型:


          圖 8. 基于 Java 的服務(wù)模型
          基于 Java 的服務(wù)模型。

          我們使用了一個(gè)簡(jiǎn)單的硬編碼實(shí)現(xiàn),如清單 10 所示:


          清單 10. 簡(jiǎn)單的硬編碼 Java 服務(wù)
          public StockData getStockData(String symbol) throws StockException {
          	if(symbol.equals("IBM"))
          	{
          		StockData stockData = new StockData();
          		stockData.setCompanyName("International Business Machine");
          		stockData.setSymbol(symbol);
          		stockData.setPrice(100.00);
          		return stockData;
          	}
          	else
          	{
          		throw new StockException("Symbol: " + symbol + " not found!");
          	}	
          }
          	

          使用 JSON-RPC 公開(kāi) Java 服務(wù)

          為了公開(kāi) Java 應(yīng)用程序,我使用了被稱為 ExportServices 的 HttpSessionListener,以便為用戶注冊(cè)服務(wù),如清單 11 所示:


          清單 11. ExportServices,即公開(kāi) Java 服務(wù)的 HttpSessionListener
          import javax.servlet.http.HttpSession;
          import javax.servlet.http.HttpSessionEvent;
          import javax.servlet.http.HttpSessionListener;
          	
          import com.ibm.issw.json.service.StockServiceImpl;
          import com.metaparadigm.jsonrpc.JSONRPCBridge;
          	
          public class ExportServices implements HttpSessionListener {
          	
          	public void sessionCreated(HttpSessionEvent sessionEvent) {
          			
          		HttpSession session = sessionEvent.getSession();
          		JSONRPCBridge json_bridge = null;
          		json_bridge = (JSONRPCBridge) session.getAttribute("JSONRPCBridge");
          			if(json_bridge == null) {
          				json_bridge = new JSONRPCBridge();
          				session.setAttribute("JSONRPCBridge", json_bridge);
          			}
          		json_bridge.registerObject
          			("StockService",StockServiceImpl.getStockService());
          	}
          	
          	public void sessionDestroyed(HttpSessionEvent arg0) {
          			
          	}
          	
          }
          	

          您需要將偵聽(tīng)器添加到應(yīng)用程序中(通過(guò)將其添加到 web.xml),如清單 12 所示:


          清單 12. 添加到 web.xml 的 ExportServices 偵聽(tīng)器
          <listener>
          	<listener-class>ExportServices</listener-class>
          </listener>
          	

          客戶端開(kāi)發(fā)過(guò)程

          設(shè)置了基礎(chǔ)結(jié)構(gòu)并公開(kāi)了服務(wù)之后,現(xiàn)在我們可以構(gòu)建 Web 客戶端了。通過(guò) Dojo,我們利用小部件構(gòu)建網(wǎng)頁(yè)并利用事件模型。圖 9 說(shuō)明了建議的開(kāi)發(fā)過(guò)程:


          圖 9. 開(kāi)發(fā)過(guò)程示例
          開(kāi)發(fā)過(guò)程示例。

          我將使用此過(guò)程演示該示例。

          從小部件構(gòu)建 UI

          首先構(gòu)建 UI。請(qǐng)參見(jiàn)清單 13,了解示例 UI。

          創(chuàng)建 UI:

          1. 加載腳本:
            1. dojo
            2. jsonrpc
            3. StockClientController
            4. resultRenderer
          2. 構(gòu)建頁(yè)面,并結(jié)合使用 div 和 HTML 標(biāo)記以創(chuàng)建 Dojo 小部件。

            清單 13. HTML UI
            <html>
            <head>
            <title>Stock Form</title>
            
            <script type="text/javascript" src="../dojoAjax/dojo.js"></script>
            <script type="text/javascript" src="../jsonrpc.js"></script>
            <script type="text/javascript" src="../view/resultRender.js"></script>
            <script type="text/javascript"
            	src="../controller/StockClientController.js"></script>
            <link REL=StyleSheet href="../StockApp.css" TYPE="text/css" ></link>
            </head>
            <body>
            
            <div class="layout" dojoType="LayoutContainer">
            <div dojoType="ContentPane" class="stockContent" layoutAlign="bottom"
             id="docpane" isContainer="true" executeScripts="true">
            <div dojoType="FloatingPane" class="stockPane" title="Stock Form" 
            id="pane" constrainToContainer="true" displayMaximizeAction="true">
            			<h2>Stock Service</h2>
            Enter symbol: <input dojoType="ValidationTextBox" required="true"
            			id="stockInput">
            			<p />
            			<button dojoType="Button2" widgetId="stockButton">
            Get Stock Data
            </button>
            			<div id="resultArea" />
            		</div>
            	</div>
            </div>
            </body>
            </html>
            	

          3. StockClientController.js 非常關(guān)鍵。在腳本的開(kāi)頭,使用 dojo.require 方法加載所需的小部件,然后初始化 Dojo 環(huán)境,如清單 14 所示。

            清單 14. 初始化 Dojo 環(huán)境的 StockClientController
            //require statements
            dojo.require("dojo.widget.*" );
            dojo.require("dojo.event.*");
            dojo.require("dojo.widget.Button2");
            dojo.require("dojo.widget.FloatingPane" );
            	
            //all dojo.require above this line
            dojo.hostenv.writeIncludes(); 
            dojo.require();	
            	

          操作前后需要考慮的事項(xiàng)

          在 Ajax 中,需要考慮的一件事是,在觸發(fā)事件之前,不要顯示某些用戶界面。不過(guò),一種做法是放置 div 標(biāo)記作為占位符。然后,可以使用 DOM 或 Dojo API 訪問(wèn)此區(qū)域,并添加動(dòng)態(tài) UI 元素。在我們的應(yīng)用程序中,我添加了一個(gè)簡(jiǎn)單的 div,以獲得以下結(jié)果:

          <div id="resultArea" />

          附加樣式表

          接下來(lái),使用 CSS 添加樣式。CSS 是設(shè)置 Ajax 應(yīng)用程序格式的標(biāo)準(zhǔn)方法。使用 CSS,您可以將樣式定義應(yīng)用于多個(gè) div 標(biāo)記,方法是將標(biāo)記的 class 屬性設(shè)置為該樣式的名稱。這允許您重用樣式定義。清單 15 顯示了我使用的樣式表:


          清單 15. 在 UI 中使用的樣式表
          @CHARSET "ISO-8859-1";
          
          .layout
          {
          	width: 100%;
          	height: 80%;
          }
          	
          .stockContent
          {
          	width: 100%; 
          	height: 90%;
          	background-color: #F0F0F0 ; 
          	padding: 10px;
          }
          	
          .stockPane
          {
          	width: 40%; 
          	height: 250px;
          }
          	
          .exceptionMsg
          {
          	color: #FF0000;
          }
          	

          服務(wù)視圖

          接下來(lái),一個(gè)好的想法是確保 UI 開(kāi)發(fā)人員在 JavaScript 中擁有一個(gè)服務(wù)視圖。Dojo 使用 SMD 來(lái)做到這一點(diǎn),如前面所述。用于 Java 的 JSON-RPC 為我們提供了直接從 JavaScript 調(diào)用 Java 服務(wù)的能力,如清單 16 所示:


          清單 16. 直接調(diào)用 Java 服務(wù)的 JavaScript
          <script type="text/javascript" src="../jsonrpc.js"></script>
          jsonrpc.StockService.getStockData(stockResultCallBack,stockButton.value);
          	

          構(gòu)建請(qǐng)求事件處理程序

          接著,在控制器 JS 文件中,我們需要?jiǎng)?chuàng)建事件處理程序和回調(diào)處理程序。回調(diào)處理程序應(yīng)是其他工作的 Facade。在我們的示例中,事件處理程序?qū)惒秸{(diào)用我們的服務(wù),并將回調(diào)傳遞到相應(yīng)的方法。XMLHttpRequest 對(duì)象的此抽象由 JSON-RPC-Java 提供。在接收到響應(yīng)時(shí),回調(diào)委派給呈現(xiàn),如清單 17 所示:


          清單 17. 控制器文件中的回調(diào)和事件處理程序
          function stockResultCallBack(result,exception) {
          	try {
          		renderStockResult(result,exception);
          	} catch(e) {
          		alert(e);
              } 	    
          }
          
          function submitStock()
          	{
             	try {
          		jsonrpc = new JSONRpcClient("/DojoJ2EE/JSON-RPC");
          		var stockButton = dojo.byId('stockInput');
          		jsonrpc.StockService.
          			getStockData(stockResultCallBack,stockButton.value);
          	} 
          	catch(e) {
          		alert(e);
          	}
          }
          	

          在加載時(shí)加載初始 UI 和網(wǎng)絡(luò)請(qǐng)求事件

          下面,我們?cè)陧?yè)面初始化時(shí)使用 Dojo 這種有力的工具,將小部件連接到請(qǐng)求處理程序。請(qǐng)參見(jiàn)清單 18 中的 init 方法。dojo.addOnLoad() 方法允許您使用同一面向方面的技術(shù),將 init 方法附加到頁(yè)面加載事件。


          清單 18. init() 方法
          function init()
          	{
          	var stockButton = dojo.widget.byId('stockButton');
          	dojo.event.connect(stockButton, 'onClick', 'submitStock');
          	}
          dojo.addOnLoad(init);
          	

          呈現(xiàn)響應(yīng)

          最后一步是添加動(dòng)態(tài)呈現(xiàn)響應(yīng)代碼。我將它放置在獨(dú)立呈現(xiàn)器 JS 文件中。您可以使用各種方法來(lái)呈現(xiàn)響應(yīng)。在我們的示例中,我們將結(jié)合使用 DOM API 和 Dojo 實(shí)用工具來(lái)構(gòu)建簡(jiǎn)單的表。在這里,我們可以使用 Dojo 的小部件之一,但是我希望對(duì)清單 19 中的函數(shù) renderStockResult 使用自已的代碼,以便突出顯示一些 Dojo 實(shí)用工具和數(shù)據(jù)結(jié)構(gòu)。

          要?jiǎng)?chuàng)建呈現(xiàn)響應(yīng)代碼,請(qǐng)執(zhí)行下列操作:

          1. renderStockResult 函數(shù)中,使用 dojo.byId() 方法訪問(wèn) resultArea 對(duì)象。
          2. 檢查任何異常;如果 renderStockResult 含有傳遞給它的異常,它會(huì)將該異常傳遞到錯(cuò)誤處理程序并返回。
          3. 使用 Dictionary(類似于 Java HashMap)和 ArrayList Dojo 結(jié)構(gòu)來(lái)存放 result 數(shù)據(jù)。
          4. 將結(jié)構(gòu)化數(shù)據(jù)傳遞到通用表創(chuàng)建者方法。

          清單 19. 呈現(xiàn)響應(yīng)方法
          dojo.require("dojo.collections.*");
          dojo.require("dojo.fx.*");
          
          function renderStockResult(result,exception)
          {
          	var resultArea = dojo.byId('resultArea');
          	if(exception)
          	{
          		handleStockError(resultArea,exception);
          		return;
          	}
          	
          	var symbolHeader = "Symbol:";
          	var priceHeader = "Price:";
          	var companyNameHeader = "Company Name:";
          	
          	var headers = new dojo.collections.ArrayList();
          	headers.add(symbolHeader);
          	headers.add(priceHeader);
          	headers.add(companyNameHeader);
          	
          	var column = new dojo.collections.Dictionary();
          	
          	column.add(symbolHeader,result.symbol);
          	column.add(priceHeader,result.price);
          	column.add(companyNameHeader,result.companyName);
          	
          	var data = new dojo.collections.ArrayList();
          	
          	data.add(column);
          	
          	createTableWithVerticleHeading(resultArea,headers,data);
          		
          }
          	

          設(shè)置了數(shù)據(jù)結(jié)構(gòu)之后,調(diào)用具體的 createTableWithVerticleHeading 方法。實(shí)際上,此類實(shí)用工具將會(huì)被外部化。在下面顯示的方法中,我們將使用 Dojo Iterator 對(duì)象來(lái)遍歷這些數(shù)據(jù)結(jié)構(gòu)并創(chuàng)建表。我要在下面指出的另一個(gè)方法是 dojo.fx.html.fadeShow(table, 200),您可以使用該方法將淡入效果添加到結(jié)果的打印中。這只是某些動(dòng)畫(huà)的一瞬。在清單 20 中,Dojo 代碼為粗體。


          清單 20. 表創(chuàng)建方法
          function createTableWithVerticleHeading(root,headers,data)
          {
          	
          	var oldResult = dojo.byId('resultTable');
          	if(oldResult)
          	{
          		root.removeChild(oldResult);
          	}
          	var exceptionMsg = dojo.byId('stockExceptionMsg');
          	if(exceptionMsg)
          	{
          		resultArea.removeChild(exceptionMsg);
          	}
          	var table = document.createElement("table");
          	dojo.fx.html.fadeShow(table, 200);
          	table.setAttribute("id","resultTable");
          	
          	root.appendChild(table);
          	var headerIter = headers.getIterator();
          	
          	
          	while(!headerIter.atEnd())
          	{
          		var row = document.createElement("tr");
          		table.appendChild(row);
          		var element = document.createElement("th");
          		element.setAttribute("align","left");
          		row.appendChild(element);
          		var header = headerIter.get();
          		var dataElement = document.createTextNode(header);
          		element.appendChild(dataElement);
          		var dataIter = data.getIterator();
          		while(!dataIter.atEnd())
          		{
          			var resultItem = dataIter.get();
          			var item = resultItem.item(header);
          			var elementItem = document.createElement("td");
          			elementItem.setAttribute("align","left");
          			row.appendChild(elementItem);
          			var dataText = document.createTextNode(item);
          			elementItem.appendChild(dataText);
          		} 	
          	}
          }
          	

          最后,我們將添加簡(jiǎn)單的錯(cuò)誤處理方法,以打印錯(cuò)誤消息,如清單 21 所示。請(qǐng)記住,通過(guò)在元素上設(shè)置類屬性,然后委派給 CSS 文件,可添加粗體文本。


          清單 21. 錯(cuò)誤處理方法
          function handleStockError(resultArea,exception)
          {
          	var oldResult = dojo.byId('resultTable');
          	if(oldResult)
          	{
          		resultArea.removeChild(oldResult);
          	}
          	var exceptionMsg = dojo.byId('stockExceptionMsg');
          	if(exceptionMsg)
          	{
          		resultArea.removeChild(exceptionMsg);
          	}
          	var error = document.createElement("h4");
          	error.setAttribute("class","exceptionMsg");
          	error.setAttribute("id","stockExceptionMsg");
          	var errorText = document.createTextNode(exception.message);
          	resultArea.appendChild(error);
          	error.appendChild(errorText);
          	
          	return;
          }
          

          測(cè)試應(yīng)用程序

          您可以下載應(yīng)用程序的最終 WAR 文件。可將其安裝在任何應(yīng)用服務(wù)器(如 WebSphere Application Server)上。部署了應(yīng)用程序后,您可以打開(kāi) HTML 頁(yè),以查看浮點(diǎn)形式,如圖 10 所示:


          圖 10. HTML 中的浮點(diǎn)形式
          HTML 中的浮點(diǎn)形式

          可以自由移動(dòng)該形式。您可能注意到,我已將浮點(diǎn)綁定到外部容器,如圖 11 所示:


          圖 11. 綁定到外部容器的浮點(diǎn)
          綁定到外部容器的浮點(diǎn)。

          輸入 IBM 以調(diào)用 Java EE 應(yīng)用程序。結(jié)果應(yīng)類似于圖 12 所示的形式:


          圖 12. 將 IBM 輸入到應(yīng)用程序的結(jié)果
          將 IBM 輸入到應(yīng)用程序的結(jié)果。

          接下來(lái),輸入一些其他數(shù)據(jù),以測(cè)試錯(cuò)誤處理程序,如圖 13 所示。


          圖 13. 測(cè)試錯(cuò)誤處理程序
          測(cè)試錯(cuò)誤處理程序。

          Dojo 還提供了單元測(cè)試套件以自動(dòng)執(zhí)行單元測(cè)試。





          回頁(yè)首


          結(jié)束語(yǔ)

          在本文中,我向您介紹了如何使用 Dojo 工具包、JSON 和 JSON-RPC 為 Java EE 應(yīng)用程序構(gòu)建 Ajax 客戶端。我概述了每項(xiàng)技術(shù),并介紹了一些設(shè)計(jì)原則。最后,我提供了一個(gè)示例應(yīng)用程序。Ajax 應(yīng)用程序?qū)⒑芸斐蔀?SOA 客戶端。通過(guò)使用 Dojo 之類的工具包,您可以方便地構(gòu)建這些網(wǎng)頁(yè)。


          引用:http://www-128.ibm.com/developerworks/cn/websphere/library/techarticles/0606_barcia/0606_barcia.html

          posted on 2007-03-06 16:54 whirlyzhq 閱讀(2172) 評(píng)論(0)  編輯  收藏 所屬分類: framework


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 屯留县| 贡山| 新乐市| 嘉禾县| 新田县| 莲花县| 泸定县| 靖远县| 长沙市| 鹰潭市| 涟源市| 贵州省| 吉林省| 淳安县| 涿鹿县| 三河市| 彝良县| 子长县| 三台县| 天等县| 进贤县| 多伦县| 运城市| 宣汉县| 措勤县| 永泰县| 临漳县| 当阳市| 南昌市| 黑水县| 库尔勒市| 盐亭县| 西盟| 昔阳县| 湘潭市| 贵阳市| 新津县| 天镇县| 西藏| 双江| 仲巴县|