本模塊講述了如何使用用于JavaTM 的帶附件的SOAP(SAAJ)和用于XML消息的Java TM API(JAXM)創(chuàng)建能夠發(fā)送和接收消息的客戶端,以及如何部署它們到Sun ONE Application Server上。本模塊包括以下幾節(jié):
SOAP客戶端
本節(jié)講述了SOAP客戶端可以采用的兩種消息模型以及開發(fā)和部署這類客戶端的過程。本節(jié)包括以下主題:
SOAP客戶端消息模型
可以使用以下兩種消息模型建立SOAP客戶端
沒有消息提供者的客戶端
不使用消息提供者的應(yīng)用程序只能交換同步消息。也就是說(shuō),扮演客戶端角色的應(yīng)用程序只能發(fā)送請(qǐng)求-響應(yīng)消息。這種類型的客戶端采用SAAJ API的SOAPConnection方法。下圖演示了在沒有消息提供者的情況下,同步消息如何在發(fā)送者和接收者之間交換。
不使用消息提供者的SOAP消息

不使用消息提供者的客戶端具有以下優(yōu)點(diǎn):
- 可以采用J2SE平臺(tái)編寫應(yīng)用程序。
- 不需要在servlet或J2EE容器中部署應(yīng)用程序。
- 不需要配置消息提供者。
不使用消息提供者的客戶端具有以下局限性:
- 客戶端只能發(fā)送請(qǐng)求-響應(yīng)消息
- 客戶端只能扮演客戶端角色
使用消息提供者的客戶端
如果想要獲得并且保存在任何時(shí)間發(fā)送給你的請(qǐng)求,你必須使用消息提供者。JAXM API提供了使用消息提供者發(fā)送和接收消息的框架。你需要在容器中運(yùn)行客戶端,容器提供了消息基礎(chǔ)結(jié)構(gòu)讓提供者使用。下圖演示了在使用消息提供者的情況 下,異步消息如何在發(fā)送者和接收者之間交換。
使用消息提供者的SOAP消息

使用消息提供者的客戶端具有以下優(yōu)點(diǎn):
- 客戶端能夠扮演客戶端或者服務(wù)角色
- 客戶端能夠切換消息傳遞給提供者
- 在客戶端傳遞消息到最終接收者之前,它能夠發(fā)送消息到一個(gè)或多個(gè)目的地。這些中間的消息接收者被稱為actor,它們?cè)谙⒌腟OAPHeader對(duì)象中被指定。
- 客戶端能夠利用任何提供者支持的SOAP消息協(xié)議和影響消息類型與可靠性的‘服務(wù)質(zhì)量’,以及消息傳遞服務(wù)的質(zhì)量。
注意
Sun ONE Application Server包含了一個(gè)示例JAXM提供者,它演示了如何使用提供者為發(fā)送客戶端激活“發(fā)后不理(fire and forget)”消息。請(qǐng)察看示例文檔獲取關(guān)于如何激活、部署和使用它的全面信息。示例應(yīng)用程序可以從以下位置得到:
install_dir/samples/webservices/jaxm/jaxm-provider/
Sun ONE Application Server的未來(lái)版本將會(huì)包括支持可靠SOAP消息和ebXML消息的JAXM提供者。
SOAP消息
本節(jié)向你介紹SOAP消息的結(jié)構(gòu)和組成部分、如何訪問它們、以及如何處理SOAP消息。本節(jié)講述以下主題:
SOAP消息的組成部分
SOAP消息是一個(gè)包括SOAPEnvelope、一個(gè)可選的SOAPHeader、以及SOAPBody的XML文件。SOAP消息頭包含了使消息在到達(dá)最終目的地之前,能夠被路由到一個(gè)或多個(gè)中間節(jié)點(diǎn)的信息。
SOAP消息的組成部分

