三、带有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文件如下所示:
<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> |
正如在前一个例子中,这些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() ) 更多内容请看PCdog.com--OSPF路由协议 路由协议专题 |
