本文的預(yù)定作者應(yīng)該對(duì)SOAP1.1的基本規(guī)范有所了解,并熟悉了j2ee的基本開發(fā),如果不熟悉的話,可以看一下我的Blog:
使用SOAP開發(fā)java web服務(wù)--Axis開發(fā)方案 ,詳細(xì)標(biāo)準(zhǔn)可以查看w3c的官方網(wǎng)站,連接如下:
http://www.w3.org/TR/2000/NOTE-SOAP-20000508/ 。本文主要是探討SAAJ(SOAP with Attachment API for Java),JAXM(Java API for XML Messaging),了解SOAP在j2ee開發(fā)中的作用與其接口。JAXM和SAAJ均支持針對(duì)B2B和Web服務(wù)應(yīng)用程序、基于XML的消息交換,支持諸多行業(yè)標(biāo)準(zhǔn),包括SOAP和ebXML。
SAAJ是JWSDP的組成部分之一,JWSDP目前已經(jīng)更新到了1.5版,SAAJ可以從SUN的網(wǎng)站單獨(dú)下載:
http://java.sun.com/xml/downloads/saaj.html,JAXM是用于XML消息交換的標(biāo)準(zhǔn),不在JWSDP1.5的發(fā)行包內(nèi),可以另外下載:
http://java.sun.com/xml/jaxm/downloads/index.html ,由于SAAJ是基于JavaMail
TM API (1.2) 、 JavaBeans
TM Activation Framework (JAF) (1.1.3)和JAXP(1.2.6) 的,所以也要把他們下載下來(lái),SUN的官方網(wǎng)站都有提供的,好了,現(xiàn)在我們得到了以下包(按我下載的名稱):activation.jar(JAF),jaxm-api.jar(JAXM),mail.jar(JavaMail),saaj-api.jar(SAAJ),saaj-impl.jar(SAAJ),我的JAXP已經(jīng)包括在jdk1.5中了。另外還要有個(gè)支持Servlet的容器。
好了,準(zhǔn)備工作完畢了,下面開始我們的學(xué)習(xí):
一、 SAAJ可用于將XML文檔作為SOAP消息發(fā)送和接收,而無(wú)需JAXM提供商的基礎(chǔ)程序結(jié)構(gòu),也無(wú)需處理基于SOAP的HTTP請(qǐng)求/響應(yīng)。SAAJ最初是JAXM1.0API軟件包的組成部分,而從JAXM1.1開始,該軟件包更名為SAAJ1.1API。
以下我們先了解一個(gè)簡(jiǎn)單的SOAP1.1消息:
POST /StockQuote HTTP/1.1
Host:
www.stockquoteserver.comContent-Type: text/xml; charset="utf-8"
Content-Length: nnnn
SOAPAction: "Some-URI"
<SOAP-ENV:Envelope
xmlns:SOAP-ENV=" SOAP-ENV:encodingStyle="> <------------這是信封標(biāo)志
<SOAP-ENV:Header> <------------這是消息頭標(biāo)志
<t:Transaction
xmlns:t="some-URI"
SOAP-ENV:mustUnderstand="1">
5
</t:Transaction>
</SOAP-ENV:Header>
<SOAP-ENV:Body> <------------這是主體標(biāo)志
<m:GetLastTradePrice xmlns:m="Some-URI">
<symbol>DEF</symbol>
</m:GetLastTradePrice>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
SAAJ API為我們提供了一個(gè)高層次SOAP消息封裝接口,如:信封接口:javax.xml.soap.SOAPEnvelope,并提供了操作getHeader(),該方法返回一個(gè)消息頭:javax.xml.soap.SOAPHeader。所以,通過(guò)調(diào)用SAAJ的接口函數(shù),我們就可以對(duì)SOAP消息進(jìn)行操作。
二、現(xiàn)在我們來(lái)討論一下在不使用消息交換提供程序的JAXM時(shí),應(yīng)用程序客戶端通過(guò)SOAP直接與其遠(yuǎn)程伙伴發(fā)送和接收消息操作(定義了點(diǎn)到點(diǎn)的交互作用和同步通信模型,其中發(fā)送方和接收方以請(qǐng)求和響應(yīng)的形式交換消息。發(fā)送方發(fā)送消息并等待鎖定目標(biāo)位置的響應(yīng))。
發(fā)送方步驟:
1)創(chuàng)建SOAP連接;
2)創(chuàng)建消息工廠;
3)創(chuàng)建消息;
4)填充消息;
5)添加消息;
6)添加SOAP附件;
7)發(fā)送消息并接收響應(yīng);
8)關(guān)閉提供程序連接;
一下是我寫的一個(gè)例子:
/**
*Sender.java
*Copyright 2005-2-10
*/
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPException;
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.SOAPHeader;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPElement;
import java.net.URL;
import javax.xml.messaging.URLEndpoint;
import javax.activation.DataHandler;
import java.io.IOException;
public class Sender{
public SOAPMessage getMessage() throws SOAPException,Exception{
//消息工廠
MessageFactory msgFactory=MessageFactory.newInstance();
SOAPMessage message=msgFactory.createMessage();
//獲得一個(gè)SOAPPart對(duì)象
SOAPPart soapPart=message.getSOAPPart();
//獲得信封
SOAPEnvelope soapEnvelope=soapPart.getEnvelope();
//獲得消息頭
SOAPHeader soapHeader=soapEnvelope.getHeader();
//獲得SOAP主體
SOAPBody soapBody=soapEnvelope.getBody();
//添加頭元素
SOAPHeaderElement headerElement=soapHeader.addHeaderElement(
soapEnvelope.createName("StudentNo","stu","
//添加消息主體
Name bodyName=soapEnvelope.createName("getStudentInfo","stu","
SOAPBodyElement bodyElement=soapBody.addBodyElement(bodyName);
Name eleName=soapEnvelope.createName("StudentName");
SOAPElement se=bodyElement.addChildElement(eleName);
se.addTextNode("Wang wenyin");
//添加SOAP附件
URL url=new URL("
DataHandler dataHandler=new DataHandler(url);//use the JAF
message.addAttachmentPart(message.createAttachmentPart(dataHandler));
//更新SOAP消息
message.saveChanges();
return message;
}
public void send(SOAPMessage message) throws SOAPException,IOException{
//創(chuàng)建SOAP連接
SOAPConnectionFactory scf=SOAPConnectionFactory.newInstance();
SOAPConnection sc=scf.createConnection();
//發(fā)送SOAP消息到目的地,并返回一個(gè)消息
URLEndpoint urlEndpoint=new URLEndpoint("http://localhost/saaj/StudentInfoServlet");
SOAPMessage response=sc.call(message,urlEndpoint);
if(response!=null){
//輸出SOAP消息到控制臺(tái)
System.out.println("Receive SOAP message from localhost:");
response.writeTo(System.out);
}else{
System.err.println("No response received from partner!");
}
sc.close();
}
public static void main(String[] args) throws SOAPException,Exception{
Sender sender=new Sender();
SOAPMessage message=sender.getMessage();
sender.send(message);
}
}
然后編譯,注意classpath變量的設(shè)置要把以上的那些包加進(jìn)去(可以設(shè)置一個(gè)腳本來(lái)完成,熟悉Ant的話,那就更加簡(jiǎn)單了)。
編譯成功后,我們等到了一個(gè)Sender.class文件,這是發(fā)送方文件。當(dāng)你運(yùn)行java Sender的時(shí)候,就會(huì)把SOAP消息發(fā)向我們的同伴http://localhost/saaj/StudentInfoServlet ,并等待返回。以下我們繼續(xù)編寫一個(gè)Servlet好接收剛才發(fā)送的消息。
三、接收方Servlet應(yīng)用程序saaj.war。
/**
*JAXMReceiveServlet.java
*Copyright 2005-2-10
*/
import javax.xml.messaging.JAXMServlet;
import javax.xml.messaging.ReqRespListener;
import javax.xml.soap.MessageFactory;
import javax.servlet.ServletException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPEnvelope;
import javax.servlet.ServletConfig;
import java.io.FileOutputStream;
import java.io.File;
public class JAXMReceiveServlet extends JAXMServlet implements ReqRespListener{
static MessageFactory mf=null;
//創(chuàng)建一個(gè)消息工廠
static{
try{
mf=MessageFactory.newInstance();
}catch(Exception e){
e.printStackTrace();
}
};
public void init(ServletConfig sc) throws ServletException{
super.init(sc);
}
//處理傳過(guò)來(lái)的SOAP消息,并返回一個(gè)SOAP消息
public SOAPMessage onMessage(SOAPMessage msg){
SOAPMessage resp=null;
try{
System.out.println("傳入的消息:");
msg.writeTo(new FileOutputStream(new File("../webapps/soapmessage.xml")));
//創(chuàng)建一個(gè)返回消息
resp=mf.createMessage();
SOAPEnvelope se=resp.getSOAPPart().getEnvelope();
se.getBody().addChildElement(
se.createName("ResponseMessage")).addTextNode("Received Message,Thanks");
return resp;
}catch(Exception e){
e.printStackTrace();
}
return resp;
}
}
然后把相關(guān)的classpath添加進(jìn)去,編譯(不會(huì)的話,自己去查有關(guān)Servlet的編程,篇幅有限)
web.xml部署文件:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns=" xmlns:xsi=" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee version="2.4">
<servlet>
<servlet-name>StudentInfoServlet</servlet-name>
<servlet-class>JAXMReceiveServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>StudentInfoServlet</servlet-name>
<url-pattern>/StudentInfoServlet</url-pattern>
</servlet-mapping>
</web-app>
至此 我們的基本工作完成了,部署好程序saaj,當(dāng)你在瀏覽器訪問(wèn) http://localhost/saaj/StudentInfoServlet ,將會(huì)返回一個(gè)錯(cuò)誤信息,因?yàn)檫@里使用的是SOAP協(xié)議。
四、測(cè)試
如果部署成功的話,那開始我們的測(cè)試。
我們繼續(xù)第二步的步驟,java Sender,接著我們就等待,我們?cè)诎l(fā)送方創(chuàng)建了一個(gè)SOAP消息(有個(gè)jpg圖片的附件),并發(fā)送到Servlet容器中(我的是tomcat),在服務(wù)器方接送到消息,并在webapps文件夾下創(chuàng)建soapmessage.xml文件,把接收到的SOAP信息寫進(jìn)去,并返回一個(gè)soap消息。
等過(guò)了一段時(shí)間后,sender方會(huì)返回一個(gè)soap格式的xml文件,在控制臺(tái)上輸出。
好了,今天的關(guān)于SOAP的深入探索就到這里了。