構(gòu)建 SOAP 服務(wù)
如果您覺(jué)得構(gòu)建 Web 服務(wù)客戶機(jī)的過(guò)程相當(dāng)簡(jiǎn)單,事實(shí)的確如此。而就很多方面而言,構(gòu)建服務(wù)的過(guò)程也同樣簡(jiǎn)單。
總體過(guò)程
創(chuàng)建 Axis2 Web 服務(wù)的整個(gè)過(guò)程涉及以下步驟:
- 創(chuàng)建服務(wù)清單
- 創(chuàng)建類
- 將其打包為 Axis 存檔文件
- 將 Axis 存檔文件上載到 Axis2 Web 應(yīng)用程序
- 重新啟動(dòng)服務(wù)器(如果有必要)
這就是全部步驟。讓我們首先從服務(wù)清單開(kāi)始。
創(chuàng)建清單
服務(wù)清單告知 Axis2 應(yīng)用程序(就更大的范圍而言,應(yīng)用服務(wù)器)哪個(gè)請(qǐng)求與哪個(gè)類對(duì)應(yīng)。例如,可以如清單 22 中所示的那樣指定兩個(gè)服務(wù)函數(shù)。
清單 22. 在清單中指定兩個(gè)服務(wù)函數(shù)
<service name="CMSService">
<description>
This is a sample Web Service for the newspaper's
Content Managment System.
</description>
<parameter name="ServiceClass" locked="false"
>CMSService</parameter>
<operation name="getNumberOfArticles">
<messageReceiver class=
"org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
</operation>
<operation name="addArticle">
<messageReceiver class=
"org.apache.axis2.receivers.RawXMLINOnlyMessageReceiver"/>
</operation>
</service>
|
首先,定義服務(wù),提供其名稱和描述,并指定實(shí)際為請(qǐng)求服務(wù)的類。接下來(lái),定義實(shí)際的操作。請(qǐng)注意,此示例指定了兩種不同類型的 messageReceiver
。第一個(gè) RawXMLINOutMessageReceiver
用于傳統(tǒng)的請(qǐng)求/響應(yīng)服務(wù)。第二個(gè) RawXMLINOnlyMessageReceiver
用于單向消息。操作的名稱與有效負(fù)載的根元素以及要執(zhí)行的方法對(duì)應(yīng)。
將此文件保存為 services.xml。
接下來(lái),讓我們創(chuàng)建實(shí)際的應(yīng)用程序。
創(chuàng)建應(yīng)用程序
讓我們首先創(chuàng)建模擬前面看到的 echo
函數(shù)的類(將直接返回原始有效負(fù)載的副本),如清單 23 中所示。
清單 23. CMSService 類
import org.apache.axis2.om.OMElement;
import javax.xml.stream.XMLStreamException;
public class CMSService {
public OMElement getNumberOfArticles(OMElement element)
throws XMLStreamException {
element.build();
element.detach();
return element;
}
}
|
要編譯此應(yīng)用程序,請(qǐng)確保 <axis2_home>/lib 中的所有 *.jar 文件都在您的 CLASSPATH 上。
此應(yīng)用程序相當(dāng)簡(jiǎn)單,僅包含一個(gè)與 getNumbereOfArticles
操作對(duì)應(yīng)的類。此函數(shù)和任何要作為操作的函數(shù)一樣,接收單個(gè) OMElement
參數(shù)(表示有效負(fù)載)。此處,您將首先使用 build()
方法來(lái)確定已接收到所有數(shù)據(jù)——AXIOM 使用一個(gè) pull 方法訪問(wèn)數(shù)據(jù)——然后將元素從其當(dāng)前樹(shù)中分離,以便能夠?qū)⑵浞祷亍?/p>
如果喜歡冒險(xiǎn),可以自由地部署服務(wù)和訪問(wèn)服務(wù),以訪問(wèn)服務(wù)并查看結(jié)果。應(yīng)該看到與清單 24 中所示類似的結(jié)果輸出。
清單 24. CMSService 類響應(yīng)
<cms:getNumberOfArticles><cms:category>classifieds</cms:category></cms:
getNumberOfArticles>
|
接下來(lái)讓我們了解如何實(shí)際處理數(shù)據(jù)。
提取有效負(fù)載
為了從有效負(fù)載提取信息,將使用與 DOM 非常類似的技術(shù)來(lái)對(duì)接收到的有效負(fù)載元素進(jìn)行操作(請(qǐng)參見(jiàn)清單 25)。
清單 25. 提取有效負(fù)載信息
...
import javax.xml.stream.XMLStreamException;
public class CMSService {
public OMElement getNumberOfArticles(OMElement element)
throws XMLStreamException {
element.build();
element.detach();
String rootName = element.getLocalName();
OMElement categoryElement = element.getFirstElement();
String categoryElementName = categoryElement.getLocalName();
String categoryValue = childElement.getText();
return element;
}
}
|
請(qǐng)記住,有效負(fù)載的根是 getNumberOfArticles
函數(shù)接收的元素。在此情況下,將提取元素的名稱,然后移動(dòng)到第一個(gè)元素子項(xiàng)(與第一個(gè)子項(xiàng)不同,后者可能是空格文本節(jié)點(diǎn))并提取其名稱和值。請(qǐng)注意,使用的是 getText()
方法來(lái)提取實(shí)際上是 category 元素的文本節(jié)點(diǎn)子項(xiàng)的值。這無(wú)疑非常簡(jiǎn)捷!
創(chuàng)建并返回響應(yīng)
最后,將需要使用從請(qǐng)求的有效負(fù)載提取數(shù)據(jù)來(lái)創(chuàng)建響應(yīng)。在本例中,將從第二個(gè)函數(shù)(在實(shí)際應(yīng)用程序中,該函數(shù)將進(jìn)行一些其他的工作)提供響應(yīng)(請(qǐng)參見(jiàn)清單 26)。
清單 26. 創(chuàng)建響應(yīng)
...
import javax.xml.stream.XMLStreamException;
public class CMSService {
public OMElement getNumberOfArticles(OMElement element)
throws XMLStreamException {
element.build();
element.detach();
String rootName = element.getLocalName();
OMElement childElement = element.getFirstElement();
String childName = childElement.getLocalName();
String categoryValue = childElement.getText();
SOAPFactory factory = OMAbstractFactory.getSOAP12Factory();
OMNamespace namespace = factory.createOMNamespace(
"http://daily-moon.com/cms/", "resp");
OMElement resultElem = factory.createOMElement(
"numberOfArticles",namespace);
String actualValue =
(articleCount(categoryValue)).toString();
resultElem.setText(actualValue);
return resultElem;
}
private Integer articleCount(String catId){
//Perform some function such as searching the CMS
//database, and return the actual value. For our
//purposes, you'll hardcode it.
return new Integer(42);
}
}
|
首先,創(chuàng)建將用于創(chuàng)建所有其他對(duì)象的工廠,然后創(chuàng)建將添加到響應(yīng)的有效負(fù)載的命名空間。接下來(lái),創(chuàng)建實(shí)際結(jié)果元素,在本例中為名為 numberOfArticles
的元素。
numberOfArticles
元素的內(nèi)容將為 articleCount()
函數(shù)返回的一個(gè)數(shù)字,在本例中,該函數(shù)可以為任何內(nèi)容。在實(shí)際的應(yīng)用程序中,將進(jìn)行所需進(jìn)行的任何工作來(lái)獲取此數(shù)據(jù)。獲取了此數(shù)據(jù)后,會(huì)將其設(shè)置為 numberOfArticles
元素的內(nèi)容,并直接返回該元素。
現(xiàn)在剩下的就是部署服務(wù)了。
部署服務(wù)
為了部署服務(wù),需要?jiǎng)?chuàng)建一個(gè) Axis 存檔文件。此文件和 *.jar 或 *.war 文件類似,實(shí)際是使用特殊文件擴(kuò)展名(在本例中使用的是 .aar)的 zip 文件。請(qǐng)按照以下步驟創(chuàng)建此文件:
- 將 <AXIS2_HOME>/lib 目錄中的所有文件添加到 CLASSPATH 并編譯 CMSService.java 文件。
- 在與 CMSService.class 文件相同的目錄中創(chuàng)建名為 META-INF 的新目錄。
- 從包含 CMSService.class 文件的目錄中發(fā)出以下命令:<code type="section" width="100"> jar cvf CMSService.aar ./* </code> 應(yīng)該看到與以下類似的結(jié)果:<code type="section" width="100"> added manifest adding:CMSService.class(in = 513) (out= 330)(deflated 35%) adding:CMSService.java(in = 328) (out= 182)(deflated 44%) ignoring entry META-INF/ adding:META-INF/services.xml(in = 391) (out= 229)(deflated 41%) </code>
- 使用安裝示例服務(wù)中列出的步驟將此服務(wù)添加到服務(wù)器上。(如果看到 Web 接口上有 Servlet 錯(cuò)誤,請(qǐng)確保登錄到了 Axis2 應(yīng)用程序。如果會(huì)話已過(guò)期,應(yīng)用程序?qū)⒉灰欢〞?huì)通知您,而可能會(huì)直接顯示錯(cuò)誤。)
- 如果有必要,請(qǐng)重新啟動(dòng) Geronimo。(將可能不必在添加服務(wù)后進(jìn)行此操作,但在進(jìn)行更改后可能必須這樣做。)
如果單擊 View services 鏈接,應(yīng)該看到與圖 4 中所示類似的內(nèi)容。
圖 4. 可用服務(wù)

?
訪問(wèn)服務(wù)
現(xiàn)在已經(jīng)完成了服務(wù)構(gòu)建,接下來(lái)要通過(guò)客戶機(jī)對(duì)其進(jìn)行訪問(wèn)。對(duì)前面創(chuàng)建的 ClassifiedClient.java 文件進(jìn)行以下更改(請(qǐng)參見(jiàn)清單 27)。
清單 27. 修改 ClassifiedClient
...
public class ClassifiedClient {
private static EndpointReference targetEPR =
new EndpointReference(
"http://localhost:8080/axis2/services/CMSService");
public static OMElement getEchoOMElement() {
SOAPFactory fac = OMAbstractFactory.getSOAP12Factory();
OMNamespace omNs = fac.createOMNamespace(
"http://daily-moon.com/cms", "cms");
OMElement method = fac.createOMElement("getNumberOfArticles", omNs);
OMElement value = fac.createOMElement("category", omNs);
value.addChild(fac.createText(value, "classifieds"));
method.addChild(value);
return method;
}
public static void main(String[] args) {
try {
OMElement payload = ClassifiedClient.getEchoOMElement();
Options options = new Options();
options.setTo(targetEPR);
options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
ServiceClient sender = new ServiceClient();
sender.setOptions(options);
OMElement result = sender.sendReceive(payload);
String response = result.getText();
System.out.println("There are "+response+" classifieds at the moment.");
} catch (Exception e) { //(XMLStreamException e) {
System.out.println(e.toString());
}
}
}
|
編譯并運(yùn)行了此應(yīng)用程序后,應(yīng)看到清單 28 中所示的響應(yīng)。
清單 28. ClassifiedClient 響應(yīng)
There are 42 classifieds at the moment.
|
單向服務(wù)
繼續(xù)討論之前,讓我們了解一下處理單向服務(wù)(而非請(qǐng)求/響應(yīng)服務(wù))時(shí)涉及到的不同之處。
服務(wù)
創(chuàng)建單向服務(wù)非常簡(jiǎn)單。此過(guò)程與創(chuàng)建請(qǐng)求/響應(yīng)服務(wù)完全類似,至少不會(huì)實(shí)際返回任何內(nèi)容。例如,可以為 CMSService
類創(chuàng)建 addArticle
操作,如圖 29 中所示。
清單 29. CMSServiceclass 中的 addArticle 操作...
private Integer articleCount(String catId){
...
}
public void addArticle(OMElement element)
throws XMLStreamException{
element.build();
System.out.println(element);
}
}
|
在 services.xml 文件中,將 addArticle
操作指定為“in only”操作,因此不會(huì)等待返回任何內(nèi)容,但即使這樣,也能看到會(huì)實(shí)際發(fā)生一些事項(xiàng),會(huì)在命令行輸出接收到的有效負(fù)載。您將在 Geronimo 窗口中看到此信息。
在實(shí)際應(yīng)用程序中,此方法將從有效負(fù)載提取信息,并會(huì)實(shí)際添加到某種類型的數(shù)據(jù)庫(kù)或其他存儲(chǔ)庫(kù)。
客戶機(jī)
此服務(wù)的客戶機(jī)也與請(qǐng)求/響應(yīng)服務(wù)所使用的服務(wù)類似(請(qǐng)參見(jiàn)清單 30)。
清單 30. 創(chuàng)建客戶機(jī)
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.om.OMElement;
import org.apache.axis2.SOAP.SOAPFactory;
import org.apache.axis2.om.OMAbstractFactory;
import org.apache.axis2.om.OMNamespace;
public class AddArticleClient {
private static EndpointReference targetEPR =
new EndpointReference(
"http://localhost:8080/axis2/services/CMSService");
private static OMElement getOMElement(){
SOAPFactory fac = OMAbstractFactory.getSOAP12Factory();
OMNamespace omNs = fac.createOMNamespace(
"http://daily-moon.com", "cms");
OMElement method = fac.createOMElement("addArticle", omNs);
OMElement category = fac.createOMElement("category", omNs);
category.setText("classifieds");
OMElement subcategory =
fac.createOMElement("subcategory", omNs);
category.setText("wantads");
OMElement adtext = fac.createOMElement("article", omNs);
adtext.setText("Do you have good head for numbers"+
" and a great deal of patience? Do you like"+
" to sit for hours sorting objects by their"+
" size? If so, then you could be the"+
" next goober counter in the world famous"+
" Murphy Brothers peanut factory. "+
" Willingness to dress up as our mascot"+
" helpful, but not required.");
method.addChild(category);
method.addChild(subcategory);
method.addChild(adtext);
return method;
}
public static void main(String[] args) {
try {
OMElement payload = AddArticleClient.getOMElement();
ServiceClient serviceClient = new ServiceClient();
Options options = new Options();
serviceClient.setOptions(options);
options.setTo(targetEPR);
serviceClient.fireAndForget(payload);
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
}
}
}
|
盡管有效負(fù)載不同,但正如您在 getOMElement()
方法中看到的,編程方面目前的唯一真正的更改是使用 fireAndForget()
方法替代 sendReceive()
方法。此方法并不會(huì)返回響應(yīng)。
如果運(yùn)行此客戶機(jī),應(yīng)該在 Geronimo 窗口中看到與圖 5 中所示類似的輸出。
圖 5. 命令行輸出
posted on 2006-12-29 18:39
SIMONE 閱讀(844)
評(píng)論(0) 編輯 收藏 所屬分類:
AXIS 、
JAVA