簡介: 在本篇技巧文章中,作者兼開發人員 Nicholas Chase 向您演示如何使用用於 XML 消息傳遞的 Java API(Java API for XML Messaging (JAXM))簡化創建和發送 SOAP 消息的過程。
Web 服務的基礎在於以標准格式發送和接收消息以便使所有系統都能理解。通常,那種格式是簡單對象訪問協議(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 消息由包含兩個主要部分(報頭和主體)的封套組成。應用程序決定如何使用這些部分,但整個消息必須遵循特定的 XML 結構,例如:
<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 ,但它可以是通常用於轉換的任何選擇。照常進行轉換。
雖然本示例中的端點是提供靜態響應的 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/