這個(gè)圖展示了SOAP消息的結(jié)構(gòu)和組成部分。不同對(duì)象代表了SOAP消息的每一個(gè)部分。
SOAPMessage對(duì)象包括:
- 一個(gè)SOAPPart對(duì)象,其中包括
- 一個(gè)SOAPEnvelope對(duì)象,其中包括
- 一個(gè)空的SOAPHeader對(duì)象 – 可選,包括它是為了方便,因?yàn)榇蠖鄶?shù)消息都要用到它。
- 一個(gè)空的SOAPBody對(duì)象 -可以容納消息的內(nèi)容,還能容納包含了狀態(tài)信息或者消息故障明細(xì)的錯(cuò)誤消息。
- AttachmentPart可能容納普通文本或者圖像文件。
SOAPEnvelope是代表消息的XML文件的根元素。它為消息如何處理、由誰(shuí)處理定義了框架。XML內(nèi)容從SOAPEnvelope開始。
SOAPHeader是添加特性到SOAP消息的基本機(jī)制。它可以容納任意數(shù)目的擴(kuò)展了基礎(chǔ)協(xié)議 的子元素。例如,header子元素可能會(huì)定義認(rèn)證信息、事務(wù)信息、本地信息、等等。處理消息的軟件可以在沒有事先約定的情況下,使用這個(gè)機(jī)制定義誰(shuí)應(yīng)該 處理某個(gè)特性,以及該特性是強(qiáng)制的還是可選的。
body是發(fā)給消息最終接收者的強(qiáng)制信息的容器。SOAP消息還可以容納一個(gè)附件,它不一定非得是XML文件。
訪問消息的元素
當(dāng)創(chuàng)建消息體或附件的時(shí)候,以及處理消息的時(shí)候,你需要訪問消息的組成部分。
SOAPMessage對(duì)象含有一個(gè)SOAPPart對(duì)象。通過message對(duì)象可以得到它。
SOAPPart soapPart = message.getSOAPPart();
然后你可以利用SOAPPart獲得它所含有的SOAPEnvelope對(duì)象。
SOAPEnvelope envelope = soapPart.getEnvelope();
現(xiàn)在你可以利用envelope獲得它的空SOAPHeader和SOAPBody對(duì)象。
SOAPHeader header = envelope.getHeader();
SOAPBody body = envelope.getBody();
SOAPBody對(duì)象最初是空的。
命名空間
XML命名空間是一種限定元素和屬性名稱的方法,目的是消除它們與同一文件中其他名稱之間產(chǎn)生的歧義。一個(gè)名確的XML命名空間聲明采用如下格式:
<prefix:myElement
xmlns:prefix ="URI">
聲明定義prefix作為一個(gè)特定URI的別名。在myElement元素內(nèi),你可以對(duì)任何元素或?qū)傩允褂们熬Y,從而指定元素或?qū)傩詫儆赨RI指定的命名空間。下面的代碼是命名空間聲明的一個(gè)例子。
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
該定義定義了SOAP_ENV作為命名空間http://schemas.xmlsoap.org/soap/envelope/
的別名。
定義了別名之后,可以使用它作為Envelope元素中任何屬性或元素的前綴。
預(yù)定義的SOAP命名空間
當(dāng)使用SAAJ或JAXM構(gòu)造或者消費(fèi)消息的時(shí)候,你有責(zé)任保證正確設(shè)定或處理命名空間,并且丟棄含有錯(cuò)誤命名空間的消息。
創(chuàng)建SOAP消息的時(shí)候使用命名空間
當(dāng)創(chuàng)建SOAP消息的body或header元素的時(shí)候,你必須使用命名空間為元素指定一個(gè)完整的名稱。通過調(diào)用方法SOAPEnvelope.createName可以獲得一個(gè)名稱。
調(diào)用該方法時(shí),可以傳遞一個(gè)本地名稱作為參數(shù),或者可以指定本地名稱、前綴、以及URI。例如,下面的命令行定義了一個(gè)名為bodyName的Name對(duì)象。
Name bodyName = MyEnvelope.createName("TradePrice", "GetLTP", "http://foo.eztrade.com");
這和下面的命名空間聲明作用相同。
<GetLTP:TradePrice xmlns:GetLTP= "http://foo.eztrade.com">
下面的代碼演示了如何創(chuàng)建一個(gè)名稱并把它和SOAPBody元素綁定。注意createName方法的使用和位置。
SoapBody body = envelope.getBody();//get body from envelope
Name bodyName = envelope.createName("TradePrice", "GetLTP", "http://foo.eztrade.com");
SOAPBodyElement gltp = body.addBodyElement(bodyName);
開發(fā)SOAP客戶端
利用SAAJ,客戶端能夠以點(diǎn)對(duì)點(diǎn)的方式創(chuàng)建并且發(fā)送SOAP消息。JAXM為使用消息提供者的 XML消息定義了API。JAXM依賴用于 Java 的帶有附件的 SOAP API(SAAJ),它定義了在Java中操作帶有附件的SOAP消息模型的API。Sun ONE Application Server不包括它所支持的JAXM消息提供者。然而它的確包含了示例應(yīng)用程序,一個(gè)簡(jiǎn)單的JAXM提供者,演示了一個(gè)消息提供者如何處理來(lái)自客戶端的 異步SOAP消息。本節(jié)講述以下主題:
SOAP消息是如何出現(xiàn)的?
當(dāng)消息工廠生產(chǎn)的SOAP消息通過連接被發(fā)送到一個(gè)端點(diǎn)的時(shí)候,SOAP消息就出現(xiàn)了。本節(jié)講述以下主題:
端點(diǎn)
端點(diǎn)標(biāo)識(shí)消息的最終目的地。端點(diǎn)是由URLEndpoint類來(lái)定義的。如果不使用提供者,你可以構(gòu)造或者查找到一個(gè)消息端點(diǎn)。
構(gòu)造端點(diǎn)
你可以通過調(diào)用構(gòu)造函數(shù)或者在名稱服務(wù)中查找來(lái)初始化一個(gè)端點(diǎn)。
以下代碼使用構(gòu)造函數(shù)創(chuàng)建一個(gè)URLEndpoint:
myEndpoint = new URLEndpoint("http://host/myServlet")
使用端點(diǎn)發(fā)送消息
指定端點(diǎn)作為SOAPConnection.call方法的一個(gè)參數(shù),該方法是用來(lái)發(fā)送SOAP消息的。
向多個(gè)端點(diǎn)發(fā)送消息
管理對(duì)象是封裝了針對(duì)提供者的配置和命名信息的對(duì)象。如果使用管理對(duì)象定義端點(diǎn),需要注意的是:可以把該管理對(duì)象綁定到多個(gè)URL——每個(gè)URL都能夠處理到達(dá)的SOAP消息。
以下代碼示例把lookup名稱為myEndpoint的端點(diǎn)綁定到兩個(gè)URL:http://www.myServlet1/
和 http://www.myServlet2/。這個(gè)語(yǔ)法允許你使用SOAP連接發(fā)布SOAP消息到多個(gè)端點(diǎn)。
imqobjmgr add
-t e
-l "cn=myEndpoint"
-o "imqSOAPEndpointList=http://www.myServlet1/
http://www.myServlet2/"
連接
想要利用SAAJ或JAXM發(fā)送SOAP消息,必須分別獲得一個(gè)SOAPConnection 或ProviderConnection。你還可以使用消息隊(duì)列傳輸消息;更多信息請(qǐng)參見Sun ONE消息隊(duì)列開發(fā)人員指南。
SOAP 連接
SOAPConnection允許你直接向遠(yuǎn)程伙伴發(fā)送消息。通過調(diào)用靜態(tài)方法SOAPConnectionFactory.newInstance(),可以容易地得到SOAPConnection對(duì)象。這種類型的連接既不保證可靠性也不保證安全性。
提供者連接
從ProviderConnectionFactory 獲得的ProviderConnection可以創(chuàng)建到特定消息提供者的連接。當(dāng)使用提供者發(fā)送SOAP消息的時(shí)候,消息被傳遞給提供者,然后提供者負(fù)責(zé) 傳遞消息到它的最終目的地,這樣保證了可靠并且安全的消息傳輸。
創(chuàng)建SOAP客戶端
創(chuàng)建SOAP客戶端之前,確定你已經(jīng)設(shè)置了客戶端環(huán)境。關(guān)于設(shè)置客戶端環(huán)境的更多信息,請(qǐng)參見。
如果創(chuàng)建一個(gè)點(diǎn)對(duì)點(diǎn)客戶端,你必須導(dǎo)入SAAJ API的javax.xml.soap程序包。如果創(chuàng)建一個(gè)pub/sub客戶端,需要導(dǎo)入import JAXM API的javax.xml.messaging程序包。除此之外,你還必須導(dǎo)入以下程序包:
import java.net.*;
import java.io.*;
import java.util.*;
import javax.servlet.http.*;
import javax.servlet.*;
import javax.activation.*;
import javax.naming.*;
創(chuàng)建SOAP客戶端并訪問消息包括以下步驟:
獲得連接
單獨(dú)客戶端
不使用消息提供者的客戶端使用SOAPConnection對(duì)象創(chuàng)建連接。使用SoapConnection對(duì)象發(fā)送的消息直接從發(fā)送者到發(fā)送者指定的URL。
必須獲得一個(gè)SOAPConnectionFactory對(duì)象來(lái)創(chuàng)建連接。SAAJ API通過提供SOAPConnectionFactory類的一個(gè)默認(rèn)實(shí)現(xiàn)簡(jiǎn)化了這一過程。以下代碼演示了如何獲得該實(shí)現(xiàn)的一個(gè)實(shí)例:
SOAPConnectionFactory scf = SOAPConnectionFactory. newInstance();
現(xiàn)在,你可以使用scFactory創(chuàng)建SOAPConnection對(duì)象
SOAPConnection con = scf.createConnection();
創(chuàng)建消息
使用MessageFactory對(duì)象來(lái)創(chuàng)建消息。如果想要?jiǎng)?chuàng)建一個(gè)單獨(dú)客戶端,也就是既不使用消息提供者也不在容器中運(yùn)行的客戶端,你可以使用SAAJ API提供的MessageFactory類的實(shí)現(xiàn)。以下代碼演示了如何獲得默認(rèn)消息工廠的一個(gè)實(shí)例,然后用它創(chuàng)建消息:
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage msg = mf.createMessage();
消息創(chuàng)建過程會(huì)完成SOAPPart的創(chuàng)建,它是SOAP 1.1規(guī)范中每個(gè)消息的必要部分。
SOAPPart sp = msg.getSOAPPart();
注意:
通常,使用默認(rèn)的消息工廠創(chuàng)建消息。但是,你也可以編寫自己的消息工廠實(shí)現(xiàn),并且把它插入到系統(tǒng)屬性中,如下所示:
- 通過擴(kuò)展javax.xml.soap.MessageFactory實(shí)現(xiàn)消息工廠類。 javax.xml.soap是在SAAJ API中定義的程序包。
- 通過設(shè)定系統(tǒng)屬性javax.xml.soap.MessageFactory為消息工廠實(shí)現(xiàn)類mypackage.MySOAPMessageFactoryImpl的完全路徑名,指定希望被實(shí)例化的消息工廠類。
關(guān)于SOAP消息結(jié)構(gòu)和組成部分的信息,請(qǐng)參見。
向Header添加內(nèi)容
創(chuàng)建一個(gè)SOAPHeaderElement對(duì)象,從而可以添加內(nèi)容到header中。以下代碼演示了如何使用SOAPEnvelope對(duì)象創(chuàng)建一個(gè)SOAPHeaderElement。
SOAPHeader hdr = envelope.getHeader();
Name headerName = envelope.createName("Purchase Order","PO", "http://www.sonata.com/order");
SOAPHeaderElement headerElement = hdr.addHeaderElement(headerName);
HeaderElement通過Name對(duì)象headerName進(jìn)行標(biāo)識(shí)。AddHeaderElement方法是用來(lái)添加或者創(chuàng)建header元素的。
為了添加內(nèi)容到headerElement,請(qǐng)象以下代碼示例那樣使用addTextNode方法。
headerElement.addTextNode("order");
SOAPHeader對(duì)象包含一個(gè)內(nèi)容為"order"的SOAPHeaderElement對(duì)象。
向消息添加內(nèi)容
你可以向SOAPPart對(duì)象,或者一或多個(gè)AttachmentPart對(duì)象添加內(nèi)容,或者可以向消息的這兩個(gè)部分都添加內(nèi)容。
為了向消息體添加內(nèi)容,請(qǐng)創(chuàng)建一個(gè)SOAPBodyElement對(duì)象并添加一個(gè)使用SOAPElement.addTextNode方法建立的XML元素。下面的代碼演示了如何添加內(nèi)容到消息:
SOAPEnvelope envelope = sp.getSOAPEnvelope();
SOAPBody bdy = envelope.getSOAPBody();
SOAPBodyElement gltp = bdy.addBodyElement(envelope.createName("GetLastTradePrice", "ztrade", "http://wombat.ztrade.com"));
gltp.addChildElement(envelope.createName("symbol","ztrade", "http://wombat.ztrade.com")).addTextNode("SUNW");;
代碼的前三行訪問了SOAPBody對(duì)象body,目的是創(chuàng)建一個(gè)新 SOAPBodyElement對(duì)象并把它添加到body上。CreateName方法需要Name對(duì)象作為參數(shù),用來(lái)指定被添加的 SOAPBodyElement。最后一行添加傳遞給addTextNode方法的XML字符串。
向消息添加一個(gè)附件
向消息添加附件的過程對(duì)于使用或不使用消息提供者的客戶端來(lái)說(shuō)都是一樣的。使用AttachmentPart對(duì)象向消息中添加附件部分。
使用SOAPMessage對(duì)象創(chuàng)建AttachmentPart對(duì)象。SOAPMessage 類含有三個(gè)創(chuàng)建附件的方法。第一個(gè)方法允許你創(chuàng)建一個(gè)沒有內(nèi)容的AttachmentPart。就是說(shuō),以后再使用AttachmentPart的方法 setContent來(lái)添加內(nèi)容到附件。
URL url = new URL(data);
AttachmentPart ap = msg.createAttachmentPart(new DataHandler(url));
SetContent有兩個(gè)參數(shù),對(duì)應(yīng)內(nèi)容的Java對(duì)象以及標(biāo)識(shí)內(nèi)容類型的String對(duì)象。 內(nèi)容是消息的SOAPBody部分,消息有一個(gè)值為"text/xml"的內(nèi)容-類型(Content-Type)header,這是因?yàn)閮?nèi)容只能是 XML格式。在AttachmentPart中,內(nèi)容的類型只能被指定為該對(duì)象能夠容納的任意類型。
每個(gè)AttachmentPart都有一個(gè)或多個(gè)與之相關(guān)的header。setContent 方法中用到的類型就是Content-Type這個(gè)header類型。這是唯一必須具備的header。你還可以設(shè)置其他可選的header,例如 Content-Id和Content-Location。為了方便,JAXM和SAAJ API為Content-type、 Content-Id、和Content-Location這幾個(gè)header提供了get和set方法。這些header在消息擁有多個(gè)附件的時(shí)候,可 以幫助對(duì)附件的訪問。
以下代碼演示了如何使用setContent方法:
String stringContent = "Update address for Sunny Skies " + "Inc., to 10 Upbeat Street, Pleasant Grove, CA 95439";
ap.setContent(stringContent, "text/html");
ap.setContentId("update_address");
msg.addAttachmentPart(ap);
如果你還想附加一個(gè)jpeg圖像,setContent方法的第二個(gè)參數(shù)必須被設(shè)為"image/jpeg"。下面的代碼演示了如何使用setContent方法附加圖片:
AttachmentPart ap2 = msg.createAttachmentPart();
byte[] jpegData = . . .;
ByteArrayInputStream stream = new ByteArrayInputStream(jpegData);
ap2.setContent(stream, "image/jpeg");
msg.addAttachmentPart(ap2);
AttachmentPart的另外兩個(gè)方法允許你創(chuàng)建帶內(nèi)容的AttachmentPart對(duì) 象。其中一個(gè)與AttachmentPart.setContent方法很象。它需要一個(gè)包含內(nèi)容的Java對(duì)象和一個(gè)指定內(nèi)容類型的String作為參 數(shù)。對(duì)象可以是String、stream、 javax.xml.transform.Source對(duì)象、或 javax.activation.DataHandler對(duì)象。
另一個(gè)創(chuàng)建帶內(nèi)容的AttachmentPart對(duì)象的方法需要一個(gè)DataHandler對(duì)象作為輸入?yún)?shù),它是JavaBeans激活框架(JAF)的一部分
以下代碼演示了如何在內(nèi)容中使用DataHandler。首先為想要作為內(nèi)容添加的文件創(chuàng)建一個(gè)java.net.URL對(duì)象。創(chuàng)建DataHandler對(duì)象,即javax.activation.DataHandler 對(duì)象dh,使用URL對(duì)象對(duì)其進(jìn)行初始化,然后把dh傳遞給createAttachmentPart方法。
URL url = new URL("http://greatproducts.com/gizmos/img.jpg");
DataHandler dh = new DataHandler(url);
AttachmentPart ap = msg.createAttachmentPart(dh);
ap.setContentId("gyro_image")
msg.addAttachmentPart(ap);
發(fā)送消息
單獨(dú)客戶端
為了發(fā)送消息,單獨(dú)客戶端使用SOAPConnection的call方法。該方法需要兩個(gè)輸入?yún)?shù),要發(fā)送的消息和消息的目的地,目的地是一個(gè)包含接收者URL的Endpoint對(duì)象。
利用SoapConnection的情況下,使用javax.xml.soap.SOAPConnection.call()發(fā)送消息。
例如:
URL urlEndpoint = new URL(to);
SOAPMessage reply = con.call(msg, urlEndpoint);
從響應(yīng)消息中檢索內(nèi)容
客戶端使用onMessage方法檢索消息內(nèi)容。客戶端通過消息得到envelope,再通過 envelope得到body,從而訪問SOAPBody對(duì)象。訪問SOAPBody對(duì)象是因?yàn)閮?nèi)容存放在該元素中。為了檢索由 Node.addTextNode方法添加的內(nèi)容,請(qǐng)調(diào)用Node.getValue方法。GetValue返回調(diào)用元素的直接子元素的值。為了訪問 bodyElement,需要在body上調(diào)用getChildElement方法。以下代碼演示了如何從響應(yīng)消息中檢索內(nèi)容。
public SOAPMessage onMessage(SOAPMessage message)
{
SOAPEnvelop env = msg.getSOAPPart().getEnvelope();
env getBody()
.addChildElement(env.createName("Response"))
.addTextNode("This is a Response");
return msg;
}
想要從含有附件的消息中檢索內(nèi)容,你需要訪問附件。沒有參數(shù)的情況 下,SOAPMessage.getAttachments方法返回指向所有AttachmentPart對(duì)象的java.util.Iterator對(duì) 象。以下代碼打印出了SOAPMessage對(duì)象消息中每一個(gè)AttachmentPart對(duì)象的內(nèi)容。
java.util.Iterator it = message.getAttachments();
while (it.hasNext()) {
AttachmentPart attachment = (AttachmentPart)it.next();
Object content = attachment.getContent();
String id = attachment.getContentId();
System.out.print("Attachment " + id + " contains: " + content);
System.out.println("");
}
訪問消息的附件部分
當(dāng)收到帶有附件的消息或是希望改變消息附件的時(shí)候,都需要訪問消息的附件。沒有附加信息的 SOAPMesssage.getAttachments方法返回指向消息中所有AttachmentPart對(duì)象的 java.util.Iterator對(duì)象。以下代碼演示了如何訪問附件從而獲得SOAPMessage對(duì)象消息中每個(gè)AttachmentPart對(duì)象 的內(nèi)容。
java.util.Iterator it = msg.getAttachments();
while (it.hasNext()) {
AttachmentPart ap = it.next();
Object content = ap.getContent();
String id = ap.getContentId();
System.out.print("Attachment " + id + " contains: " + content);
System.out.println("");
}
組裝并部署SOAP客戶端
利用JAXM API和SAAJ API創(chuàng)建的應(yīng)用程序被組裝為web應(yīng)用(WAR)或者基于J2EE平臺(tái)的應(yīng)用(EAR)。關(guān)于組裝和部署web應(yīng)用,請(qǐng)參見Sun ONE Application Server開發(fā)人員web應(yīng)用指南。
SOAP 服務(wù)
本節(jié)講述如何編寫SOAP服務(wù)以及如何在SOAP消息中處理異常和錯(cuò)誤。本節(jié)講述以下主題:
創(chuàng)建SOAP服務(wù)
SOAP服務(wù)是SOAP消息的最終接收者,并且被實(shí)現(xiàn)為servlet。要么創(chuàng)建你自己的servlet,要么擴(kuò)展javax.xml.messaging包中的JAXMServlet類。本節(jié)講述了基于JAXMServlet類創(chuàng)建SOAP服務(wù)的過程。
為了創(chuàng)建SOAP服務(wù),你的servlet必須實(shí)現(xiàn)ReqRespListener或者OneWayListener接口。ReqRespListener需要返回一個(gè)回應(yīng)。
public class MyServlet extends JAXMServlet implements ReqRespListener{
...
...
}
public SOAPMessage onMessage(SOAP Message msg)
使用任意借口,實(shí)現(xiàn)一個(gè)叫做onMessage(SOAPMsg)的方法。
以下代碼是使用JAXMServlet 的SOAP消費(fèi)者的完整清單:
public class MyServlet extends JAXMServlet implements ReqRespListener {
public SOAPMessage onMessage(SOAP Message msg) {
//Process message here
}
}
JAXMServlet在使用HTTP POST方法接受消息之后會(huì)調(diào)用onMessage。你就省去了實(shí)現(xiàn)自己的doPost()方法把收到的消息轉(zhuǎn)換成為SOAP消息的麻煩。
OnMessage方法需要分解由servlet傳入的SOAP消息并處理它的內(nèi)容。處理消息包括訪問SOAP消息的組成部分。如果在處理消息過程中出現(xiàn)故障,服務(wù)需要?jiǎng)?chuàng)建SOAP fault對(duì)象并把它發(fā)回到客戶端。關(guān)于處理錯(cuò)誤的更多信息,請(qǐng)參見。
以下代碼演示了SOAP消息的處理:
{http://xml.coverpages.org/dom.html
SOAPEnvelope env = reply.getSOAPPart().getEnvelope();
SOAPBody sb = env.getBody();
// create Name object for XElement that we are searching for Name ElName = env.createName("XElement");
//Get child elements with the name XElement
Iterator it = sb.getChildElements( ElName );
//Get the first matched child element.
//We know there is only one.
SOAPBodyElement sbe = (SOAPBodyElement) it.next();
//Get the value for XElement
MyValue = sbe.getValue(); }
異常和錯(cuò)誤處理
On the client's side, JAXM and SAAJ uses a SOAP exception to handle errors that occur during the generation of the SOAP request or unmarshalling of the response. This section describes the following topics:
在客戶端,JAXM和SAAJ使用SOAP異常來(lái)處理SOAP 請(qǐng)求生成過程中,或者響應(yīng)反編組過程中發(fā)生的錯(cuò)誤。本節(jié)講述以下主題:
錯(cuò)誤處理
服務(wù)器端代碼必須使用SOAPFault對(duì)象處理在反編組請(qǐng)求、處理消息、或是編組響應(yīng)過程中發(fā)生的錯(cuò)誤。SOAPFault接口擴(kuò)展了SOAPBodyElement接口。
在服務(wù)器端,SOAP消息擁有用來(lái)形成錯(cuò)誤報(bào)告的特定元素和格式:SOAP消息的body可以包 含一個(gè)SOAPFault元素來(lái)報(bào)告發(fā)生在請(qǐng)求處理過程中的錯(cuò)誤。在服務(wù)器端創(chuàng)建并且從服務(wù)器發(fā)回到客戶端的SOAP消息包含了SOAPFault對(duì)象, 它報(bào)告了消息生成者沒有預(yù)期到的任何行為。
SOAPFault元素定義了以下四個(gè)子元素
faultcode
標(biāo)識(shí)錯(cuò)誤的代碼。軟件使用該代碼為鑒別錯(cuò)誤提供一個(gè)算法機(jī)制。此元素是必需的。
faultstring
一個(gè)描述錯(cuò)誤代碼所標(biāo)識(shí)的錯(cuò)誤的字符串。該元素提供了為人們無(wú)法理解的錯(cuò)誤提供了一個(gè)解釋。此元素是必需的。
faultactor
指定錯(cuò)誤來(lái)源的URI:誰(shuí)引起了錯(cuò)誤。如果消息沒有通過任何中間站直接發(fā)送給它的最終目的地,該元素不是必需的。如果在中間站發(fā)生了錯(cuò)誤,這個(gè)錯(cuò)誤必須包含一個(gè)faultactor元素。
detail
該元素持有與body元素相關(guān)的特定信息。如果body元素的內(nèi)容不能夠被成功處理,它就必須被給出。因此,如果這個(gè)元素丟失了,客戶端應(yīng)該推斷出body元素已經(jīng)被處理了。除了畸形負(fù)載,這個(gè)元素對(duì)任何錯(cuò)誤都不是必須的,你可以在其他情況下用它來(lái)為客戶端提供附加信息。
預(yù)定義的錯(cuò)誤代碼
SOAP規(guī)范列出了以下四個(gè)預(yù)定義的faultcode值:
VersionMismatch
處理方發(fā)現(xiàn)SOAP envelope元素有一個(gè)不合法的命名空間;也就是說(shuō),SOAPEnvelope元素的命名空間不是http://schemas.xmlsoap.org/soap/envelope/.
MustUnderstand
SOAPHeader元素的一個(gè)直接子元素要么無(wú)法理解,要么接收者不能正確處理。這個(gè)元素的MustUnderstand屬性設(shè)被為1(true)。
Client
消息格式不正確或者沒包含合適的信息。例如,消息沒有包含正確的認(rèn)證或付款信息。客戶端應(yīng)該翻譯這個(gè)代碼從而指定這個(gè)消息在重新發(fā)送之間必須被修改。如果這是一個(gè)返回代碼,SOAPFault對(duì)象應(yīng)該包括一個(gè)detailEntry對(duì)象,它為格式錯(cuò)誤的消息提供附加信息。
Server
該消息由于一些與它的內(nèi)容沒有聯(lián)系的原因而不能被處理。例如,消息的一個(gè)處理者無(wú)法與另一個(gè)上游的、沒有相應(yīng)的消息處理者進(jìn)行通信。或者,服務(wù)器需要訪問的數(shù)據(jù)庫(kù)崩潰了。客戶端應(yīng)該解釋這個(gè)錯(cuò)誤,以指出事務(wù)可以在以后的某個(gè)及時(shí)時(shí)間點(diǎn)成功。
定義SOAP錯(cuò)誤
可以使用SOAPFault對(duì)象的方法為faultcode、 faultstring、和faultctor指定值。以下代碼演示了SOAPFault對(duì)象的創(chuàng)建和faultcode、 faultstring、faultctor屬性的設(shè)定。
SOAPFault fault;
reply = factory.createMessage();
envp = reply.getSOAPPart().getEnvelope(true);
someBody = envp.getBody();
fault = someBody.addFault():
fault.setFaultCode("Server");
fault.setFaultString("Some Server Error");
fault.setFaultActor("http://xxx.me.com/list/endpoint.esp/");
reply.saveChanges();
一旦發(fā)生服務(wù)器錯(cuò)誤,服務(wù)器能夠在對(duì)收到的SOAP消息做出的回應(yīng)中,返回這個(gè)對(duì)象。
以下代碼演示了如何定義一個(gè)detail和detail entry對(duì)象。注意,必須為detail entry對(duì)象創(chuàng)建一個(gè)名稱。
SOAPFault fault = someBody.addFault();
fault.setFaultCode("Server");
fault.setFaultActor("http://foo.com/uri");
fault.setFaultString ("Unkown error");
DetailEntry entry = detail.addEntry(envelope.createName("125detail", "m", "Someuri");
entry.addTextNode("the message cannot contain the string //");
reply.saveChanges();
組裝并部署SOAP服務(wù)
使用JAXM API和SAAJ API創(chuàng)建的應(yīng)用被組裝為web應(yīng)用(WAR)或者基于J2EE平臺(tái)的應(yīng)用(EAR)。關(guān)于組裝和部署web應(yīng)用,請(qǐng)參見Sun ONE Application Server開發(fā)人員web應(yīng)用指南。
客戶端和服務(wù)示例
客戶端和服務(wù)應(yīng)用程序示例被捆綁在Sun ONE Application Server中。這些例子示范如何創(chuàng)建發(fā)送和接收XML消息的服務(wù)和客戶端。你可以在下面的位置找到這些例子:
install_dir/samples/webservices/jaxm
install_dir/imq/demo/jaxm
使用SAAJ 和JAXM的 SOAP客戶端及服務(wù) | 816-7869-10 |