繁体中文
设为首页
加入收藏
当前位置:.Net技术首页 >> Asp.Net开发 >> SOAP净化有线协议(二):Apache SOAP介绍(2) 

SOAP净化有线协议(二):Apache SOAP介绍(2) 

2007-03-15 08:00:00  作者:  来源:互联网  浏览次数:0  文字大小:【】【】【
简介:三、带有JavaBean的HelloWorld实例 如前所述,Apache SOAP提供了许多预先构造的串行化和反串行化方法,其中包括为利用Java Vector、Enumeration、数组、JavaBean作为参数和返回值而提供的串行化器和反串行化器。...
关键字:SOAP 有线 协议 Apache zt

三、带有JavaBean的HelloWorld实例

如前所述,Apache SOAP提供了许多预先构造的串行化和反串行化方法,其中包括为利用Java Vector、Enumeration、数组、JavaBean作为参数和返回值而提供的串行化器和反串行化器。在这一部分,我将修改HelloWorld服务,通过一个JavaBean传入接收Hello信息的用户名。

3.1、HelloWorld服务

改写后的HelloWorld服务完整代码如下:

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?";

}

}

服务的代码仍旧很简单,仍旧类似于不用JavaBean时的HelloWorld服务。不过,这意味着最复杂的工作都转移到了客户端。事实上,这个版本的服务与以前版本的唯一差别在于,现在出现了一个重载的sayHelloTo()方法。上面的代码中重载后的方法用粗体字显示。

重载的方法需要一个对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;

}

}

3.2、部署服务

部署一个使用了JavaBean的服务时,需要为Apache SOAP服务器提供一些额外的信息。因此,现在部署服务的过程稍微复杂一点。

■ 使用管理工具部署服务

要使用管理工具部署这个新版的HelloWorld服务,首先按照前面所介绍的步骤进行,但这一次不要点击Deploy按钮。现在,在Number of Mappings输入框输入1,它表示我们将给出一个映射(即Name JavaBean)的信息。紧接Mappings之下有一个表格,我们要用到这个表格的第一行。保留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(比如还有一个Address Bean),则应该在这个表格中输入其他Bean的信息,同时还应该更新Number of Mappings输入框的值,使之反映出表格中实际被使用的行数。

■ 从命令行部署服务

要从命令行进行部署,我们只需修改作为命令行参数传入的XML部署描述器文件。修改后的XML文件如下所示:

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"/>

正如在前一个例子中,这些XML代码所包含的信息和通过Web界面的管理工具所提供的信息一样。

3.3、HelloWorld客户程序

和第一个例子一样,客户程序更复杂,也更令人感兴趣。这里我不再仔细分析整个客户程序,而是介绍两个客户程序版本的不同之处。由于调用方法的一个参数(在本例中,它是唯一的参数)是一个JavaBean,所以必须手工设置一个类型映射注册项。这个任务通过如下步骤完成:先创建org.apache.soap.encoding.SOAPMappingRegistry类的一个实例,然后调用它的mapTypes()方法。正如mapTypes()方法名字所预示的,它用来注册一个以前未知的类型,比如定制的JavaBean。mapTypes()方法的参数包括要使用的编码方式、限定的JavaBean名字、类型的完整类名、串行化器和反串行化器。在本例中,执行串行化任务的是标准的Bean串行化器。限定的JavaBean名字包含一个元素的名字,包括它所属的名称空间。在本例中,Name JavaBean的限定名字由名称空间URI(urn:Hello)和本地名字(hello.Name)结合构成。请看下面的代码片断:

// 创建类型映射注册器

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对象使用新的注册器而不是默认的注册器。为此,我们要调用Call对象的setSOAPMappingRegistry()方法,如下所示:

call.setSOAPMappingRegistry(smr);

手工设置好类型映射注册器之后,接下来还必须为Call对象设置参数。这一步骤可以按前面介绍的方法完成,不同之处在于,现在我们不再用字符串类型的名字作为参数,而是用JavaBean作为参数,如下所示:

// 设置调用参数

Vector params = new Vector();

Name theName = new Name();

theName.setName(name);

params.addElement(new Parameter("name", hello.Name.class, theName, null));

call.setParams(params);

客户程序剩下的部分和原来的版本一样。Listing 3显示了完整的客户程序代码:

Listing 3: Client2.java

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目录放到了Apache SOAP的示例目录(即E:\soap-2_0\samples)之下。编译程序时,classpath中只需包含hello目录的父目录(即E:\soap-2_0\samples)、soap.jar和xerces.jar。我用下面的批命令编译程序:

set CLASSPATH=E:\soap-2_0\samples\;E:\soap-2_0\lib\soap.jar;E:\xerces-1_2_0\xerces.jar

javac -d .. HelloServer.java Client.java Client2.java

注意:从hello目录执行这个批命令文件。

要使用这个服务,除了部署它之外,还需要修改Web服务器的classpath,确保Web服务能够找到hello.HelloServer类——对于本例,这是指把E:\soap-2_0\samples加入到Web服务器的classpath。对classpath进行必要的修改之后,重新启动Web服务器。接下来就可以运行客户程序了。下面是我运行hello.Client的批命令文件:

set CLASSPATH=E:\soap-2_0\samples\;E:\soap-2_0\lib\soap.jar;E:\xerces-1_2_0\xerces.jar

java hello.Client Tarak

这里的classpath和编译程序时用的classpath相同。

最后,运行hello.Client2的批命令文件可以如下:

set CLASSPATH=E:\soap-2_0\samples\;E:\soap-2_0\lib\soap.jar;E:\xerces-1_2_0\xerces.jar

java hello.Client2 Tarak

观察Web服务器的控制台窗口,看看在运行两个不同的客户程序时,HelloWorld服务的哪些方法正在被调用。

■ 结束语

在这篇文章中,我介绍了如何用Apache SOAP实现来创建简单的基于SOAP的服务。在SOAP实现方面,另一个重要的竞争者是Microsoft。遗憾的是,“纯”Java开发者在使用Microsoft实现的时候会有一段艰苦的时光,因为它的实现包含了COM对象。

在下一篇文章中,我将介绍Apache SOAP支持的另一种创建服务的方式:使用JavaScript之类的脚本语言,而不是Java。另外,我还要介绍一个很不错的JavaScript引擎,即Rhino。

■ 参考资源

W3C的SOAP 1.1规范:

http://www.w3.org/TR/SOAP/ 下载Apache SOAP:

http://xml.apache.org/dist/soap/ 有关IBM SOAP工程的更多信息:

http://www.alphaworks.ibm.com/tech/soap4j Apache SOAP可用功能的一个清单:

http://xml.apache.org/soap/features.html Apache许可协议:

http://www.apache.org/LICENSE.txt 下载Tomcat 3.1

http://jakarta.apache.org/builds/jakarta-tomcat/release/v3.1.1/bin/ 下载Apache Xerces 1.2版本:

http://xml.apache.org/dist/xerces-j/ "MS SOAP SDK vs IBM SOAP4J: Comparison & Review," James Snell (O'Reilly):

http://windows.oreilly.com/news/soapreview_0600.html

责任编辑:admin
相关文章