使用SOAP协议来实现SOA服务
Soap是简单对象访问协议(Simple Object Access Protocal)的缩写,它是由W3C定义的Web服务的实现标准。基本说来,它定义了要交换的消息的结构,SOAP消息由信封、消息头和消息体构成。下面您会看到,SOAP协议针对问题的复杂程度不同,其定义的层次也不尽相同。SOAP提供了很多强大的功能,其中包括:
(1) 能自动生成消息交换过程中所需要的类;
(2) 自动生成Web服务描述符(WSDL);
(3) 能自动从Web服务的WSDL中生成客户端类;
(4) 能够使用HTTP之外的协议(如SMTP和JMS等)进行消息传输;
(5) 提供了消息验证机制;
(6) 能够建立有状态的会话;
为了让您对该协议的实现有一个比较直观的了解,我们还是以前面的例子,及JDK6自带的功能来定义和发布Web服务。我们前面的例子其实是利用JAXB库对XML消息文档和Java对象之间进行自动绑定,这里我们使用JAX-WS库进行这个操作。JAX-WS库能明显提高软件层的抽象化层次。
现在,让我们看看使用SOAP创建一个插入和更新的Web服务是何其简单:
代码清单14 – 使用JAX-WS注解创建SOAP服务
- package com.packt.soajava.soap.service.item;
- import javax.jws.WebMethod;
- import javax.jws.WebService;
- import javax.xml.ws.Endpoint;
- import com.packt.soajava.model.item.Item;
- import com.packt.soajava.model.item.Outcome;
- @WebService
- public class ItemWs {
- @WebMethod
- public Outcome insert(Item item) {
- //Insert item ...
- System.out.println("Inserting item "+item.getId());
- Outcome outcome = new Outcome();
- outcome.setRetCode("OK");
- outcome.setRetMessage("Item was inserted successfully");
- return outcome;
- }
- @WebMethod
- public Outcome update(Item item) {
- //Update item ...
- System.out.println("Updating item "+item.getId());
- Outcome outcome = new Outcome();
- outcome.setRetCode("OK");
- outcome.setRetMessage("Item was updated successfully");
- return outcome;
- }
您可以看到,上面的代码非常简洁,抽象化层次很高,它并不需要那些序列化和反序列化的代码,它只包含了那些必需的代码。用SOAP实现Web服务和我们前面介绍的方法(POX-over-HTTP及REST)都不尽相同。当我们使用基本的POX-over-HTTP方法开发Web服务时,我们需要为某个功能(比如商品这个业务对象上的功能)创建几个Servlets;在使用REST时我们需要新建一个类,而且REST中需要设计的业务方法正好和HTTP谓词相一致而已。但使用SOAP协议,我们可以在Web服务中定义多种方法,每种方法都相互独立,只要它们的方法签名不同即可。
为了发布上面的Web服务,我们还需要完成以下几步。首先,我们需要生成消息交换中所需要的类,这可通过JDK6自带的wsgen工具完成,请打开命令行并输入下列命令:
<JDK6_HOME>/bin/wsgen -cp <ProjectClassesRoot> -d <ProjectSourceRoot> -keep com.packt.soajava.soap.service.item.ItemWs
上面的命令将生成服务所需要的类,并把这些新生成的类放到<ProjectSourceRoot>(-d选项)所定义的路径中,-cp选项定义了ItemWs类所在的类路径。(译者注,在我的机器上,我运行的命令为:wsgen -cp C:/carl/workspace/SoaBookPoxHttp/WebRoot/WEB-INF/classes/ com.packt.soajava.soap.service.item.ItemWs -d C:/carl/workspace/SoaBookPoxHttp/src)。运行上述命令后,您会发现您的项目源文件夹中新增了一个新包(com.packt.soajava.soap.service.item.jaxws),这个包中有4个类。实际上,每个Web服务方法将产生两个类,其中的一个类名和Web服务方法名相同但大写首字母,另一个类名由方法名加Response构成。
现在,我们就可以发布Web服务了,JDK6主要使用了原型使Web服务的发布变得异常简单,您只需要写一个主类,运行下面一行代码即可。
Endpoint.publish( "http://localhost:8001/SoaBookSOAP_server/itemWs", new ItemWs());
到此为止,我们就完成了SOAP形式的Web服务的发布,当然,您也可以修改上面URI中的地址和端口号。
那我们怎样才能检测我们的Web服务已经正确发布了呢?最简单的方法是打开浏览器,输入下面的地址,请求该服务的WSDL:
http://localhost:8001/SoaBookSOAP_server/itemWs?WSDL
您会在浏览器中看到由SOAP自动生成的WSDL(Web服务描述语言),其内容代表了Web服务的结构,WSDL文件对客户端非常重要,客户端可以依据它来自动生成客户端需要的类。JDK6自带的wsimport工具可以根据WSDL在客户端自动生成需要的类,其用法如下:
<JDK6_HOME>/bin/wsimport -d <ClientProjectSourceRoot> -p com.packt.soajava.soap.client.test.item –keep http://localhost:8001/SoaBookSOAP_server/itemWs?WSDL
上面的命令可以在客户端生成需要的类,并把它们放到客户端项目文件夹中(由-d选项指定),-p选项是为客户端生成的类指定包名(译者注:我本机上运行的示例命令为:wsimport -d C:/temp/ -p com.packt.soajava.soap.client.test.item -keep http://localhost:8001/SoaBookSOAP_server/itemWs?WSDL)。我们会在这些自动生成的类中发现ItemWsService类(译者注:我觉得是ObjectFactory这个类,不是作者说的这个),它是客户端的工厂类,您还会发现ItemWs接口,ItemWsService工厂产生的服务代理会支持这个接口。
现在,客户端的代码就变得异常简单:
- ItemWsService service = new ItemWsService();
- ItemWs itemWs = service.getItemWsPort();
- Item item1 = new Item();
- item1.set ...
- Outcome outcome = itemWs.insert(item1);
请您注意,支持SOAP的所有技术都能根据已经发布的Web服务的WSDL,自动生成自己的客户端类。
总之,使用SOAP方法,我们可以使Web服务两端的代码变得简洁,而那些中间比较困难的操作都交给那些自动产生的类来替我们完成。
[译者注,如果您有兴趣,请补齐上面的代码,并创建一个客户端项目来测试一下您创建的SOAP形式的Web服务。如果有困难,请参考附件,这是我的参考实现。首先,您需要创建两个项目,一个是服务器端的实现,另一个是客户端测试项目。服务器端的您需要完成Item.java, ItemWs.java, Outcome.java, Test.java这几个类的代码,然后运行genws命令,然后运行主类Test;客户端请先运行wsimport命令生成必须的客户端类,然后将它们导入到客户端项目中,然后再手动添加一个测试类TestMain.java。此时,您可以使用Apache TCPMon工具观察Soap请求和应答的XML文档,如下图所示:
】
本文源代码下载地址:http://blog.ccidnet.com/job-htm-action-download-itemid-813217-aid-88694.html