您的位置:首页 > 编程语言 > Java开发

使用SAAJ发送和接收SOAP消息

2007-10-22 14:03 459 查看
在本技巧中,作者和开发人员 Nicholas Chase 向您展示了如何使用 SOAP with Attachments API for Java (SAAJ),从而简化创建和发送SOAP消息的过程。
Web 服务的基础是以标准格式发送和接收消息,这样所有系统都可以理解消息。通常情况下,这种标准格式是 SOAP。SOAP 消息可以手工生成和发送,但 SOAP with Attachments API for Java (SAAJ)—— Java API for XML Messaging (JAXM)的一个分支——能够使许多必需的步骤变得自动化,例如创建连接,或者创建和发送实际消息。本技巧介绍了同步 SOAP 消息的创建和发送。

该过程包括 5 个步骤:

1. 创建 SOAP 连接
2. 生成 SOAP 消息
3. 填充消息
4. 发送消息
5. 检索响应

SAAJ 是 Java Web Services Developer Pack 1.2 的一部分(参见 参考资料)。这个软件包还包含了 Tomcat Web 服务器(因此您就可以建立自己的服务)和例子应用程序。

安装问题

安装 Java Web Services Developer Pack 1.2 是很容易的——只要通过包含的 Tomcat Web 服务器发送消息即可。要通过独立的应用程序发送消息,像我这里所做的一样,需要采取以下步骤:

从网址 http://java.sun.com/webservices/downloads/webservicespack.html下载 JWSDP1.2。

将软件安装到相应目录中。

如果您正使用 Java 1.4,需要用下载的软件覆盖相关的 XML 类。创建以下目录:
<JAVA_HOME>/jre/lib/endorsed

并复制目录
<JWSDP_HOME>/jaxp/lib/endorsed

中的文件到该目录下。(JAVA_HOME和JWSDP_HOME 分别表示 Java 安装以及 JWSDP 安装的目录。)

将下列文件加入 classpath 中:
<JWSDP_HOME>/saaj/lib/saaj-api.jar

<JWSDP_HOME>/saaj/lib/saaj-impl.jar

<JWSDP_HOME>/jwsdp-shared/lib/commons-logging.jar

<JWSDP_HOME>/jwsdp-shared/lib/mail.jar

<JWSDP_HOME>/jwsdp-shared/lib/activation.jar

<JWSDP_HOME>/jaxp/lib/endorsed/dom.jar

<JWSDP_HOME>/jaxp/lib/endorsed/xercesImpl.jar

<JWSDP_HOME>/jaxp/lib/endorsed/sax.jar

<JWSDP_HOME>/jaxp/lib/endorsed/xalan.jar

现在您就可以使用独立的程序从自己系统的任意位置发送消息了。

SOPA 消息的结构

首先来看消息自身的结构。一条基本的 SOAP 消息由带有两个主要部分的信封(envelope)构成:头部和主体。应用程序确定如何使用这些部分,但整个消息必须遵循特定的 XML 结构,例如:

清单1. 一条示例 SOAP 消息
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Header />
<SOAP-ENV:Body> 
<ns1:getPrice xmlns:ns1="urn:xmethods-BNPriceCheck"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<isbn xsi:type="xsd:string">0672324229</isbn>
</ns1:getPrice>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope> 

这里,头部是空的,而主体包含了有效信息,或要传递的消息。在本例中,它是请求某本书价格的消息。

注意消息的结构。Envelope 包含 Header 和 Body 元素,这三者都是http://schemas.xmlsoap.org/soap/envelope/ namespace的一部分。应用程序使用 SOAPConnection 来发送消息。

创建连接和消息

第一步是要创建总体类和连接:

清单2. 创建连接
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());
}
}
}

应用程序可以直接使用 SOAPConnnection 或间接使用消息提供者来发送 SOAP 消息,现在 SOAPConnection 已经是 SAAJ 包的一部分了,而消息提供者仍然属于 JAXM 包。在本例中,应用程序使用工厂创建 SOAPConnection 对象。

工厂还创建了消息自身:

清单3. 创建消息对象
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:

清单4. 填充主体
...
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("getPrice" ,
"ns1",
"urn:xmethods-BNPriceCheck"));
//Add content
bodyElement.addChildElement("isbn").addTextNode("0672324229");
//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.getMessa
a0a9
ge());
}
}
}

SOAP 消息的主体就好像是另一个 XML 元素,可以在其中添加孩子元素,比如 getPrice。然后就可以像处理典型的 DOM 元素一样,为它添加 isbn 元素和文本节点。

使用 SAAJ 还有可能使用外部文件来直接创建消息的 SOAPPart。例如,第一个程序清单中,prepped.msg 文件包含了 XML 结构,在手工建立文档的地方可以调用该文件:

清单5. 从一个外部文件创建消息
...
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();
...
}
}

通常,StreamSource 类用作 XSL Transformation 的一部分,但在这儿可以简单地使用它来获得 FileInputStream。结果是一个 SOAP 消息已经就绪,可以发送了。

发送消息

对于同步消息,发送 SOAP 消息,并接收在同一步中发生的响应:

清单6. 发送消息
...
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
String destination =
"http://services.xmethods.net:80/soap/servlet/rpcrouter";
//Send the message
SOAPMessage reply = connection.call(message, destination);
//Close the connection
connection.close();
...
}
}

实际的消息是使用 call()方法发送的,该方法接收消息本身和目的地作为参数,并返回第二个 SOAPMessage 作为响应。在早期版本的 JAXM 中,目的地必须是一个 Endpoint 对象或一个 URLEndpoint,但现在它只要是一个对象就可以了。这个例子使用了由 XMethods 支持的“书价检验程序” Web 服务,该服务返回请求中给定 ISBN 的书的价格。

call()方法将会阻塞,直到它接收到返回的 SOAPMessage 为止。

响应

相应地,返回的 SOAPMessage 是一个与发送消息具有相同形式的 SOAP 消息,这样该消息操作时就可以像另一个 XML 消息一样。SOAP 允许直接使用 XSLT 来转换响应:

清单7.读取响应
...
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 请求和响应


 
接下来的步骤

这个简单的应用程序仅仅输出所接收到的消息,但是您可以同样简单地从 XML 文档中提取信息。同样,虽然这一技巧仅演示了消息的同步发送和接收,但是 JAXM API 也允许用于同步传送的消息提供者的使用,只是通过使用 ProviderConnection 对象而不是 SOAPConnection 进行。提供者保持消息,直到该消息成功传送为止。

JAXM 也允许配置文件的使用,配置文件可以简化特定 SOAP 消息的创建,比如 SOAP-RP 或 ebXML 消息。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息