簡介: 在本篇技巧文章中,作者兼開發人員 Nicholas Chase 向您示範如何使用用於 XML 訊息傳遞的 Java API(Java API for XML Messaging (JAXM))簡化建立和發送 SOAP 訊息的過程。
Web 服務的基礎在於以標準格式發送和接收訊息以便使所有系統都能理解。通常,那種格式是簡易物件存取通訊協定 (SOAP)(Simple Object Access Protocol (SOAP))。SOAP 訊息可以手工產生和發送,但是用於 XML 訊息傳遞的 Java API(JAXM)使許多必需步驟(如建立串連或建立並發送實際訊息)自動化。這篇技巧文章記錄了一個同步 SOAP 訊息的建立和發送。
這個過程包含五個步驟:
- 建立 SOAP 串連
- 建立 SOAP 訊息
- 填充訊息
- 發送訊息
- 檢索應答
JAXM 可以作為 Java XML Pack(2002 年春季版)的一部分和 Java Web Services Developer Pack EA2(請參閱 參考資料)的一部分而獲得。後者還包含了一份 Tomcat Web 服務器以及樣本應用程式的副本。那些樣本 Web 服務之一作為本技巧文章中 SOAP 訊息的目的地,這個例子中實際服務的內容和功能卻不是很重要。
SOAP 訊息結構
一個基本的 SOAP 訊息由包含兩個主要部分(前序和主體)的封套組成。應用程式決定如何使用這些部分,但整個訊息必須遵循特定的 XML 結構,例如:
樣本 SOAP 訊息
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"> <soap-env:Header/> <soap-env:Body> <cal:schedule xmlns:cal="http://www.example.com/calendar"> <cal:newitem> <cal:eventDate>4/10/2002</cal:eventDate> <cal:title>Fun With Frogs</cal:title> </cal:newitem> </cal:schedule> </soap-env:Body></soap-env:Envelope> |
在這個例子中,前序為空白,而主體包含目的地為一個日曆應用程式的資訊。
請注意這個訊息的結構。Envelope 包含 Header 和 Body 元素,而三者全都是 http://schemas.xmlsoap.org/soap/envelope/ 名稱空間的一部分。整個訊息將通過一個 SOAP 串連發送到一個 Web 服務中。
回頁首
建立串連和訊息
第一步是建立整個類和串連:
建立串連
import javax.xml.soap.SOAPConnectionFactory;import javax.xml.soap.SOAPConnection;public class SOAPTip { public static void main(String args[]) { try { //First create the connection SOAPConnectionFactory soapConnFactory = SOAPConnectionFactory.newInstance(); SOAPConnection connection = soapConnFactory.createConnection(); //Close the connection connection.close(); } catch(Exception e) { System.out.println(e.getMessage()); } }} |
SOAP 訊息可以通過使用 SOAPConnection 直接發送,或使用訊息傳遞提供者間接發送。在這個例子中,應用程式通過使用工廠(factory)建立 SOAPConnection 對象。
工廠也建立訊息本身:
建立訊息對象
import javax.xml.soap.SOAPConnectionFactory;import javax.xml.soap.SOAPConnection;import javax.xml.soap.MessageFactory;import javax.xml.soap.SOAPMessage;import javax.xml.soap.SOAPPart;import javax.xml.soap.SOAPEnvelope;import javax.xml.soap.SOAPBody;public class SOAPTip { public static void main(String args[]) { try { //First create the connection SOAPConnectionFactory soapConnFactory = SOAPConnectionFactory.newInstance(); SOAPConnection connection = soapConnFactory.createConnection(); //Next, create the actual message MessageFactory messageFactory = MessageFactory.newInstance(); SOAPMessage message = messageFactory.createMessage(); //Create objects for the message parts SOAPPart soapPart = message.getSOAPPart(); SOAPEnvelope envelope = soapPart.getEnvelope(); SOAPBody body = envelope.getBody(); //Close the connection connection.close(); } catch(Exception e) { System.out.println(e.getMessage()); } }} |
首先,通過使用 MessageFactory 來建立訊息本身。這個訊息已包含如 envelope 和 header 等基本部分的空白版本。 SOAPPart 包含envelope ,而 envelope 包含主體。同時建立所需對象(如 SOAPBody )的引用。
接著,填充 SOAPBody :
填充主體
...import javax.xml.soap.SOAPBody;import javax.xml.soap.SOAPElement;public class SOAPTip { public static void main(String args[]) { try {... //Create objects for the message parts SOAPPart soapPart = message.getSOAPPart(); SOAPEnvelope envelope = soapPart.getEnvelope(); SOAPBody body = envelope.getBody(); //Populate the body //Create the main element and namespace SOAPElement bodyElement = body.addChildElement(envelope.createName("schedule" , "cal", "http://www.example.com/calendar")); //Add content bodyElement.addChildElement("cal:newitem").addTextNode("contentHere"); //Save the message message.saveChanges(); //Check the input System.out.println("\nREQUEST:\n"); message.writeTo(System.out); System.out.println(); //Close the connection connection.close(); } catch(Exception e) { System.out.println(e.getMessage()); } }} |
SOAP 訊息的主體就象任何其它 XML 元素,您可以在其中添加子項目(如 schedule 元素)。通常,您可以使用 addChildElement(elementname) ,但是這裡示範的 envelope.createName() 方法使用用於資料或承載的名稱空間聲明簡化了元素的建立。的確,建立 schedule 元素從而建立了 bodyElement SOAPElement 對象。然後, bodyElement 對象可以給其自己的子項目 cal:newitem 添加其自己的文本節點。通過這種方式,您可以象構建任何其它 XML 文檔一樣構建 XML 結構。
然而,使用 JAXM,您也有機會通過使用外部檔案直接建立訊息的 SOAPPart 。例如,第一個清單中的 XML 結構儲存在檔案prepped.msg 中,而且可以調用它來替代手工構建文檔。
從外部檔案建立訊息
...import javax.xml.soap.SOAPElement;import java.io.FileInputStream;import javax.xml.transform.stream.StreamSource;public class SOAPTip { public static void main(String args[]) {... //Create objects for the message parts SOAPPart soapPart = message.getSOAPPart(); SOAPEnvelope envelope = soapPart.getEnvelope(); SOAPBody body = envelope.getBody(); //Populate the Message StreamSource preppedMsgSrc = new StreamSource( new FileInputStream("prepped.msg")); soapPart.setContent(preppedMsgSrc); //Save the message message.saveChanges();... }} |
結果就是準備發送的 SOAP 訊息。
回頁首
發送訊息
對於同步訊息,發送 SOAP 訊息和接收應答是在單個步驟中發生的:
發送訊息
...import javax.xml.messaging.URLEndpoint;public class SOAPTip { public static void main(String args[]) { ... //Check the input System.out.println("\nREQUEST:\n"); message.writeTo(System.out); System.out.println(); //Send the message and get a reply //Set the destination URLEndpoint destination = new URLEndpoint("http://localhost:8080/jaxm-simple/receiver"); //Send the message SOAPMessage reply = connection.call(message, destination); //Close the connection connection.close(); ... }} |
實際的訊息是使用 call() 方法發送的,該方法把訊息本身和目的地作為參數,然後返回第二個 SOAPMessage 作為應答。目的地必須是一個 Endpoint 對象,或者是這個例子中的 URLEndpoint 。這個樣本使用來自 JWSDP 的一個樣本 servlet,它只用於擷取響應。
call() 方法一直處於阻塞狀態,直到它接收到返回的 SOAPMessage 為止。
回頁首
響應
返回的 SOAPMessage ― reply ― 是 SOAP 訊息,它與已發送的訊息格式相同,因此可以象操作任何其它 XML 訊息那樣操作它。SOAP 允許您通過使用 XSLT 直接轉換應答:
讀取響應
...import javax.xml.transform.TransformerFactory;import javax.xml.transform.Transformer;import javax.xml.transform.Source;import javax.xml.transform.stream.StreamResult;public class SOAPTip { public static void main(String args[]) { try { ... //Send the message SOAPMessage reply = connection.call(message, destination); //Check the output System.out.println("\nRESPONSE:\n"); //Create the transformer TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); //Extract the content of the reply Source sourceContent = reply.getSOAPPart().getContent(); //Set the output for the transformation StreamResult result = new StreamResult(System.out); transformer.transform(sourceContent, result); System.out.println(); //Close the connection connection.close();... }} |
象在任何 XSLT 應用程式中那樣建立 Transformer 對象。在這個例子中,我們只希望輸出內容,所以沒有用到樣式表。這裡,內容本身就是訊息的整個 SOAP 部分(與可能包含附件的 SOAP 訊息本身不同)。您還可以在處理之前抽取封套和主體。這個例子中的結果只是 System.out ,但它可以是通常用於轉換的任何選擇。照常進行轉換。
圖 1. SOAP 請求和響應
回頁首
下一步
雖然本樣本中的端點是提供靜態響應的 servlet,但是實際的響應取決於服務的功能和請求的性質。同時,雖然本篇技巧文章示範了訊息的同步發送和接收,但是通過使用 ProviderConnection 對象而不是 SOAPConnection ,JAXM 允許使用訊息傳遞提供者進行非同步發送。該提供者一直儲存這個訊息,直到成功發送訊息為止。
JAXM 還允許使用 profile,這樣很容易建立諸如 SOAP-RP 或 ebXML 訊息那樣的專門 SOAP 訊息,而且還能使非 XML 附件能夠附加到 SOAP 訊息中。
參考資料
- 您可以參閱本文在 developerWorks 全球網站上的 英文原文.
- 請查看 W3C中的各種與 Web 服務相關的建議書的情況。
- JAXM 可以作為 Java XML Pack(2002 年春季版)的一部分和 Java Web Services Developer Pack EA2的一部分而獲得。
- IBM WebSphere Studio Application Developer是用於構建、測試和部署 Web 服務的易用的整合式開發環境。
- 要擷取完整的 Web 服務工具箱,請下載 IBM 的 Web Services Development Kit。
- 在 developerWorks 的 XML和 Web 服務專區尋找更多參考資料。
轉載:http://www.ibm.com/developerworks/cn/xml/tips/x-jaxmsoap/