运用Apache SOAP工具包实现SOAP
时间:2006-07-27 来源:little_cat
- j2sdk-.....
- jakarta-tomcat-.....
- soap-bin-.....
- Xerces-J-bin.....
可以从下面链接下载以上工具:
- Tomcat服务器下载:http://jakarta.apache.org/builds/
- Apache Soap工具包下载:http://xml.apache.org/dist/soap/
- Xerces XML分析器下载:http://xml.apache.org/dist/xerces-j/
- j2sdk下载:http://java.sun.com/j2se/
还需要下载下列JAR文件:
- servlet.jar
- mail.jar
- activation.jar
可以从http://java.sun.com/products/jsp/download.html下载servlet.jar。对于mail.jar文件,可以从http://java.sun.com/products/javamail/下载可行的JavaMail程序包。而对于activation.jar文件,则可以从http://java.sun.com/products/javabeans/glasgow/jaf.html下载JavaBeans Activation Framework。
在下载和安装了所需要的工具和文件后,下一步就是设置环境变量。
JAVA_HOME=C:\jdk...... TOMCAT_HOME=C:\jakarta-tomcat-..
将路径变量(path)设置成指向java安装的bin文件夹和Tomcat安装的bin文件夹。将classpath设置为包括xercesImpl.jar、xercesSamples.jar、xmlParserAPIs.jar、soap.jar、servlet.jar、mail.jar和activation.jar。
在jakarta-tomcat\conf\server.xml配置文件中增加一个新的<Context>标记,如下所示:
<Context path="/soap" docBase="C:\soap-2_3_1\webapps\soap"
debug="1" reloadable="true">
</Context>
(启动和终止tomcat:从命令终端进入tomcat安装的bin目录下,用startup和shutdown来启动和终止)
xercesImpl.jar、xercesSamples.jar和xmlParserAPIs.jar文件在Xerces安装目录下。可以在Apache SOAP工具包安装的lib文件夹中找到soap.jar。(必须将xercesImpl.jar设置在CLASSPATH的任何JAR文件前。)将C:\soap-2_3_1\webapps下的soap.war放在tomcat\webapps\下。
如果程序和发布没有错误的话,就把服务的*.class放在common\class下,如果是*.jar就放在common\lib下。另外要把xerces.jar和soap.jar拷贝到tomcat\common\lib下面。
最后测试是否配置成功,http://localhost:8080/soap
下面是一个简单的SOAP服务调用的例子:
服务端程序:
package hello;
public class HelloServer
{
public String sayHelloTo(String name)
{
System.out.println("sayHelloTo(String name)");
return "Hello " + name + ", How are you doing?";
}
}
这里不介绍用web界面管理工具部署服务,只说明一下怎样从命令行部署服务。用命令行Java工具org.apache.soap.server.ServiceManagerClient,它是一个Apache SOAP附带的类。这个类要求有两个必不可少的参数,一个指向Apache SOAP路由Servlet(即rpcrouter)的URL,以及一个动作。这个动作可以是以下四者之一:deploy,undeploy,list,或query。
描述HelloWorld部署细节的部署XML文件(DeploymentDescriptor.xml)如下:
<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment"
id="urn:Hello">
<isd:provider type="java" scope="Application" methods="sayHelloTo">
<isd:java class="hello.HelloServer" static="false"/>
</isd:provider>
</isd:service>
从命令行部署HelloWorld服务:
java org.apache.soap.server.ServiceManagerClient
http://localhost:8080/soap/servlet/rpcrouter
deploy DeploymentDescriptor.xml
要验证服务是否部署成功,输入以下命令:
java org.apache.soap.server.ServiceManagerClient
http://localhost:8080/soap/servlet/rpcrouter query urn:Hello
这时,应该看到和DeploymentDescriptor.xml文件内一样的XML。
列出服务命令:
java org.apache.soap.server.ServiceManagerClient
http://localhost:8080/soap/servlet/rpcrouter list
删除服务命令:
java org.apache.soap.server.ServiceManagerClient
http://localhost:8080/soap/servlet/rpcrouter
undeploy urn:Hello
HelloWorld客户程序
package hello;
import java.net.URL;
import java.util.Vector;
import org.apache.soap.SOAPException;
import org.apache.soap.Constants;
import org.apache.soap.Fault;
import org.apache.soap.rpc.Call;
import org.apache.soap.rpc.Parameter;
import org.apache.soap.rpc.Response;
public class Client
{
public static void main(String[] args) throws Exception
{
if(args.length == 0)
{
System.err.println("Usage: java hello.Client [SOAP-router-URL] ");
System.exit (1);
}
try
{
URL url = null;
String name = null;
if(args.length == 2)
{
url = new URL(args[0]);
name = args[1];
}
else
{
url = new URL("http://localhost:8080/apache-soap/servlet/rpcrouter");
name = args[0];
}
// 构造Call对象
Call call = new Call();
call.setTargetObjectURI("urn:Hello");
call.setMethodName("sayHelloTo");
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
Vector params = new Vector();
params.addElement(new Parameter("name", String.class, name, null));
call.setParams(params);
// 发出调用
Response resp = null;
try
{
resp = call.invoke(url, "");
}
catch( SOAPException e )
{
System.err.println("Caught SOAPException (" + e.getFaultCode() + "): " +
e.getMessage());
System.exit(-1);
}
// 检查应答
if( !resp.generatedFault() )
{
Parameter ret = resp.getReturnValue();
Object value = ret.getValue();
System.out.println(value);
}
else
{
Fault fault = resp.getFault();
System.err.println("Generated fault: ");
System.out.println (" Fault Code = " + fault.getFaultCode());
System.out.println (" Fault String = " + fault.getFaultString());
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
package hello;
public class HelloServer
{
public String sayHelloTo(String name)
{
System.out.println("sayHelloTo(String name)");
return "Hello " + name + ", How are you doing?";
}
public String sayHelloTo(Name theName)
{
System.out.println("sayHelloTo(Name theName)");
return "Hello " + theName.getName() + ", How are you doing?";
}
}
重载的方法需要一个对Name JavaBean的引用。Name JavaBean的定义如下:
package hello;
public class Name
{
private String name;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
使用管理工具部署服务
与部署普通服务不同的是,在Number of Mappings输入框输入1,它表示将给出一个映射(即Name JavaBean)的信息。保留Encoding Style的值为SOAP,把NameSpace URI设置成对象的ID:在本例中,它是urn:Hello。接下来,把Local Part和Java Type输入框设置成Name JavaBean的完整名字,即hello.Name。最后,把Java to XML Serializer和XML to Java Deserializer输入框设置成org.apache.soap.encoding.soapenc.BeanSerializer,这是一个实现了Serializer和Deserializer接口的类,用来串行化和反串行化Name JavaBean。如果你用到了更多的JavaBean,则应该在这个表格中输入其他Bean的信息,同时还应该更新Number of Mappings输入框的值,使之反映出表格中实际被使用的行数。
从命令行部署服务描述部署服务的XML文件如下所示:
<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment" id="urn:Hello">
<isd:provider type="java" scope="Application" methods="sayHelloTo">
<isd:java class="hello.HelloServer" static="false"/>
</isd:provider>
<isd:mappings>
<isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:x="urn:Hello" qname="x:hello.Name"
javaType="hello.Name"
java2XMLClassName="org.apache.soap.encoding.soapenc.BeanSerializer"
xml2JavaClassName="org.apache.soap.encoding.soapenc.BeanSerializer"/>
</isd:mappings>
</isd:service>
HelloWorld客户程序
由于调用方法的一个参数是一个JavaBean,所以必须手工设置一个类型映射注册项:先创建org.apache.soap.encoding.SOAPMappingRegistry类的一个实例,然后调用它的mapTypes()方法。正如mapTypes()方法名字所预示的,它用来注册一个以前未知的类型,比如定制的JavaBean.mapTypes()方法的参数包括要使用的编码方式、限定的JavaBean名字、类型的完整类名、串行化器和反串行化器。在本例中,执行串行化任务的是标准的Bean串行化器。限定的JavaBean名字包含一个元素的名字,包括它所属的名称空间。在本例中,Name JavaBean的限定名字由名称空间URI(urn:Hello)和本地名字(hello.Name)结合构成。接下来,客户程序必须告诉Call对象使用新的注册器而不是默认注册器。为此要调用Call对象的setSOAPMappingRegistry()方法。手工设置好类型映射注册器之后,接下来还必须为Call对象设置参数。这一步骤可以按前面介绍的方法完成,不同之处在于,现在不再用字符串类型的名字作为参数,而是用JavaBean作为参数。完整的程序如下:
package hello;
import java.net.URL;
import java.util.Vector;
import org.apache.soap.SOAPException;
import org.apache.soap.Constants;
import org.apache.soap.Fault;
import org.apache.soap.rpc.Call;
import org.apache.soap.rpc.Parameter;
import org.apache.soap.rpc.Response;
import org.apache.soap.encoding.SOAPMappingRegistry;
import org.apache.soap.encoding.soapenc.BeanSerializer;
import org.apache.soap.util.xml.QName;
public class Client2
{
public static void main(String[] args) throws Exception
{
if(args.length == 0)
{
System.err.println("Usage: java hello.Client [SOAP-router-URL] ");
System.exit (1);
}
try
{
URL url = null;
String name = null;
if(args.length == 2)
{
url = new URL(args[0]);
name = args[1];
}
else
{
url = new URL("http://localhost:8080/apache-soap/servlet/rpcrouter");
name = args[0];
}
// 构造调用对象
Call call = new Call();
call.setTargetObjectURI("urn:Hello");
call.setMethodName("sayHelloTo");
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
// 创建类型映射注册器
SOAPMappingRegistry smr = new SOAPMappingRegistry();
BeanSerializer beanSer = new BeanSerializer();
// 映射类型
smr.mapTypes(Constants.NS_URI_SOAP_ENC,
new QName("urn:Hello", "hello.Name"),
hello.Name.class, beanSer, beanSer);
call.setSOAPMappingRegistry(smr);
// 设置参数
Vector params = new Vector();
Name theName = new Name();
theName.setName(name);
params.addElement(new Parameter("name", hello.Name.class,
theName, null));
call.setParams(params);
// 发出调用
Response resp = null;
try
{
resp = call.invoke(url, "");
}
catch( SOAPException e )
{
System.err.println("Caught SOAPException (" +
e.getFaultCode() + "): " + e.getMessage());
System.exit(-1);
}
// 检查应答
if( !resp.generatedFault() )
{
Parameter ret = resp.getReturnValue();
Object value = ret.getValue();
System.out.println(value);
}
else
{
Fault fault = resp.getFault();
System.err.println("Generated fault: ");
System.out.println (" Fault Code = " + fault.getFaultCode());
System.out.println (" Fault String = " + fault.getFaultString());
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
编译运行程序
创建一个hello目录,把Client1.java、Client2.java和HelloServer.java复制到这个目录。进入hello所在的父目录后,运行以下命令:
编译程序 javac hello\*.java
运行程序 java hello.Client tom
打开TCP Tunnel/Monitor的命令
java org.apache.soap.util.net.TcpTunnelGui 8081 localhost 8080