對這文章發表回應
發表限制: 非會員 可以發表
當您要將企業應用程序轉變成與 Web服務一起使用時,最簡單的途徑就是將單個操作與單個的企業服務結合在一塊。但這並不是最好的方法。在本文中,Jerome Josephraj將向您展示如何構架基於分層的、正確的模型-視圖-控制器(MVC)設計模式的Web 服務應用程序。為此,他修改了Struts(一種流行的開放源碼MVC 框架),以使其適用於 Web 服務領域。通過研究此處所概述的樣本應用程序,您將知道如何才能將Struts 與 Web 服務聯合起來使用。
不斷發展的 Java 編程語言和 Sun 公司的 J2EE規範使得遵守各類準則的軟件開發者們能夠創建出分布式計算應用程序,這些應用程序在以前只能通過相關專門工具才可實現。這樣,當某些開發團體要選擇在 Java平台中實現新系統時,其他團體就會通過另外的技術來創建、提高並維護應用程序,然後將它們集成到已有的各類分布式應用程序中去。這種情形就引起了互操作性的競爭。新應用程序與舊應用程序如何交互呢?答案就是:Web服務。Web 服務是程序設計新的聖杯。它們能夠共享並協調分散的各類計算資源。
在本文中,您將了解實現此目的的一種方法。您將看到如何在與 Web服務相結合的開放源碼 Struts框加的基礎上來構建應用程序。在開始之前您必須了解一些 J2EE 與 Web 服務的相關知識。這裡,我將簡要地介紹下 Struts架構與模型-視圖-控制器(MVC),如果您以前沒碰到過,那麼您應該在後面先看下 參考資料部分來獲取更多信息。
MVC設計模式很清楚的劃定了程序員與設計者的角色界限。換句話說,從商業邏輯上拆解了數據。這種模式是讓設計者集中於設計應用程序的顯示部分,而開發者則集中於開發驅動應用程序功能所需的組件。
MVC 模式有好幾種變異,不過它們都是基於相同的基礎結構:應用程序的數據模型 (Model),顯示層代碼(View),以及程序控制邏輯( Controller)是存在其中的獨立但能相互間通信的組件。模型組件描述並處理應用程序數據。視圖指的是用戶界面;它反映的是模型數據並把它遞交給用戶。控制器是將視圖上的行為(例如,按下Submit 按鈕)映射到模型上的操作(例如,檢索用戶詳細信息)。模型更新後,視圖也被更新,用戶就能夠完成更多行為。MVC模式使代碼易懂而且使代碼更容易重用;另外,在很多工程中視圖經常要被更新,MVC 模式將模型和控制器與這些所做的更改獨立開來。
圖 1 MVC 模式概要
請參閱下面的參考資料,以獲取更多關於模型-視圖-控制器的更多信息。
Struts是 MVC 模式基礎上構建 Web 應用程序的一種開放源碼框加。Struts 鼓勵在 MVC 模式上構建應用程序而且提供大多數 Web 應用程序所共有的服務。
在 Struts應用程序中,您可以構建模型層,這樣業務邏輯與數據檢索邏輯重用就很容易了。這層負責運行應用程序的業務邏輯,獲取相關數據(例如,運行SQL 命令或者讀取平面文件)。
Struts 鼓勵在模型-視圖-控制器設計範例基礎上構建應用程序。Struts 提供自己的控制器組件(ActionController類)並與其他技術相結合來提供模型與視圖。對於模型(Model 類), Struts 能與任何標準的數據訪問技術相結合,包括 EJB、JDBC以及 Object-Relational Bridge。對於視圖(ActionForm類),Struts 在 JSP 環境以及其他基於表示邏輯的系統中運行的很好。圖 2 闡明了基於Struts 應用程序的邏輯流程。
構建Web 服務最簡單的途徑就是將單個操作與單個企業服務結合起來,如圖 3所示。在這種設計方法中,實現業務邏輯的服務與實現數據檢索的服務是混合在一起的。
這樣的一種 Web服務可以很容易從已有的業務組件中開發出來。然而,它有很多的缺點:對用戶沒有提供統一認證,提供者與訂閱者耦合不緊,業務邏輯沒有重用。簡而言之,對於一個連貫的解決方案來說這並不是一個非常好的體系結構。
在 MVC 模式基礎上來實現 Web 服務解決方案會更好點。在後續部分,您將看到如何使用 Struts 來做到這一點。我將通過 WSManager層來詳述現有的 Struts 架構,這一層展示了採用 Web 服務的模型服務方法。
在以後的開發工作中您可以擴大構建得比較好的 Struts 應用程序來支持 Web服務。前面講過,Struts架構清晰地區分開了視圖、控制器以及模型。模型包含所有必須的業務邏輯,從存儲數據倉庫中檢索數據。您可以構建一個簡單的 Web 服務層——稱為 WSManager層——這樣的模型可以提供 Web 服務也可以訂購 Web 服務。使用這種體系結構的應用程序將基於組件開發的最佳點與萬維網結合在了一起,如圖 4所示。
下面的部分要討論的是這種體系結構中不同組件的詳細信息,特別要密切注意 WSManager層,因為它是此體系結構中真正新加的部分。
Struts 控製器
MVC體系結構的控制器部分主要集中於接收客戶端的請求(一般為運行 Web瀏覽器的用戶),決定執行哪一種業務邏輯功能來響應請求,然後負責生成下一個用戶界面連接到合適的視圖組件上去。在 Struts中,控制器的主要組件就是 ActionServlet 類的一個小服務程序。
ActionServlet 負責通過 XML 文檔將 URI 請求映射到特定的行為。這個文檔包含了URI 請求列表而且還告知 ActionServlet 它應該如何分配每個請求。這種方法有幾個好處:
- 應用程序的整個邏輯流程在分級文本文件中。
- 這種格式的列表更容易查看與理解,尤其是對於一個很大的應用程序而言。
ActionServlet 決定了應用程序的流程。許多 Action類都繼承了 ActionServlet 。每個 Action類:
- 都映射到各自獨立的處理過程
- 通過 Struts 的 ActionController與 Struts JSPs 相結合
- 作為繼承 Struts中 Action 類的一個 Java 類來實現。
Struts中 Action 類調用 WSManager 類中的相關方法來使用 Web服務。 WSManager 獲取所要求的響應——或者如果有一個被解除了就會出現異常——將它回傳給 Struts控制器。
WSManager
WSManager接收 JAX-RPC 端點的請求。將 WSManager 類中的方法調用映射到新來的客戶端請求。這些新來的客戶端請求是SOAP 信息的格式。WSManager必須實現安全認證,轉變參數,在指定請求到模型服務之前,要對這些請求進行參數預處理。請求所包含的參數形式有 Java對象,Java原始參數,XML 文檔,或者甚至是 SOAP 文檔分片(例如,SOAP Element對象)。這些類型必須要轉化成內部所支持的 schema(例如,預定義的 Java 數據訪問對象)。
雖然 WSManager 可以很直接地處理與 Java 對象結合的參數,但它還需要採取一些附加步驟來處理 XML文檔。建議以下步驟:
- WSManager 類應該能夠通過XML Schema來驗證XML文檔的有效性。
- WSManager 類接著要把 XML 文檔轉化成內部支持的 schema。
- 最後 WSManager 應該分解文檔並且儘可能地將它映射到域對象中去。
WSManager 實現以下任務是非常重要的:
- 身份驗證和授權使用
- 錯誤處理
- 緩存。
WSManager 也可以生成響應;這個過程由方法調用返回值的簡單構造所組成。WSManager 中保留這樣的功能,您可以通過緩存數據從而避免重複訪問模型服務層。您還可以集中管理響應聚集以及XML 文檔轉換,如果您要返回給調度者的文檔必須遵守與內部 schema 不同的 schema 時,這一點就顯得尤其重要。
WSManager處理所有SOAP 請求並把它們委派到模型層所暴露的業務邏輯。如果模型服務是作為一個 EJB 層來實現,那您一樣可以在 EJB 層中通過 SessionFac,ade 設計模式來實現。如果您採用這種模式執行 WSManager ,您將獲得很多好處,因為 WSManager會:
- 作為初始聯繫點來管理請求與服務
- 調用安全服務,包括身份驗證與授權使用,從而避免任何重複的層訪問。
- 委派業務處理(採用由 Struts 應用程序所使用的模型服務)
- 在 WSManager層緩存數據避免任何不必要的數據庫訪問。
發布者:展示 Web 服務
在 WSManager類中實現的每一個公共方法都將作為一種 Web 服務發布出來。換句話說,您要為這些類發布一種Web 服務描述 。Web 服務描述是由服務的 Web 服務描述語言(WebServices Description Language,WSDL)描述與由它所引用的任何 XML schema所組成。(WSDL 是描述服務的標準語言。)
您可以在公共註冊中心或在企業內的公司註冊表上發布 Web 服務描述。同樣,你也可以發布由WEB 服務定義的XMLSchema到同一個公共的或者公司專有的(UDDI)註冊中心上。 Java Web 服務客戶端採用 JAXR應用編程接口來查詢公司或公共註冊表上的服務描述。
如果您的客戶都是專有的合作夥伴,那您就不需要使用註冊表了。不過,您可以在您的應用程序的 Web 層或者在具備適當安全保護的熟知位置來發布您的Web 服務描述( WSDL 和 XML schemas)。例如,假想有一個轉售者的客戶應用程序,他與某個特殊廠商有協定。客戶應用程序已經在廠商開發時間中靜態地與 Web 服務結合在一起了。只有授權的團體才可以查詢 XML schema 或者從 Web 層檢索服務描述來生成客戶端代碼。您應該在 WSManager層中執行有效客戶的身份驗證和授權使用。
訂購者:使用 Web 服務
應用程序可以利用在公共註冊表或者企業內部中已存的 Web 服務。 WSManager有解析必要的 WSDL文件的方法並且調用相關的操作返回一個值。Struts 控制器在 WSManager 類中調用相關方法來使用特定的Web 服務。數據作為預定義的數據訪問對像在 WSManager 和 Struts 控制器之間來回傳送。訪問 Web服務時所發生的所有異常都將在 WSManager中列舉出來並且傳回到 Struts ActionController.
服務請求者要通過使用服務代理來搜索 Web 服務;如果找到它所想要使用的 Web 服務,為使用這個服務它將與服務提供者建立一個合約,然後才能調用服務中的業務。
WSManager使用 WSDL文檔、服務器名字、端口名、操作名以及包括 Java原始類型、Java 數組、Java 對象 或者與 XML 文檔等所有必需的請求參數一起來訂購一個 Web 服務。
如果是在 UDDI 註冊表中發布目標 Web 服務,那麼所有基於 Struts 的應用程序都能使用像 XMethods(請參閱參考資料)這樣的代理服務來訂購它。在執行完所請求的操作後,供應者 Web 服務返回所期望的值。 WSManager可以更改返回值使得它與應用程序所期待的 schema 相匹配;它也可以在應用程序要求基礎上修改結果。從 WSManager收到結果以後,Struts ActionController能夠處理結果並傳送給相關視圖,或者還能調用相關的模型服務來完成深層處理。
錯誤處理
所有的錯誤都是在 WSManager 層中處理的;這就消除了不必要的服務器開銷。如果模型服務是當作 EJB層來實現的,那麼其性能會得到非常顯著地增強。
在充當供應者角色時, WSManager拋出所有如 SOAPFaultException這樣的異常。它還可以檢查新來的請求並且拋出所有缺少強制字段的異常。您可以創建一個類來跟蹤並在數據倉庫中記錄這些錯誤,以後可以做作參考。
在充當訂購者角色時, WSManager捕捉到由服務供應者所拋出的所有 SOAP 異常並且將它們更改為 WSManager所要求的格式。您可以記錄下所拋出的錯誤作為以後參考之用。如果需要,那麼在需要時候也能夠校驗出響應值並且作為異常拋出。您可以創建一個類來記錄這些異常,作為以後參考之用。 WSManager能夠驗證響應值而且可以作為一個異常將它拋出。
審核
在充當供應者角色時, WSManager可以記錄下詳細信息,將來可以做為審核。使用這些信息有很多用途,像:
- 在所接收到的大量採樣點基礎上登記客戶端。
- 收集數據用作市場目的。
- 決定應用程序是否需要更新。
- 鑑別並捕捉非法用戶。
緩存
Web 服務的客戶往往要比一般的客戶端-服務器體系結構中的客戶要多些;因此在 Web服務體系結構中,客戶端就要做更多的工作,比如緩存。Web服務正確使用數據緩存就可以實現其最大的性能。當服務的請求信息主要是只讀的時候或者當那些信息按照比所要求的速率變化得還要慢時,您就應該考慮要在 Web服務中使用緩存了。
身份驗證與授權使用
您可以在 WSManager層中執行所有訂購者的身份驗證。所有想使用 Web服務的客戶都要經過這樣的身份驗證邏輯。您可以使用基本用戶身份驗證或者數字證書來實現此目的。
Struts 視圖
您要通過使用JSP 技術來構建基於 Struts 應用程序的視圖部分。JSP 頁包含有靜態 HTML 加上動態內容,這些內容是基於對特別行為標籤說明(在頁面要求時)的。JSP 環境包括一套標準的行為標籤。另外,在自定義標籤庫中組織了一套標準的工具,開發者們可以使用這些工具來定義他們自己的標籤。
Struts框架包含有擴展的自定義標籤庫,這個庫能幫助用戶界面國際化更為全面並能非常適度地與 ActionForm組件相互作用。視圖層比較單薄,它不提供業務邏輯。Struts 視圖是通過 ActionForm 與 Struts控制器相互作用的。
Struts ActionForm
ActionForms只是一些 Java 類而已,它繼承了 Struts 所提供的 ActionForm 類,這些類中包含有 accessor和 mutator 方法。 JSP 頁或者 Action 類都會調用這些方法來檢索或者從數據庫刷新數據。
模型服務
模型服務是作為一組Java 類來執行的。每個模型服務組件都會提供一套服務,而這些組件結合起來同樣也提供一套普通服務。 ActionController與 WSManager類將數據當作預定義的數據訪問對象來回傳送。在處理過程中,ActionController或者 WSManager可以調用相關模型服務組件中所要求的方法。這些組件將所要求的數據以數據訪問對象的形式傳給模型服務,模型服務執行一切必須的商業邏輯處理然後從存儲數據倉庫中取出所需要的數據。模型服務組件聚集相關的預定義數據訪問對象,然後將它傳回給 ActionServlet或者 WSManager類。所有的錯誤或者確認信息都會通知給 ActionServlet或 WSManager層。
對於您的應用程序,您應該遵守以下的設計規則:
- 模型服務不能含有任何與視圖相關的代碼(例如,會話處理)。
- 所有的事務僅僅只能在 Action 或 WSManager層中來提交。
- 模型服務只能被同一模型服務組件中其他的模型服務或者高層 Action 類所調用。
數據存儲層
數據存儲層由所有的存儲數據倉庫組成。例如,它可能包含有關係數據庫、平面文件或者甚至有 XML 文檔。
我已經附上了實現此處所討論的體系結構的一個簡單示例。所有的示例代碼都包含在了 zip文件中(請參閱下面的參考資料)。這個例子舉例說明了一個簡單的新聞Portal。新聞內容是從數據源(這裡稱為 DataSource)傳送到 JSP 頁,同時信息內容也要作為一個 Web服務發布出來。這個 Portal 也可以從 StockQuote Web服務中檢索最新的股票報價並顯示在同一個 JSP 頁中。
這個 zip 文件包含了所有的源代碼和 DataSource 的 SQL 腳本。它還包含有 Struts Action和 ActionForm類、模型服務類以及用來為發布者與訂購者顯示結果及其源代碼的 JSP 頁。它同時還包含有WSDL 文件以及客戶端源代碼來訪問已發布的 NewsContent Web 服務。
這裡我不再闡述示例代碼的詳細信息了;您想要發現它的複雜性,最好的途徑就是自己去試驗。開始時,我會向您說明應用程序如何將信息內容(存儲在 DataSource中)和股票信息(從 Web 服務處獲得)遞交給 JSP 頁的。
JSP 頁被加載時,它就調用 Action 類,這個類在 MVC 設計模式中充當控制器角色。 Action類通過傳遞預定義的數據訪問對象來調用模型服務類中的 getNews() 方法。(清單 1中所示的一小段 Action 類代碼說明了如何從 Action 類中調用模型服務。)
getNews()方法實現了所有必需的業務邏輯與數據檢索邏輯。一旦從數據源取出了相關數據,模型服務就可以聚集數據訪問對象並將它發送回給 Action類。
清單 1. Action 類的部分代碼
/*
* Create a pre-defined Data Access Object
*/
newsSearchResultVOB = new NewsSearchResult();
/*
* Call Business layer NewsMs's searchNews method passing the NewsCOD
* and get back a Collection of News
*/
newsList = (Vector) newsMs.getNews(newsSearchResultVOB);
/*
* Put the NewsList in the request.
*
*/
request.setAttribute(SystemConstants.NEWS_LIST, newsList);
//Set the newslist in the form
newsFrm.setNewsDetails(newsList);
// Set the NewsForm in the request
request.setAttribute(mapping.getAttribute(), newsFrm);
//return actionForward;
return mapping.findForward("success");
從模型服務處接收到數據訪問對象後, Action類通過傳遞轉給模型服務的同一個數據訪問對象來調用 WSManager類中的 getStocks() 方法。 WSManager類中的 getStocks()方法執行 JAX-RPC 來訂購股票 Web 服務。
從股票 Web 服務獲得的結果要轉變成本地的 schema 並且聚集回到預定義數據訪問對象中去。這個對象從它被調用的地方傳回到 action類。 清單 2 闡明了如何使用 WSManager中的 JAX-RPC來訂購 Web 服務,以及如何將股票 Web 服務的結果轉變成本地 schema 並聚集回到數據訪問對象中去。
清單 2. 訂購 Web 服務及傳送響應
public Vector getStocks() throws Exception {
//Method level variables
Vector stockValues = new Vector();
try {
// create service factory
javax.xml.rpc.ServiceFactory factory =
javax.xml.rpc.ServiceFactory.newInstance();
// define targetNameSpace
String targetNamespace = "http://www.themindelectric.com/"
+ "wsdl/net.xmethods.services.stockquote.StockQuote/";
// define qname
QName serviceName =
new QName(targetNamespace,
"net.xmethods.services.stockquote.StockQuoteService");
// define portname
QName portName =
new QName(targetNamespace,
"net.xmethods.services.stockquote.StockQuotePort");
// define operation name
QName operationName = new QName("urn:xmethods-delayed-quotes",
"getQuote");
//Specify wsdl location
java.net.URL wsdlLocation =
new java.net.URL("http://services.xmethods.net/soap/urn:xmethods-
delayed-quotes.wsdl");
// create service
javax.xml.rpc.Service service =
factory.createService(wsdlLocation, serviceName);
// create call
javax.xml.rpc.Call call =
service.createCall(portName, operationName);
//Populate an array with list of stock names
Vector populatedStockNames = this.getPopulatedList();
//Loop through the populated list, and for each stock get a result
java.util.Iterator i = this.getPopulatedList().iterator();
String stockName = null;
Float result;
com.ddj.wsstruts.valueobject.StockValue stockValue = null;
while(i.hasNext()) {
stockName = (String) i.next();
// invoke the remote web service
result = (Float) call.invoke(new Object[] {stockName});
if(category.isDebugEnabled()) {
category.debug(" The quote for " + stockName + " is: " + result);
}
//Set stock name and stock values in stockValue bean
stockValue = new com.ddj.wsstruts.valueobject.StockValue();
stockValue.setStockName(stockName);
stockValue.setStockValue(result.toString());
//Add the stockValue bean to stockValues vector
stockValues.add(stockValue);
}
}
一旦 Action 類調用完模型服務和 WSManager, ActionForm中的股票值及信息內容域就會被填充。控制就被返回到 JSP頁面,從 ActionForm 獲取所有必需的值並打印 UI.
在本文中,您看到了 Struts架構是如何與 Web 服務相集成的。您也了解了如何使用 Struts組件來提供和預訂 Web服務。本文附帶的簡單應用程序代碼將幫助您深入理解所有這些是如何工作的。
使用此處所闡明的體系結構,您可以開發出這樣的企業應用程序,它非常健壯,很容易維護,而且能很容易地與早期應用程序集成在一起。我希望您將可以開發出更多的關於 Struts 和 Web服務的項目,並看到這種體系結構在您自己的項目中是多麼的有用。
- 下載本文附帶的 zip文件,以開始使用這裡所闡述的體系結構。
- 在 project 的主頁查找更多關於 Struts 框架的信息(由 Apache項目託管)。
- 查看 Malcolm Davis所寫的「Struts,MVC 的一種開放源碼實現」(developerWorks,2001年2月)。雖然這個項目的觀點有點過時了,但對於項目目標與一般的 MVC模式仍然是一個很好的入門介紹。
- 閱讀 Wellie Chao 的「Struts 和 Tiles 輔助基於組件的開發」(developerWorks,2002年6月),以了解更多關於 Struts的信息。
- 查看 BrettMcLaughlin 的「實體 bean 保護」(developerWorks,2002年10月),以了解更多關於 Session Fac,ade模式的信息。
- XMethods是代理服務的一個示例。