转自(http://tscjsj.blog.51cto.com/412451/84813)
一、概述
SOAP原意为Simple Object Access Protocol(简单对象访问协议),是一个用于分布式环境的、轻量级的、基于XML进行信息交换的通信协议(SOAP is an XML based protocol used to exchange information throughout a distributed environment)。
以下是w3c网站上的定义:
SOAP Version 1.2 (SOAP) is a lightweight protocol intended for exchanging structured information in a decentralized, distributed environment. It uses XML technologies to define an extensible messaging framework providing a message construct that can be exchanged over a variety of underlying protocols. The framework has been designed to be independent of any particular programming model and other implementation specific semantics.
可以认为SOAP是XML-RPC的高级版本,二者基于相同的原理:利用HTTP + XML封装进行RPC调用。
SOAP最初由MS发起研究,用以解决MTS/COM资源消耗大,不够轻巧等问题,后逐渐被IBM等巨头接纳并加入研究,现已提交W3C,成为Web Service应用传输标准。对于轻量级、可扩展Web Service应用协议的需求促成了SOAP的广泛应用,也间接促进了XML的流行。关于相关历史的更多信息,见
[url]http://www.microsoft.com/china/MSDN/library/WebServices/WebServices/SOAPSpecificationIndexPage.mspx[/url]或
[url]http://www-128.ibm.com/developerworks/cn/webservices/ws-ref1/index.html[/url]。
二、SOAP数据包结构解析
SOAP的消息被称为一个SOAP Envelope,包括SOAP Header和SOAP Body。其中,SOAP Header可以方便的插入各种其它消息来扩充Web Service的功能,比如Security(采用证书访问Web Service),SOAP Body则是具体的消息正文,也就是Marshall后的信息。
SOAP调用的时候,也就是向一个URL(比如
[url]http://api.google.com/search/beta2[/url])发送HTTP Post报文(根据SOAP规范,HTTP Get报文也可被支持),调用方法的名字在HTTP Request Header SOAP-Action中给出,接下来就是SOAP Envelope了。服务端接到请求,执行计算,将返回结果Marshall成XML,用HTTP返回给客户端。
以下是一个典型的SOAP数据包:
<
s:Envelope
xmlns:s
="http://www.w3.org/2003/05/soap-envelope"
>
< s:Header >
< m:transaction xmlns:m ="soap-transaction" s:mustUnderstand ="true" >
< transactionID >1234 </ transactionID >
</ m:transaction >
</ s:Header >
< s:Body >
< n:purchaseOrder xmlns:n ="urn:OrderService" >
< from >
< person >Christopher Robin </ person >
< dept >Accounting </ dept >
</ from >
< to >
< person >Pooh Bear </ person >
< dept >Honey </ dept >
</ to >
< order >
< quantity >1 </ quantity >
< item >Pooh Stick </ item >
</ order >
</ n:purchaseOrder >
</ s:Body >
</ s:Envelope >
< s:Header >
< m:transaction xmlns:m ="soap-transaction" s:mustUnderstand ="true" >
< transactionID >1234 </ transactionID >
</ m:transaction >
</ s:Header >
< s:Body >
< n:purchaseOrder xmlns:n ="urn:OrderService" >
< from >
< person >Christopher Robin </ person >
< dept >Accounting </ dept >
</ from >
< to >
< person >Pooh Bear </ person >
< dept >Honey </ dept >
</ to >
< order >
< quantity >1 </ quantity >
< item >Pooh Stick </ item >
</ order >
</ n:purchaseOrder >
</ s:Body >
</ s:Envelope >
Note:
如果你是一个普通的应用开发者,以上介绍已经足够了,因为相应的SOAP应用平台会负责完成相应SOAP数据包的打包和解析;如果你是一个SOAP应用平台的实现者,关于SOAP基础理论的更多介绍可参考《Programming Web Services with SOAP》一书或SOAP Specification([url]http://www.w3.org/TR/soap12-part0/[/url])。
三、安装Apache Axis
Apache Axis本身也是一个Web Project,它内建了对SOAP的编码、解析,并为Client提供了一些使用SOAP Service的API,同时,为Web Service的发布提供管理,并对Client提交的处理请求作出响应。对于基于Axis的应用而言,我们可以将注意力完全放在具体Service和Client的设计上,而无需考虑中间的传输过程(对于Client而言,还需要使用一些Axis提供的访问SOAP服务的特定API),这一点是与XML RPC不同的地方。
Apache Axis可以从
[url]http://ws.apache.org/axis/[/url]下载,当前的最新版本是1.4。
安装Axis的过程很简单:
1、解压Axis到任意目录下;
2、拷贝Axis目录下的webapps/axis目录到%TOMCAT_HOME%/webapps下;
3、为了便于编译和测试程序,添加环境变量:
AXIS_HOME Axis的解压目录
AXIS_LIB %AXIS_HOME%/lib
AXISCLASSPATH %AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery-0.2.jar;%AXIS_LIB%\commons-logging-1.0.4.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar
完成上述工作后,启动Tomcat,并用IE打开:
[url]http://localhost:8080/axis/[/url],点击其中的Validation、List两个链接,如果没有报告任何错误,则说明Axis安装成功。
关于Apache Axis安装的更多信息可以参考官方文档:
[url]http://ws.apache.org/axis/java/install.pdf[/url]。
四、举例
有了上面对SOAP的基本理解,下面我们体验一下Apache Axis 1.4提供的SOAP服务。
以下面EchoService为例:
public
class EchoService {
public String echoString(String name) {
return name;
}
}
public String echoString(String name) {
return name;
}
}
其对应的
Client程序如下所示:
package demo.soap;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import javax.xml.namespace.QName;
public class EchoClient {
public static void main(String [] args) {
try {
String endpoint = "http://localhost:8080/axis/EchoService.jws";
// Create Service and Call object to set up a SOAP RPC
Service service = new Service();
Call call = (Call)service.createCall();
// Tells which service and method will be invoked
call.setTargetEndpointAddress(new java.net.URL(endpoint));
call.setOperationName(new QName("echoString"));
// Invoke method with required parameters
String ret = (String)call.invoke(new Object[] { "Hello!" });
System.out.println("Sent 'Hello!', got '" + ret + "'");
} catch (Exception e) {
System.err.println(e.toString());
}
}
}
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import javax.xml.namespace.QName;
public class EchoClient {
public static void main(String [] args) {
try {
String endpoint = "http://localhost:8080/axis/EchoService.jws";
// Create Service and Call object to set up a SOAP RPC
Service service = new Service();
Call call = (Call)service.createCall();
// Tells which service and method will be invoked
call.setTargetEndpointAddress(new java.net.URL(endpoint));
call.setOperationName(new QName("echoString"));
// Invoke method with required parameters
String ret = (String)call.invoke(new Object[] { "Hello!" });
System.out.println("Sent 'Hello!', got '" + ret + "'");
} catch (Exception e) {
System.err.println(e.toString());
}
}
}
对于Client程序而言,对Axis Service进行访问的基本方法是:
1、创建Service及Call对象;
2、设置Call对象属性,如访问点(标明将访问哪个Axis Service)及方法名等;
3、传入参数数组,调用Call对象的invoke方法。
可使用如下命令编译EchoClient.java:
javac -cp %AXISCLASSPATH% EchoClient.java
在Axis中,存在两种发布SOAP Service的方法。
方法一:
将源程序EchoService.java拷贝到%TOMCAT_HOME%/webapps/axis下,并将其后缀改为.jws即可。
第一种方法非常的简单,但是第一种发布方法存在几个重要的限制:
1、不能指定package;
2、需要有Service的源码;
因此常常不能满足我们的需要。
方法二:
第二种发布Axis Service的方法需通过配置来完成。
以下面的HelloService为例(与前面的EchoService基本没有什么区别,但其中使用了package):
package demo.soap;
public class HelloService {
public String sayHello() {
return "Hello World!";
}
}
public class HelloService {
public String sayHello() {
return "Hello World!";
}
}
要发布上面的Service,需编写如下的配置文件:
<
deployment
xmlns
="http://xml.apache.org/axis/wsdd/"
xmlns:java
="http://xml.apache.org/axis/wsdd/providers/java"
>
< service name ="HelloService" provider ="java:RPC" >
< parameter name ="className" value ="demo.soap.HelloService" />
< parameter name ="allowedMethods" value ="*" />
</ service >
</ deployment >
< service name ="HelloService" provider ="java:RPC" >
< parameter name ="className" value ="demo.soap.HelloService" />
< parameter name ="allowedMethods" value ="*" />
</ service >
</ deployment >
java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient deploy.txt
生成server-config.wsdd文件,打开该文件看一下,可以看到HelloService的相关信息已被添加到该文件,此外,还包括一些默认的配置信息以及AdminService、Version两个基础服务。
以下是HelloService的Client程序的相关代码:
package demo.soap;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
public class HelloClient {
public static void main(String [] args) throws Exception {
String endpoint = "http://localhost:" + "8080" + "/axis/services/HelloService"; // Attention: A little difference
Service service = new Service();
Call call = (Call)service.createCall();
call.setTargetEndpointAddress(new java.net.URL(endpoint));
call.setOperationName("sayHello");
String res = (String)call.invoke(new Object[] {});
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
public class HelloClient {
public static void main(String [] args) throws Exception {
String endpoint = "http://localhost:" + "8080" + "/axis/services/HelloService"; // Attention: A little difference
Service service = new Service();
Call call = (Call)service.createCall();
call.setTargetEndpointAddress(new java.net.URL(endpoint));
call.setOperationName("sayHello");
String res = (String)call.invoke(new Object[] {});
System.out.println(res);
}
}
发布后如何删除对应的Service呢?要删除上面发布的HelloService服务,只需在%TOMCAT_HOME%\webapps\axis\WEB-INF目录下添加如下的undeploy.txt描述文件,其内容如下:
<
undeployment
xmlns
="http://xml.apache.org/axis/wsdd/"
>
< service name ="HelloService" />
</ undeployment >
< service name ="HelloService" />
</ undeployment >
然后执行:
java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient deploy.txt
以更新server-config.wsdd文件。
将看到前面已发布的对应的Service已被删除。
如果以后还要发布新的Service,你可以选择直接更新上面产生的server-config.wsdd文件,或者重复上面的步骤。