技巧: 用 JAXM 发送和接收 SOAP 消息—Java API 使许多手工生成和发送消息方面必需的步骤自动化...
簡(jiǎn)介:?在本篇技巧文章中,作者兼開發(fā)人員 Nicholas Chase 向您演示如何使用用于 XML 消息傳遞的 Java API(Java API for XML Messaging (JAXM))簡(jiǎn)化創(chuàng)建和發(fā)送 SOAP 消息的過程。
Web 服務(wù)的基礎(chǔ)在于以標(biāo)準(zhǔn)格式發(fā)送和接收消息以便使所有系統(tǒng)都能理解。通常,那種格式是簡(jiǎn)單對(duì)象訪問協(xié)議(Simple Object Access Protocol (SOAP))。SOAP 消息可以手工生成和發(fā)送,但是用于 XML 消息傳遞的 Java API(JAXM)使許多必需步驟(如創(chuàng)建連接或創(chuàng)建并發(fā)送實(shí)際消息)自動(dòng)化。這篇技巧文章記錄了一個(gè)同步 SOAP 消息的創(chuàng)建和發(fā)送。
這個(gè)過程包含五個(gè)步驟:
JAXM 可以作為 Java XML Pack(2002 年春季版)的一部分和 Java Web Services Developer Pack EA2(請(qǐng)參閱?參考資料)的一部分而獲得。后者還包含了一份 Tomcat Web 服務(wù)器以及樣本應(yīng)用程序的副本。那些樣本 Web 服務(wù)之一作為本技巧文章中 SOAP 消息的目的地,這個(gè)例子中實(shí)際服務(wù)的內(nèi)容和功能卻不是很重要。
SOAP 消息結(jié)構(gòu)
一個(gè)基本的 SOAP 消息由包含兩個(gè)主要部分(報(bào)頭和主體)的封套組成。應(yīng)用程序決定如何使用這些部分,但整個(gè)消息必須遵循特定的 XML 結(jié)構(gòu),例如:
樣本 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> |
?
在這個(gè)例子中,報(bào)頭為空,而主體包含目的地為一個(gè)日歷應(yīng)用程序的信息。
請(qǐng)注意這個(gè)消息的結(jié)構(gòu)。Envelope 包含 Header 和 Body 元素,而三者全都是?http://schemas.xmlsoap.org/soap/envelope/?名稱空間的一部分。整個(gè)消息將通過一個(gè) SOAP 連接發(fā)送到一個(gè) Web 服務(wù)中。
回頁首
創(chuàng)建連接和消息
第一步是創(chuàng)建整個(gè)類和連接:
創(chuàng)建連接
| import javax.xml.soap.SOAPConnectionFactory; import javax.xml.soap.SOAPConnection; public class SOAPTip {public static void main(String args[]) {try {//First create the connectionSOAPConnectionFactory soapConnFactory = SOAPConnectionFactory.newInstance();SOAPConnection connection = soapConnFactory.createConnection();//Close the connection connection.close();} catch(Exception e) {System.out.println(e.getMessage());}} } |
?
SOAP 消息可以通過使用?SOAPConnection?直接發(fā)送,或使用消息傳遞提供程序間接發(fā)送。在這個(gè)例子中,應(yīng)用程序通過使用工廠(factory)創(chuàng)建?SOAPConnection?對(duì)象。
工廠也創(chuàng)建消息本身:
創(chuàng)建消息對(duì)象
| 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 connectionSOAPConnectionFactory soapConnFactory = SOAPConnectionFactory.newInstance();SOAPConnection connection = soapConnFactory.createConnection();//Next, create the actual messageMessageFactory 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?來創(chuàng)建消息本身。這個(gè)消息已包含如?envelope?和?header?等基本部分的空白版本。?SOAPPart?包含envelope?,而?envelope?包含主體。同時(shí)創(chuàng)建所需對(duì)象(如?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 namespaceSOAPElement bodyElement = body.addChildElement(envelope.createName("schedule" , "cal", "http://www.example.com/calendar"));//Add contentbodyElement.addChildElement("cal:newitem").addTextNode("contentHere");//Save the messagemessage.saveChanges();//Check the inputSystem.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()?方法使用用于數(shù)據(jù)或有效負(fù)載的名稱空間聲明簡(jiǎn)化了元素的創(chuàng)建。的確,創(chuàng)建 schedule 元素從而創(chuàng)建了?bodyElement SOAPElement?對(duì)象。然后,?bodyElement?對(duì)象可以給其自己的子元素?cal:newitem?添加其自己的文本節(jié)點(diǎn)。通過這種方式,您可以象構(gòu)建任何其它 XML 文檔一樣構(gòu)建 XML 結(jié)構(gòu)。
然而,使用 JAXM,您也有機(jī)會(huì)通過使用外部文件直接創(chuàng)建消息的?SOAPPart?。例如,第一個(gè)清單中的 XML 結(jié)構(gòu)保存在文件prepped.msg?中,而且可以調(diào)用它來替代手工構(gòu)建文檔。
從外部文件創(chuàng)建消息
| ... 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 MessageStreamSource preppedMsgSrc = new StreamSource( new FileInputStream("prepped.msg"));soapPart.setContent(preppedMsgSrc);//Save the messagemessage.saveChanges(); ...} } |
?
結(jié)果就是準(zhǔn)備發(fā)送的 SOAP 消息。
回頁首
發(fā)送消息
對(duì)于同步消息,發(fā)送 SOAP 消息和接收應(yīng)答是在單個(gè)步驟中發(fā)生的:
發(fā)送消息
| ... import javax.xml.messaging.URLEndpoint; public class SOAPTip {public static void main(String args[]) {...//Check the inputSystem.out.println("\nREQUEST:\n");message.writeTo(System.out);System.out.println();//Send the message and get a reply //Set the destinationURLEndpoint destination = new URLEndpoint("http://localhost:8080/jaxm-simple/receiver");//Send the messageSOAPMessage reply = connection.call(message, destination);//Close the connection connection.close(); ...} } |
?
實(shí)際的消息是使用?call()?方法發(fā)送的,該方法把消息本身和目的地作為參數(shù),然后返回第二個(gè)?SOAPMessage?作為應(yīng)答。目的地必須是一個(gè)?Endpoint?對(duì)象,或者是這個(gè)例子中的?URLEndpoint?。這個(gè)示例使用來自 JWSDP 的一個(gè)樣本 servlet,它只用于獲取響應(yīng)。
call()?方法一直處于阻塞狀態(tài),直到它接收到返回的?SOAPMessage?為止。
回頁首
響應(yīng)
返回的?SOAPMessage?―?reply?― 是 SOAP 消息,它與已發(fā)送的消息格式相同,因此可以象操作任何其它 XML 消息那樣操作它。SOAP 允許您通過使用 XSLT 直接轉(zhuǎn)換應(yīng)答:
讀取響應(yīng)
| ... 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 messageSOAPMessage reply = connection.call(message, destination);//Check the outputSystem.out.println("\nRESPONSE:\n");//Create the transformerTransformerFactory transformerFactory = TransformerFactory.newInstance();Transformer transformer = transformerFactory.newTransformer();//Extract the content of the replySource sourceContent = reply.getSOAPPart().getContent();//Set the output for the transformationStreamResult result = new StreamResult(System.out);transformer.transform(sourceContent, result);System.out.println();//Close the connection connection.close(); ... } } |
?
象在任何 XSLT 應(yīng)用程序中那樣創(chuàng)建?Transformer?對(duì)象。在這個(gè)例子中,我們只希望輸出內(nèi)容,所以沒有用到樣式表。這里,內(nèi)容本身就是消息的整個(gè) SOAP 部分(與可能包含附件的 SOAP 消息本身不同)。您還可以在處理之前抽取封套和主體。這個(gè)例子中的結(jié)果只是?System.out?,但它可以是通常用于轉(zhuǎn)換的任何選擇。照常進(jìn)行轉(zhuǎn)換。
圖 1. SOAP 請(qǐng)求和響應(yīng)?
?
回頁首
下一步
雖然本示例中的端點(diǎn)是提供靜態(tài)響應(yīng)的 servlet,但是實(shí)際的響應(yīng)取決于服務(wù)的功能和請(qǐng)求的性質(zhì)。同時(shí),雖然本篇技巧文章演示了消息的同步發(fā)送和接收,但是通過使用?ProviderConnection?對(duì)象而不是?SOAPConnection?,JAXM 允許使用消息傳遞提供程序進(jìn)行異步發(fā)送。該提供程序一直保存這個(gè)消息,直到成功發(fā)送消息為止。
JAXM 還允許使用?profile,這樣很容易創(chuàng)建諸如 SOAP-RP 或 ebXML 消息那樣的專門 SOAP 消息,而且還能使非 XML 附件能夠附加到 SOAP 消息中。
參考資料
- 您可以參閱本文在 developerWorks 全球站點(diǎn)上的?英文原文.?
- 請(qǐng)查看?W3C中的各種與 Web 服務(wù)相關(guān)的建議書的情況。?
- JAXM 可以作為?Java XML Pack(2002 年春季版)的一部分和?Java Web Services Developer Pack EA2的一部分而獲得。?
- IBM WebSphere Studio Application Developer是用于構(gòu)建、測(cè)試和部署 Web 服務(wù)的易用的集成開發(fā)環(huán)境。?
- 要獲取完整的 Web 服務(wù)工具箱,請(qǐng)下載 IBM 的?Web Services Development Kit。?
- 在 developerWorks 的?XML和?Web 服務(wù)專區(qū)查找更多參考資料。
- 您可以參閱本文在 developerWorks 全球站點(diǎn)上的?英文原文.?
轉(zhuǎn)載:http://www.ibm.com/developerworks/cn/xml/tips/x-jaxmsoap/
轉(zhuǎn)載于:https://www.cnblogs.com/chenying99/archive/2013/05/23/3094128.html
總結(jié)
以上是生活随笔為你收集整理的技巧: 用 JAXM 发送和接收 SOAP 消息—Java API 使许多手工生成和发送消息方面必需的步骤自动化...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 笔记1-3: 从标准输入读取命令并执行
- 下一篇: 选房心得