級(jí)別: 初級(jí)
陳亞強(qiáng), 高級(jí)軟件工程師
2003 年 6 月 01 日
本文是本系列的第二篇,前一篇我們介紹了JAXM的開(kāi)發(fā)技術(shù),在這篇里,我將結(jié)合前一篇的案例來(lái)討論JAXM Web服務(wù)的構(gòu)架和設(shè)計(jì)模式。
本文是本系列的第二篇, 前一篇我們介紹了JAXM的開(kāi)發(fā)技術(shù),在這篇里,我將結(jié)合前一篇的案例來(lái)討論JAXM Web服務(wù)的構(gòu)架和設(shè)計(jì)模式。
閱讀本文前您需要以下的知識(shí)和工具:
JavaTM Web Services Developer Pack 1.1,并且會(huì)使用初步使用;
至少會(huì)使用一種EJB容器來(lái)開(kāi)發(fā)、部署EJB,并且會(huì)在客戶(hù)端調(diào)用EJB組件;
對(duì)J2EE平臺(tái)有比較全面的了解;
對(duì)UML比較熟悉。
本文的參考資料見(jiàn) 參考資料
本文的全部代碼在這里 下載
系統(tǒng)構(gòu)架
消息傳送方式
JAXM使用SOAP消息在消息客戶(hù)端和服務(wù)端傳送消息,消息有兩種類(lèi)型,一種是SOAPConnection,另一種是ProviderConnection。前者是一種點(diǎn)對(duì)點(diǎn)的消息發(fā)送模型,后者需要通過(guò)MessageProvider來(lái)把消息傳送到目標(biāo)。它們的消息傳送路徑如圖1所示。
圖1 單向和雙向的消息傳送方式
不使用MessageProvider,可以帶來(lái)一些便利,比如:
客戶(hù)端可以是一般的J2SE程序(本文講述的案例就是如此);
不需要額外的配置。
但是,不使用MessageProvider也有以下的限制:
只能發(fā)送request-response類(lèi)型的消息;
客戶(hù)端只能是客戶(hù)端的角色。
本文的案例采用了點(diǎn)對(duì)點(diǎn)的消息傳送方式,調(diào)用環(huán)境如圖2所示。
圖2 JAXM調(diào)用環(huán)境
整體構(gòu)架
系統(tǒng)體系結(jié)構(gòu)如圖3所示。
圖3 系統(tǒng)體系結(jié)構(gòu)
上圖的分層模型和J2EE應(yīng)用程序的分層模型基本一致,不同的是客戶(hù)端和JAXM Servlet數(shù)據(jù)的通信是封裝成SOAP,但是,它也是HTTP的調(diào)用。
用例
本案例共有三個(gè)用例,它們分別是按名字查找書(shū),按類(lèi)別查找書(shū),查找所有的書(shū)。如圖4所示。
圖4 用例圖
數(shù)據(jù)模型
在數(shù)據(jù)庫(kù)里,圖書(shū)信息用圖5的格式保存。
圖5 數(shù)據(jù)庫(kù)表
為了傳輸數(shù)據(jù)的方便,減少遠(yuǎn)程調(diào)用的次數(shù),特別設(shè)計(jì)了BookVO來(lái)代表圖書(shū)的信息,BookVO是一個(gè)值對(duì)象,如圖6所示。
圖6 BookVO值對(duì)象類(lèi)圖
值對(duì)象設(shè)計(jì)模式在J2EE模式中是非常有名且大量使用的設(shè)計(jì)模式,相信讀者會(huì)很熟悉。我們知道,JAXM Servlet和EJB組件之間傳遞數(shù)據(jù)是通過(guò)對(duì)象來(lái)傳遞的,這個(gè)對(duì)象就是包含有BookVO實(shí)例的java.util.Collection。但是JAXM和客戶(hù)端是通過(guò)SOAP消息來(lái)傳遞的(當(dāng)然,也可以使用序列化的對(duì)象作為附件發(fā)送),為了傳輸圖書(shū)信息,我們就要定義對(duì)應(yīng)的DTD(或者schema)。針對(duì)以上的模型,定義的DTD如例程1所示。
例程1 傳輸圖書(shū)信息的格式(book.dtd)
<!ELEMENT books(book*)>
<!ELEMENT book ( name, publisher, price, author+, category, description ) >
<!ELEMENT name (#PCDATA)>
<!ELEMENT publisher (#PCDATA)>
<!ELEMENT price (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT category (#PCDATA)>
<!ELEMENT description (#PCDATA)>
<!ATTLIST book id CDATA #REQUIRED>
|
業(yè)務(wù)邏輯
業(yè)務(wù)層是EJB組件,這里使用了兩個(gè)EJB組件,一個(gè)是BookServiceFacadeEJB,它是一個(gè)有狀態(tài)會(huì)話(huà)Bean,另一個(gè)是BookEntityEJB,它是一個(gè)實(shí)體Bean,代表了BookEntityTable的持久數(shù)據(jù)。
BookEntityEJB組件類(lèi)圖如圖7所示。
圖7 BookEntityEJB組件的類(lèi)圖
其中,isbn是BookEntityEJB組件的主鍵,BookEntityHome定義了幾個(gè)find方法,它們是:
findAllBook(),查找所有的書(shū),返回的是由BookEntity組成的Collection;
findByCategory(String category),按類(lèi)別查找書(shū),返回的是由BookEntity組成的Collection;
findByName(String name),按書(shū)名查找書(shū),返回的是一個(gè)BookEntity的遠(yuǎn)程引用。
BookServiceFacadeEJB是會(huì)話(huà)門(mén)面,JAXM Servlet通過(guò)它來(lái)和BookEntityEJB交互。它的類(lèi)圖如下:
圖8 BookServiceFacadeEJB組件的類(lèi)圖
同樣,它也定義了幾個(gè)find方法,但是和BookEntityHome接口不同的是,它返回的是包含了BookVO值對(duì)象的Collection,而不是包含了BookEntity遠(yuǎn)程引用的Collection。具體的實(shí)現(xiàn)細(xì)節(jié)請(qǐng)參考源代碼。
EJB組件之間的依賴(lài)關(guān)系如圖9所示。
圖9 EJB組件之間的依賴(lài)關(guān)系
JAXM服務(wù)端
在JAXM 服務(wù)端設(shè)計(jì)了三個(gè)服務(wù)JAXM Servlet,分別對(duì)應(yīng)了圖4中的三個(gè)用例,它們是:
ListAllBook:查找所有的書(shū);
BookDetail:按書(shū)名查找某本特定的圖書(shū);
ListByCategory:按類(lèi)別查找。
它們的建模關(guān)系如圖9所示。
圖9 服務(wù)端JAXM Servlet的類(lèi)圖
每個(gè)JAXM Servlet都有一個(gè)SOAPMessage onMessage(SOAPMessage message)方法,這個(gè)方法在它們接收到SOAP消息時(shí)調(diào)用,可以說(shuō)是客戶(hù)端調(diào)用服務(wù)端的入口。
客戶(hù)端
最終客戶(hù)端是一個(gè)叫BookClientGUI的圖形界面程序,它并不直接和SOAP消息打交道,它是通過(guò)JAXMDelegate類(lèi)來(lái)和服務(wù)端JAXM Servlet進(jìn)行交互的,這里我們簡(jiǎn)單列出它的類(lèi)圖,在接下來(lái)的設(shè)計(jì)模式里將詳細(xì)介紹。
圖10 客戶(hù)端類(lèi)圖
在上圖中,請(qǐng)注意到BookBusiness接口,它是BookClientGUI和JAXMDelegate通信的橋梁,這里也體現(xiàn)了面向接口編程的思想。
設(shè)計(jì)模式
JAXM進(jìn)行Web服務(wù)開(kāi)發(fā)還不是特別普遍,故對(duì)它的設(shè)計(jì)模式的探討還比較少。但是它也有它自己的特點(diǎn),基本上來(lái)說(shuō),它的設(shè)計(jì)模式和J2EE平臺(tái)其它組件設(shè)計(jì)模式是一致的。我們?cè)谑褂肑2EE設(shè)計(jì)模式時(shí),基本上有以下幾點(diǎn)的考慮:
- 減少遠(yuǎn)程調(diào)用的次數(shù)(使用值對(duì)象、值列表組裝器、值對(duì)象組裝器模式)
- 降低組件之間、層(Tier)之間的耦合(使用會(huì)話(huà)門(mén)面、業(yè)務(wù)代表模式)
- 減少服務(wù)查找的復(fù)雜度(使用服務(wù)定位器模式)
- 數(shù)據(jù)的一致訪(fǎng)問(wèn)(使用數(shù)據(jù)訪(fǎng)問(wèn)對(duì)象模式)
- 進(jìn)行異步通信(使用服務(wù)激發(fā)器模式)
JAXM也是J2EE平臺(tái)的一種技術(shù),它當(dāng)然可以使用J2EE核心模式中的任何一種,但是它有自己的特點(diǎn),比如客戶(hù)端和服務(wù)端是通過(guò)SOAP消息進(jìn)行通信,這個(gè)和J2EE平臺(tái)的其它組件之間通信是不同的。在JAXM編程中,為了實(shí)現(xiàn)數(shù)據(jù)(這里是SOAP消息)的一致返回,我們可以使用XML業(yè)務(wù)代表的模式。
JAXM進(jìn)行編程時(shí),數(shù)據(jù)傳遞的特點(diǎn)如圖11所示。
圖11 JAXM數(shù)據(jù)傳輸?shù)奶攸c(diǎn)
從上圖可以看出,客戶(hù)端最終要使用的數(shù)據(jù)是java對(duì)象或者Java的基本數(shù)據(jù)類(lèi)型,而客戶(hù)端和服務(wù)端的通信是通過(guò)SOAP消息格式來(lái)傳輸?shù)模煌瑯樱诜?wù)端,它要調(diào)用業(yè)務(wù)邏輯,也必須使用java對(duì)象或者是java基本數(shù)據(jù)類(lèi)型。這樣就存在數(shù)據(jù)的傳輸和數(shù)據(jù)的使用的矛盾,為了解決這個(gè)矛盾,降低層(Tier)之間的耦合度,使數(shù)據(jù)易于處理,我們可以使用一個(gè)數(shù)據(jù)轉(zhuǎn)換器來(lái)轉(zhuǎn)換數(shù)據(jù)。當(dāng)客戶(hù)端要發(fā)送數(shù)據(jù)時(shí),它使用數(shù)據(jù)轉(zhuǎn)換器把請(qǐng)求數(shù)據(jù)轉(zhuǎn)換成SOAP消息格式;在服務(wù)端,它調(diào)用了業(yè)務(wù)邏輯后,為了使數(shù)據(jù)能在internet上傳輸,它要使用數(shù)據(jù)轉(zhuǎn)換器把調(diào)用結(jié)果封裝成SOAP消息。接下來(lái)我們來(lái)看怎么處理這個(gè)問(wèn)題。
客戶(hù)端模式--JAXM業(yè)務(wù)代表
在客戶(hù)端,通過(guò)使用JAXM業(yè)務(wù)代表,可以降低最終客戶(hù)和SOAP消息的耦合度。系統(tǒng)的結(jié)構(gòu)如下。
圖12 JAXM業(yè)務(wù)代表
JAXM業(yè)務(wù)代表使用數(shù)據(jù)轉(zhuǎn)換器來(lái)轉(zhuǎn)換數(shù)據(jù),業(yè)務(wù)代表直接和Web服務(wù)進(jìn)行交互,它屏蔽了Web服務(wù)請(qǐng)求的復(fù)雜過(guò)程,為客戶(hù)端提供易于使用的接口。
此案例中,具體實(shí)現(xiàn)的類(lèi)圖如下:
圖13 客戶(hù)端類(lèi)圖
圖中的JAXMDelegate為JAXM業(yè)務(wù)代表,它實(shí)現(xiàn)了BookBusiness接口,它是此模式的核心,它實(shí)現(xiàn)的方法是客戶(hù)端可以直接調(diào)用的方法。
BookBusiness接口定義了和最終客戶(hù)端(BookClientGUI)交互的方法,BookBusiness接口如例程2所示。
例程2 BookBusiness接口
package com.hellking.webservice;
import java.util.Collection;
public interface BookBusiness
{
/**
* @return Collection,查詢(xún)所有的書(shū)
*/
public Collection getAllBooks();
/**
* @param name
* @return BookVO
*查詢(xún)某本特定的書(shū)
*/
public BookVO getTheBookDetail(String name);
/**
* @return Collection
*按類(lèi)別查詢(xún)圖書(shū)
*/
public Collection getBookByCategory(String category);
}
|
SOAPToBeanEngine是數(shù)據(jù)轉(zhuǎn)換器,它負(fù)責(zé)把具體的SOAP消息轉(zhuǎn)換成客戶(hù)端可以使用的數(shù)據(jù)。SOAPToBeanEngine實(shí)現(xiàn)了DTOEngine接口,我們看DTOEngine接口的具體代碼,如例程3所示。
例程3 DTOEngine接口
package com.hellking.webservice;
import java.util.Collection;
import javax.xml.soap.SOAPMessage;
public interface DTOEngine
{
public void build();//把SOAP Message轉(zhuǎn)換成Bean(對(duì)象)的具體代碼。
public Collection getResult();//返回轉(zhuǎn)換結(jié)果。
public void init(SOAPMessage msg);//初始化,msg為要轉(zhuǎn)換的信息。
}
|
以上三個(gè)方法是每個(gè)把SOAP消息轉(zhuǎn)換成Java對(duì)象的數(shù)據(jù)轉(zhuǎn)換器(如SOAPToBeanEngine)都必須實(shí)現(xiàn)的方法。實(shí)際上,這里的SOAPToBeanEngine只能轉(zhuǎn)換BookVO相關(guān)的信息,如果要把此模式的框架設(shè)計(jì)得更加完美,還需進(jìn)一步抽象,比如抽象到只要傳入相關(guān)的值對(duì)象類(lèi)(BookVO.class)和SOAP Message就能轉(zhuǎn)換成對(duì)應(yīng)的Bean結(jié)果集。
當(dāng)客戶(hù)端(BookClientGUI)發(fā)出一請(qǐng)求時(shí),它調(diào)用JAXMDelegate對(duì)應(yīng)的方法,JAXMDelegate根據(jù)請(qǐng)求構(gòu)造對(duì)應(yīng)的SOAP消息,然后把消息發(fā)送到服務(wù)端(如ListByCategory Servlet),服務(wù)端根據(jù)客戶(hù)的請(qǐng)求做出對(duì)應(yīng)的處理,并把處理結(jié)果返回到JAXMDelegate,JAXMDelegate使用SOAPToBeanEngine把返回的SOAP Message轉(zhuǎn)化成Java對(duì)象(如值Bean),最后返回給客戶(hù)端(BookClientGUI),BookClientGUI再把獲得的數(shù)據(jù)進(jìn)行處理后顯示。
假如客戶(hù)端要按類(lèi)別查詢(xún)圖書(shū)信息,我們來(lái)看下一個(gè)順序圖,如圖14所示。
圖14 按類(lèi)別查詢(xún)圖書(shū)客戶(hù)端順序圖
JAXMDelegate是此模式的核心,我們來(lái)看一下它的代碼,如例程4所示。
例程4 JAXMDelegate的部分代碼
package com.hellking.webservice;
import java.net.*;
import java.io.*;
import java.util.*;
import javax.xml.soap.*;
public class JAXMDelegate implements BookBusiness
{
SOAPConnection con =null;//到服務(wù)端的連接
EndpointLocator locator=new EndpointLocator();//服務(wù)定位器
Collection allbook;//cache
DTOEngine dto;//數(shù)據(jù)轉(zhuǎn)換對(duì)象
public JAXMDelegate()
{
allbook=new ArrayList();
dto=new SOAPToBeanEngine();
try
{
SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance();
con = scf.createConnection();//生成一個(gè)用于SOAP調(diào)用的連接
}
catch(Exception e)
{
e.printStackTrace();
}
}
//構(gòu)造SOAP消息
public SOAPMessage createMessage(String target,String name,String category)
{
try
{
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage msg = mf.createMessage();
SOAPPart sp = msg.getSOAPPart();
SOAPEnvelope envelope = sp.getEnvelope();
//SOAPHeader hdr = envelope.createSOAPHeader();
//AttachmentPart attachment = message.createAttachmentPart();
SOAPBody body = envelope.getBody();
Name bodyName=envelope.createName(
"books",target,"http://hellking.webservice.com");
SOAPBodyElement gpp=body.addBodyElement(bodyName);
//如果category不空,那么構(gòu)建一個(gè)按類(lèi)別查找的SOAP消息
if(category!=null)
{
gpp.addChildElement("category").addTextNode(category);
}
//如果name不空,那么構(gòu)建一個(gè)按圖書(shū)名字查找的SOAP消息
if(name!=null)
{
gpp.addChildElement("name").addTextNode(name);
}
msg.saveChanges();
//msg.writeTo(new FileOutputStream("e://d.msg"));
return msg;
}
catch(Exception e)
{
e.printStackTrace();
return null;//一般要進(jìn)行錯(cuò)誤處理,這里省略
}
}
//按類(lèi)別查找書(shū),業(yè)務(wù)代表方法
public Collection getBookByCategory(String category)
{
try
{
SOAPMessage msg=createMessage("GetBookByCategory",null,category);
String endpoint=locator.getBookByCategory_Endpoint();
SOAPMessage reply=con.call(msg,new URL(endpoint));
reply.writeTo(System.out);
dto.init(reply);//初始化數(shù)據(jù)轉(zhuǎn)換器
return dto.getResult();//返回?cái)?shù)據(jù)轉(zhuǎn)換結(jié)果
}
catch(Exception ex)
{
ex.printStackTrace();
return null; //一般要進(jìn)行錯(cuò)誤處理,這里省略。
}
}
//查詢(xún)所有的圖書(shū),業(yè)務(wù)代表方法
public Collection getAllBooks()
{
/**
*allbook為JAXMDelegate的cache,由于Web服務(wù)調(diào)用代價(jià)比較高,
*故使用它來(lái)減少不必要的遠(yuǎn)程調(diào)用。如果allbook為空,那么調(diào)用對(duì)應(yīng)的Web服務(wù)
*來(lái)獲得數(shù)據(jù),并且把調(diào)用結(jié)果保存在allbook中,如果不為空,那么直接返回allbook
*中的數(shù)據(jù)。
*/
if(allbook.size==0)
{
try
{
SOAPMessage msg=createMessage("GetAllBooks",null,null);
String endpoint=locator.getAllBooks_Endpoint();
SOAPMessage reply=con.call(msg,new URL(endpoint));
reply.writeTo(new FileOutputStream("e://out.msg"));
dto.init(reply); //初始化數(shù)據(jù)轉(zhuǎn)換器
Collection re=dto.getResult(); //獲得轉(zhuǎn)換結(jié)果
allbook=re;
return re; //返回?cái)?shù)據(jù)轉(zhuǎn)換結(jié)果
}
catch(Exception e)
{
e.printStackTrace();
return null; //一般要進(jìn)行錯(cuò)誤處理,這里省略
}
}
else
return allbook;
}
//按圖書(shū)名字查找某本圖書(shū),業(yè)務(wù)代表方法
public BookVO getTheBookDetail(String name)
{
try
{
SOAPMessage msg=createMessage("GetBookDetail",name,null);
String endpoint=locator.getTheBookDetail_Endpoint();
SOAPMessage reply=con.call(msg,new URL(endpoint));
reply.writeTo(System.out);
dto.init(reply); //初始化數(shù)據(jù)轉(zhuǎn)換器
Collection ret=dto.getResult();
if(ret.size()==1)
{
return (BookVO)ret.iterator().next();
}
else
return null;
}
catch(Exception e)
{
e.printStackTrace();
return null; //一般要進(jìn)行錯(cuò)誤處理,這里省略
}
}
}
|
 |
服務(wù)端模式
服務(wù)端的模式和客戶(hù)端的模式基本一樣,只是處理過(guò)程相反。服務(wù)端從客戶(hù)端接收到SOAP消息后,然后讀取參數(shù),調(diào)用對(duì)應(yīng)的業(yè)務(wù)方法,然后使用SOAPToBeanEngine來(lái)把調(diào)用的結(jié)果轉(zhuǎn)換成SOAP消息返回。
如圖15所示是相應(yīng)的數(shù)據(jù)轉(zhuǎn)換模型。
圖15所示是相應(yīng)的數(shù)據(jù)轉(zhuǎn)換模型
在服務(wù)端,數(shù)據(jù)轉(zhuǎn)換器負(fù)責(zé)把對(duì)象轉(zhuǎn)換成SOAP消息,這里和客戶(hù)端是相反的。服務(wù)端類(lèi)圖如下。
圖16 服務(wù)端類(lèi)圖
在圖16中,OTDEngine接口定義了把Bean轉(zhuǎn)換成SOAP消息的方法,如例程5所示。
例程5 OTDEngine接口定義的方法
package com.hellking.webservice;
import javax.xml.soap.*;
import java.util.Collection;
public interface OTDEngine
{
public void build();//構(gòu)造SOAP消息
public SOAPMessage getResult();//返回結(jié)果
public void init(Collection c,String type);//初始化
}
|
OTDEngine定義了把Bean轉(zhuǎn)換成SOAP消息需要的方法:build()、init()、getResult()。
XMLBusinessDelegate是此模式的核心,它調(diào)用業(yè)務(wù)邏輯,并且使用BeanToSOAPEngine來(lái)轉(zhuǎn)換結(jié)果。我們來(lái)看它的部分代碼,如例程6所示。
例程6 XMLBusinessDelegate部分代碼
package com.hellking.webservice;
import javax.naming.*;
import com.hellking.webservice.ejb.*;
import java.util.*;
import java.rmi.*;
import javax.xml.messaging.*;
import javax.xml.soap.*;
public class XMLBusinessDelegate
{
InitialContext init=null;
BookServiceFacadeHome facadeHome;
OTDEngine otd;
public XMLBusinessDelegate()throws NamingException
{
init=this.getInitialContext();
otd=new BeanToSOAPEngine();
}
public static InitialContext getInitialContext()
throws javax.naming.NamingException
{
Properties p = new Properties();
//… p.put(XXX,XXX)
return new javax.naming.InitialContext(p);
}
//查找所有的圖書(shū)
public SOAPMessage listAllBook()
{
try
{
//查找業(yè)務(wù)組件à調(diào)用業(yè)務(wù)邏輯à構(gòu)造SOAP消息à返回消息。
Object objref = init.lookup("ejb/bookservicefacade");
facadeHome = (BookServiceFacadeHome)
javax.rmi.PortableRemoteObject.narrow(objref, BookServiceFacadeHome.class);
Collection result=facadeHome.create().getAllBook();
System.out.println(result.size());
otd.init(result,"GetAllBooks");//初始化BeanToSOAPEngine
SOAPMessage ret=otd.getResult();//獲得結(jié)果
return ret;
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
//按Category查找圖書(shū)
public SOAPMessage listByCategory(String category)
{
try
{
//查找業(yè)務(wù)組件à調(diào)用業(yè)務(wù)邏輯à構(gòu)造SOAP消息à返回消息。
Object objref = init.lookup("ejb/bookservicefacade");
facadeHome = (BookServiceFacadeHome)
javax.rmi.PortableRemoteObject.narrow(objref, BookServiceFacadeHome.class);
Collection result=facadeHome.create().findByCategory(category);
otd.init(result,"GetBookByCategory");//初始化BeanToSOAPEngine
SOAPMessage ret=otd.getResult();//獲得結(jié)果
return ret; //返回結(jié)果
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
//查詢(xún)某本特定的圖書(shū)。
public SOAPMessage getBookDetail(String name)
{
try
{
//查找業(yè)務(wù)組件à調(diào)用業(yè)務(wù)邏輯à構(gòu)造SOAP消息à返回消息。
Object objref = init.lookup("ejb/bookservicefacade");
facadeHome = (BookServiceFacadeHome)
javax.rmi.PortableRemoteObject.narrow(objref, BookServiceFacadeHome.class);
Collection result=facadeHome.create().getBookDetail(name);
otd.init(result,"GetBookDetail");
SOAPMessage ret=otd.getResult();
return ret;
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
…
}
|
假如客戶(hù)端傳來(lái)要按類(lèi)別查詢(xún)圖書(shū)信息,ListByCategory Servlet將調(diào)用XMLBusinessDelegate 的listByCategory(String category)方法,XMLBusinessDelegate查找BookServiceFacadeHome接口,生成BookServiceFacade應(yīng)用,調(diào)用getBookDetail(name);方法,然后初始化OTDEngine,最后調(diào)用getResult()方法來(lái)返回結(jié)果。順序圖如圖17所示。
圖17 按類(lèi)別查找圖書(shū)的服務(wù)端順序圖
總結(jié)
本篇結(jié)合具體的案例介紹了JAXM Web服務(wù)開(kāi)發(fā)的體系結(jié)構(gòu)和設(shè)計(jì)模式。數(shù)據(jù)轉(zhuǎn)換在設(shè)計(jì)中占有很大的分量,總的來(lái)說(shuō),從客戶(hù)端發(fā)出的數(shù)據(jù)要經(jīng)過(guò)以下途徑:
java數(shù)據(jù)類(lèi)型àSOAP請(qǐng)求消息àjava數(shù)據(jù)類(lèi)型à業(yè)務(wù)邏輯返回的java數(shù)據(jù)類(lèi)型àSOAP相應(yīng)消息àjava數(shù)據(jù)類(lèi)型
業(yè)務(wù)代表模型在以上數(shù)據(jù)轉(zhuǎn)換和業(yè)務(wù)處理起著重要的作用。