使用WSDL发布WebService(第二部分)简单对象访问协议——学习SOAP语法和使用SOAP发布WSDL

来源:互联网 发布:新闻资讯类数据分析 编辑:程序博客网 时间:2024/04/28 19:59

作者:Bilal Siddiqui (wap_monster@yahoo.com)
CEO, WAP Monster
01 Mar 2002

译者:梅青松

注:由于时间和本人水平问题差错在所难免,还往各位海涵。

     简单对象访问协议(SOAP)提供了访问远程对象的方法。这样的对象有JavaBean,EJB组件,COM和COM+对象等等。这些对象使用不同的公司,可能在互联网上随处可见。因此SOAP是一种在互联网上交换企业信息的机制。在本文中,笔者将讨论SOAP通信的细节,对象如何使用SOAP显示其功能,如何调用SOAP对象以及如何在SOAP感知软件中交换信息。他将演示如何将第一部分中的WSDL程序发布为SOAP服务,及其远程调用。

一.SOAP 和 WSDL

    我在这个系列的第一部分介绍了WSDL。WSDL描述Web Service的接口。Web Service的拥有者将使用SOAP实现这些的接口。因此WSDL服务就以SOAP服务的形式存在。一旦Web Service的用户拥有了WSDL文件,他就知道了接口的详细资料,就可以使用SOAP同Web Service通信。

    可以将你通过WSDL接口发布的Web Service看作对象,它可以通过SOAP从互联网上远程访问。既然服务都是对象,必然就会有一些属性跟每个服务及其行为相关。SOAP消息是可能工作在HTTP上的XML文件。

二.使用SOAP的原因

    B2B(business-to-business)和A2A(application-to-application)需要通信的企业双方的指示以交换其信息。工作流的概念用于B2B,并贯穿于企业集成。例如,某个企业调用供应商的服务以满足客户的需求,这就形成了一条垂直的供应链。有的供应商也会拓展供应联调用其他企业的服务。

    显然这类应用软件的交互性极其重要。任一企业都只是实现SOAP通信的一端,而另一端由互联网上的其他人实现。

    在未来的几年里,企业集成和交互能力将成为软件工程师和企业极具挑战性的任务。平台依赖性也将是集成和交互能力达成的一大难题。SOAP是至今为止最简单的实现企业集成和交互能力的机制。

三.SOAP架构

    在初步了解了SOAP及其作用后,下面我将讨论它的架构以了解其内部的情况。在图Figure 1中,你可以看见下面的组件运用于典型的SOAP通信机制中:

1.  SOAP Client

2.  SOAP Service

3.  Actual Service

 

 

Figure 1. Components of a typical SOAP communication architecture

下面讨论上面提及的各个实体在架构中的角色。

SOAP Client

SOAP Client是一个SOAP感知机器,它可以产生SOAP请求并通过HTTP将SOAP请求发送给SOAP Server。SOAP Client是一种SOAP消息。一般来说有两种SOAP消息:SOAP Client发送给SOAP Service的SOAP请求消息和SOAP Service发送给SOAP Client的SOAP响应消息。Listing 1是一个典型SOAP请求消息,而Listing 2则是一个典型SOAP响应消息。

<SOAP-ENV:Envelope  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" >

   <SOAP-ENV:Body>

         <m:getListOfModels xmlns:m = "uri reference" >

         </m:getListOfModels>

    </SOAP-ENV:Body>

</SOAP-ENV:Envelope>

SOAP Server

    SOAP Server也是一个SOAP感知机器,它可以接受SOAP Client发来的请求并创建合适的响应。加密的响应会发给发出请求的SOAP Client。在SOAP Server内部有三个实体:

1.  Service manager

2.  Deployed service list

3.  XML translator

Service manager管理响应请求的服务。在Listing 1中的SOAP请求中,节点<m:getListOfModels xmlns:m=”urn:MobilePhoneService”>包含了服务的名称。Service manager会读出Service Client向要调用的服务的名称并向包含SOAP Service中所有服务列表的Deployed service list查询是否有该项服务。如果有Service manager就将SOAP请求发给XML translator。XML translator将SOAP请求的XML结构转换成程序员用来实现Actual Service的程序语言。XML translator还将Actual Service返回的响应转回XML结构的SOAP响应。Listing 2就是一个SOAP响应的例子。

<SOAP-ENV:Envelope  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

   <SOAP-ENV:Body>

  <m:getListOfModelsResponse xmlns:m="urn:MobilePhoneservice">

    <Model>M1</Model>

    <Model>M2</Model>

    <Model>M3</Model>

  </m:getListOfModelsResponse>

    </SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Actual Service

Figure 1中标为Actual Service的方框显示了Actual Srrvice的位置。服务的实现可能是一个COM组件或是一个JavaBean组件。XML translator会把XML结构转换成合适的方法调用。当XML translator调用Actual Srrvice的方法时,这些方法会执行其功能并返回结果给XML translator。

Figure 1中连接XML translator和Actual Service的箭头的两端都在一个企业里,这意味着同一个组织控制着通信两端的接口。与此相反的是SOAP Client和SOAP Service穿越了企业的边界。这就是SOAP的用途。

SOAP请求响应机制

    SOAP Client传输SOAP消息给SOAP Service时使用HTTP协议传输。这称为SOAP绑定HTTP.当SOAP Service收到消息时,他将消息传给Service Maneger. SOAP Service检查Deployed service list中是否有SOAP消息请求的服务。如果没有该项服务,他将请求失败的响应发回给SOAP Client。但如果有该项服务,就由XML translator进行适合的语言转换,访问actual service的实现。服务的实现会处理请求并返回结果给XML translator. XML translator再将结果转换为SOAP Client理解的SOAP响应。同样,HTTP绑定也用在SOAP响应的传输上。

SOAP绑定HTTP

    当你将HTTP同SOAP帮定绑定或是在HTTP上操作SOAP时,你实际上在SOAP请求和响应上添加了HTTP头。Listing 1是典型的SOAP请求,而Listing 3,4,5,6演示了在Listing 1上添加了HTTP头的SOAP请求。与此类似的是Listing 7演示了在Listing 2上添加了HTTP头的SOAP响应。

    当你在HTTP上使用SOAP时,Content-Type字段必须为text/html.在Listing 7中可以看到Listing 3的细节。

一个使用HTTP的SOAP请求

  你可以将SOAP联合在HTTP的请求方法POST上。要发送一个SOAP HTTP请求,你必须在HTTP头上提供一个SOAPAction字段。

SOAPAction定义了SOAP请求的目的。服务器(例如过滤HTTP上SOAP请求消息的防火墙)可以使用SOAPAction的值做决定。

HTTP客户端在发出SOAP请求时必须使用HTTP头的这个字段。SOAPAction可以取的值如下所示:

SOAPAction:”URI-Reference”

SOAPAction:”filename”

SOAPAction:””

SOAPAction

POST /Vendors HTTP/1.1

Host: www.mobilephoneservice.com

Content-Type:"text/xml";Charset="utf-8"

Content-Length: nnnn

SOAPACtion:"www.mobilephoneservice.com/Vendors/MobilePhoneservice#getListOfModels"

 

<?xml version="1.0"?>

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"  >

  <SOAP-ENV:Body>

    <m:getListOfModels xmlns:m="urn:MobilePhoneservice" >

    </m:getListOfModels>

  </SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Listing 3在SOAPAction中包含了下面的URI引用

www.mobilephoneservice.com/Vendors/MobilePhoneservice#getListOfModels

这个SOAPAction说明了两件事:一是SOAP发布的详细地址www.mobilephoneservice.com/Vendors/MobilePhoneservice,二是我们感兴趣的方法的名称(#getListOfModels).

 

POST /Vendors HTTP/1.1

Host: www.mobilephoneservice.com

Content-Type:"text/xml";Charset="utf-8"

Content-Length: nnnn

SOAPAction:"MobilePhoneservice#getListOfModels"

 

<?xml version="1.0"?>

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"  >

  <SOAP-ENV:Body>

    <m:getListOfModels xmlns:m="urn:MobilePhoneservice" >

    </m:getListOfModels>

  </SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Listing 4在SOAPAction中包含了一个文件名(MobilePhoneservice#getListOfModels)。MobilePhoneservice文件必须放在主机URI下(www. Mobilephoneservice.com/Vendors)。主机URI是由HTTP头的host字段加文件夹名(/Vendors)组成的。

POST /Vendors HTTP/1.1

Host: www.mobilephoneservice.com

Content-Type:"text/xml";Charset="utf-8"

Content-Length: nnnn

SOAPAction:""

 

<?xml version="1.0"?>

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"  >

  <SOAP-ENV:Body>

    <m:getListOfModels xmlns:m="urn:MobilePhoneservice" >

    </m:getListOfModels>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Listing 5的SOAPAction中包含了一个控字符串(””)。空字符串说明SOAP的目标跟主机URI相同www. Mobilephoneservice.com/Vendors

POST /Vendors HTTP/1.1

Host: www.mobilephoneservice.com

Content-Type:"text/xml";Charset="utf-8"

Content-Length: nnnn

SOAPAction:

 

<?xml version="1.0"?>

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"  >

  <SOAP-ENV:Body>

    <m:getListOfModels xmlns:m ="urn:MobilePhoneservice" >

    </m:getListOfModels>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Listing 6的SOAPAction没有值。这表明没有消息的目标的信息。

使用HTTP的SOAP响应

SOAP响应有两种类型:

        成功的SOAP操作产生的SOAP结果。

        不成功的SOAP操作产生的SOAP错误消息。

HTTP/1.1 Content-Type:"text/xml"; Charset="utf-8"

Content-Length: nnnn

 

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" >

<SOAP-ENV:Body>

  <m:getListOfModelsResponse xmlns:m = "URI-Reference">

    <model>m1</model>

    <model>m2</model>

  </m:getListOfModels>

</SOAP-ENV:Body>

Listing 7就是一个从SOAP服务返回的有意义的结果。

Listing 8则是一个典型的SOAP错误消息。SOAP HTTP响应在HTTP中添加了通信状态信息的HTTP状态码的语义。当处理请求失败时,SOAP HTTP服务器必须发出一个包含带有SOAP错误元素的SOAP消息的HTTP 500内部服务错误的响应。

HTTP/1.1 500 Internal Server Error

Content-Type: "text/xml"; Charset="utf-8"

Content-Length: nnnn

 

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" >

  <SOAP-ENV:Body>

    <SOAP-ENV:Fault> 

    <faultstring>Failed to process the request</faultstring>

    </SOAP-ENV:Fault>

  </SOAP-ENV:Body>

</SOAP-ENV:Envelope>

SOAP和e-mail

HTTP并非是绑定SOAP消息的唯一解决方案。你可以在HTTP步使用的地方使用其他的机制如SMTP进行SOAP绑定。绑定SOAP到SMTP,你可以创建一个单向的通道。两个单向的消息可以建立请求/响应通讯。为了使用SMTP发送SOAP消息,你必须按照下面的步骤做:

        使用SMTP头的 MIME-Version字段

MIME-Version字段使用版本号区别不同版本的MIME(多用途网际邮件扩充协议).他允许邮件服务代理(如pop 服务)区别新老版本MIME产生的邮件消息。图Listing 9就是用了SMTP头的 MIME-Version字段。

TO: <info@waxsys.com>

From: <abc@punjab.com>

Reply-To: <abc@punjab.com>

Date: SAT, 2 Feb 2002 16:00:00 

Message-Id: <4FAB345C8D93E93B7A6E9@punjab.com>

MIME-Version: 1.0

Content-Type: text/xml; charset=utf-8

Content-Transfer-Encoding: QUOTED-PRINTABLE

 

<?xml version ="1.0" encoding="UTF-8"?>

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

  <SOAP-ENV:Body>

    <prnt:echoString xmlns:prnt="http://waxsys.com">

      <msgString>Put your mail Message</msgString>

    </prnt:echoString>

  </SOAP-ENV:Body>

</SOAP-ENV:Envelope>

        使用SMTP头的 Content-Type字段

Content-Type字段用来标明消息体重的数据类型。”text/xml”就是一个可以去的值。图Listing 9就使用了Content-Type字段。

        使用SMTP头的 Content-Transfer-Encoding字段

Content-Transfer-Encoding字段用来说明传输编码的类型,就是说你想传输什么样的数据,是字符格式还是二进制格式的。图Listing 9使用了QUOTED-PRINTABLE编码就是ASCII字符集中可打印的字符。它是以邮件传出代理不太可能修改结果字节的方式进行数据编码的

SOAP模式及其撰写

SOAP消息

SOAP消息就是一个XML文档,其中必须有一个包含可选SOAP头和必需的SOAP体的SOAP Envelope。

SOAP模式的元素:

        Envelope

        Header

        Body

        Faule

Envelope:

Envelope是SOAP消息的根结点。该节点在SOAP消息中是必须出现的。Envelope使用的SOAP名称空间标识 :http://schemas.xmlsoap.org/soap/envelope/ 是必需的。如果Envelope节点包含错误的名称空间就会产生一个Envelope名称空间版本的错误。Listing 10是一个空的Envelope节点。你称之为空信以强调在”post”之前Envelope节点必须包含一封”信”。SOAP模式中的信就是一个SOAP体而HTTP POST则是传输机制。

Listing 10

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

 

</SOAP-ENV:Envelope>

Header

SOAP头是可选的。你可以跳过SOAP头直接在SOAP Envelope中封装一个SOAP体。SOAP头提供了一个拓展SOAP消息功能的机制。例如,在SOAP头中添加验证就是一个典型的拓展。本例中就有一个将在底层传输的验证框架。Listing 11中可以看到SOAP中Header的实现。

Listing 11

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

<SOAP-ENV:Header>

  <m:Order xmlns:m="some URI" SOAP-ENV:mustUnderstand="1">

  </m:Order>

</SOAP-ENV:Header>

</SOAP-ENV:Envelope>

Body

Body节点将会包含你想发送的消息。这是一个必需的节点,而它的字节点通常属于一个用户自定义的名称空间中。Listing 12显示了一个含有用户自定义名称空间“u”的SOAP消息。Body节点用来包含必需的信息。Body节点是SOAP消息必需的,而且它必须是SOAP Envelop节点的直接子节点。他必须直接跟在SOAP Header后面。如果没有Header节点,则直接跟在Envelop节点后面。Body可以包含字节点,字节点可以有其名称空间。

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

<SOAP-ENV:Header>

  <m:Order xmlns:m="some URI" SOAP-ENV:mustUnderstand="1">

  </m:Order>

</SOAP-ENV:Header>

<SOAP-ENV:Body>

  <u:GetPrice xmlns:u="some URI" >

    <model>m1</model>

  </u:GetPrice>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Fault

这个节点指示错误消息。它必须在Body中出现而最多出现一次。通常,Fault节点出现在SOAP响应中表明SOAP请求出错了。

Fault的子节点:

        faultcode(fault标识)

        faultstring(fault描述)

        faultactor(引发错误的原因)

        detail(错误的细节。通常是相应遇SOAP请求的Body中名称空间的应用程序的错误细节。)

Listing 13是一个典型的fault消息。

Listing 13

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

<SOAP-ENV:Header>

<m:Order xmlns:m="some URI" SOAP-ENV:mustUnderstand="1">

</m:Order>

</SOAP-ENV:Header>

<SOAP-ENV:Body>

<SOAP-ENV:Fault>

<faultcode>SOAP-ENV:Server</faultcode>

<faultstring>Not necessary information</faultstring>

<detail>

  <d:faultdetail xmlns:d = "uri-referrence">

    <msg>

      application is not responding properly.

    </msg>

    <errorcode>12</errorcode>

  </d:faultdetail>

</detail>

</SOAP-ENV:Fault>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

第一部分的WSDL文件的SOAP请求

在大致介绍了SOAP消息的语法之后,我将演示如何为本系列文章中第一部分的MobilePhoneservice开发一个SOAP请求。在第一部分中你为MobilePhoneservice设计了一个完整的WDL接口。移动电话公司在MobilePhoneservice提供了两个方法:一个是getListOfModels,另一个是getPrice(modelNumber)GetListOfModels没有参数,返回移动电话型号列表而getPrice(modelNumber)有一个参数modelNumber,返回请求型号的价格。你需要把他们做成SOAP请求的格式,在这之前我要展示一下SOAP请求和响应的一般格式。

<SOAP-ENV:Envelope xmlns:SOAP-ENV ="SOAP schema's URI"

<SOAP-ENV:Body>

  <Instance:"Method Name" xmlns:Instance= "URI where method is located">

    <parameter1>value</parameter1>

    <parametern>value</parametern>

  </Instance:"Method Name">

</SOAP_Envelop:Body>

</SOAP-ENV:Envelope>

一个SOAP请求或响应只能定义服务的一个方法。SOAP请求的一般形式如Listing 14所示。而Listing 16则是一个调用getListOfModels方法的实际请求。在Listing 16中,我提供了方法的名称和URI。由于getListOfModels没有参数,因此<m: getListOfModels>是一个空节点。

Listing 15

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

<SOAP-ENV:Body>

  <Instance:"Method Name"+"Response" 

  xmlns:Instance="URI where method is located">

  <return>

    <responseparameter1>value</responseparameter1>

    <responseparametern>value</responseparametern>

  </return>

  </Instance: "Method Name"+"Response">

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Listing 15是一个一般的SOAP响应。Apach SOAP服务器在方法名后添加了Response关键字并将返回值封装在<return>节点中作为方法节点的直接子节点。如果返回值是一个复杂类型,那么<return>节点将包含一个或多个<item>节点。与Listing 15相比Listing 17则是方法getListOfModels的实际响应。Listing 17中返回值是Vector类型的,因此<return>节点包含了一个<item>节点的列表。与此类似的是Listing 18Listing 19,这两个图展示了MobilePhoneservicegetPrice()方法的SOAP请求和响应。

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

<SOAP-ENV:Body>

  <m:getListOfModels xmlns:m = "www.mobilphoneservice.com" >

  </m:getListOfModels>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

 

 

<?xml version="1.0" encoding="UTF-8"?>

<SOAP-ENV:Envelope 

  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

  xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" 

  xmlns:xsd="http://www.w3.org/1999/XMLSchema">

<SOAP-ENV:Body>

  <ns1:getListOfModelsResponse xmlns:ns1="urn:MobilePhoneservice" 

  SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

  <return xmlns:ns2="http://xml.apache.org/xml-soap" 

    xsi:type="ns2:Vector">

    <item xsi:type="xsd:string">M1</item>

    <item xsi:type="xsd:string">M2</item>

    <item xsi:type="xsd:string">M3</item>

    <item xsi:type="xsd:string">M4</item>

    <item xsi:type="xsd:string">M5</item>

  </return>

  </ns1:getListOfModelsResponse>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

 

 

<SOAP-ENV:Envelope 

  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

  xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" 

  xmlns:xsd="http://www.w3.org/1999/XMLSchema">

<SOAP-ENV:Body>

  <m:getPrice xmlns:m ="www.mobilphoneservice.com">

    <modelNumber xsi:type ="xsd:String">M1</modelNumber>

  </m:getPrice>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

 

 

<?xml version="1.0" encoding="UTF-8"?>

<SOAP-ENV:Envelope 

  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 

  xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" 

  xmlns:xsd="http://www.w3.org/1999/XMLSchema">

<SOAP-ENV:Body>

  <ns1:getPriceResponse xmlns:ns1="urn:MobilePhoneservice" 

    SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

      <return xsi:type="xsd:string"> 5000 </return>

  </ns1:getPriceResponse>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

SOAP服务器上发布基于WSDL的服务

在这部分我们将把第一部分中的WSDL服务发布到一台Apache SOAP服务器上。Apache SOAP工具包把WSDL服务信息保存在一个发布描述文件中。发布描述文件包含了WSDL服务的名称及其方法。发布描述文件在运行时将这些信息提供给SOAP 服务器。发布描述文件还包含了实现接口的JavaBean组件的地址。

Listing 20

<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment"

  id="URN:SERVICE-URN">

<isd:provider type="java" 

  scope="Request" 

  methods="EXPOSED-METHODS">

  <isd:java class="IMPLEMENTING-CLASS"/> 

</isd:provider>

<isd:faultListener>org.apache.soap.server.DOMFaultListener

</isd:faultListener>

</isd:service>

Listing 20是发布描述文件的骨架,基于WSDL服务的发布描述需要三个信息(URN:SERVICE-URN, EXPOSED-METHOIMPLEMENT-CLASS)。URN:SERVICE-URN是发布的服务的名称。EXPOSED-METHO服务的方法列表。在本次发布中就是getListOfModelsgetPriceIMPLEMENT-CLASS就是带有完整名称的java类。如samples.phonequote.MobilePhoneservice。本例的试验中你有下面的路径结构:

Apache SOAP server: C:/foo/SOAP-2-2

Mobile pone service 实现

C:/foo/SOAP-2-2/samples/phonequotes/MobilePhoneservice

因此在安装SOAP工具包时实现类路径跟目录有关。我并没有提供实际的java实现类。这需要依据商务逻辑或者其他的什么东西。

<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment"

id="urn:MobilePhoneservice">

<isd:provider type="java"

  scope="Request"

  methods="getListOfModels getPrice">

  <isd:java class="samples.phonequote.MobilePhoneservice"/>

</isd:provider>

<isd:faultListener>

  org.apache.soap.server.DOMFaultListener

</isd:faultListener>

</isd:service>

Listing 21就是第一部分中WSDL文件的完整描述。

SOAP客户端同SOAP服务器的通讯

我准备了一个例子演示SOAP客户端同SOAP服务器的通讯。因此我给出了三个清单:Startup.html(Listing 22), Operation.html(Listing 23)Excute.jsp(Listing 24)

Startup.html是一个简单的html文件。它是一个用户界面,由用户决定调用哪个SOAP方法。

Listing 22

<HTML>

<BODY bgcolor="Teal">

<br/>

<p align="center">

  <font size="5" face="Arial" color="white"><b> 

  SOAP method invocation demo </b></font>

</p>

<hr/>

<font face="Arial" color="whitesmoke" size="3">

<br/><b>

  Click any of the method name to execute.<br/>

  1. Get the List of all Models that we manufacture.... 

    <a href="execute.jsp?index=1"> 

    <font color="orange"> GetListOfModels </font></a> <br/>

  2. Get the Price of any particular model......................

    <a href="operation.html"> 

    <font color="orange"> GetPrice </font></a>

</b>

</BODY>

</HTML>

Operation.html(Listing 23)让用户输入调用方法的参数。

Listing 23

<HTML>

<BODY bgcolor="Teal">

<br/>

<p align="center"> 

<font size="5" face="Arial" color="white"><b>

  GetPrice Operation input Form </b>

</font></p>

<hr/>

<p align="center"> 

<form action="execute.jsp" method="POST">

<input type="hidden" name="index" value="0">

<table textColor="white">

<tr><td>

<font color="whitesmoke"><b>Description :</b></font>

</td><td><font color="whitesmoke">

  Method GetPrice is used to Get Price of given Model Number</font>

</td></tr>

<tr><td>

<font color="whitesmoke"><b>Parameter(s)</b></font></td><td>

</td></tr>

<tr><td><font color="whitesmoke">Model Number </td></font>

<td><font color="whitesmoke">

  <input type="text" name="parameter" size="30"> 

  (required) </font>

</td></tr>

<tr><td>

  </td><td><input type="Submit" value="Invoke">

</td></tr>

</font>

</table>

</form>

</p>

</BODY>

</HTML>

Excute.jsp(Listing 24)才是重点。它侦查调用的方法及其参数,然后向远程服务器发送方法调用请求。

Listing 24

<%@ page language="java" import="java.util.Vector" %>

<%@ page import="java.net.MalformedURLException, java.net.URL" %>

<%@ page import="java.util.Vector" %>

<%@ page import="org.apache.soap.SOAPException, 

    org.apache.soap.Constants" %>

<%@ page import="org.apache.soap.rpc.Call, org.apache.soap.rpc.Response, 

    org.apache.soap.rpc.Parameter" %>

<%@ page import="org.apache.soap.transport.http.SOAPHTTPConnection" %>

<%@ page import="org.apache.soap.Fault" %>

 

<HTML>

<BODY bgcolor="Teal">

<br/>

<p align="center">

<font color="whitesmoke">

<% 

  boolean isParameter = false ;

  SOAPHTTPConnection soapTransport = new SOAPHTTPConnection();

 

  // Address of the remote server. 

  // Normally this should be dynamically passed and detected.

  // We have hard coded it only for demonstration.

  URL url = new URL ("http://localhost:8080/soap/servlet/rpcrouter");

 

  // Build the call.

  Call call = new Call ();

  call.setTargetObjectURI ("urn:MobilePhoneservice");

  call.setSOAPTransport (soapTransport);

  call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);

 

  // We'll detect which method user selected

  // and give a call accordingly.

  // We'll pass parameters if present.

 

  if (request.getParameter("parameter")!=null)

  isParameter = true;

 

  if (request.getParameter("index").equals("0")) 

  {

    call.setMethodName("getPrice");

    Vector params = new Vector();

    String message = new String (request.getParameter("parameter"));

    params.addElement (new Parameter("message", String.class, 

    message , null));

    call.setParams(params);

  }

  else

    call.setMethodName("getListOfModels");

 

  Response resp = call.invoke ( url, /* actionURI */ "" );

  out.println("<p align=left> 

  <font size=/"4/" face=/"Arial/" color=/"white/">

  Response of [ "+call.getMethodName()+" ]

  </font><hr/>");

  

  // Check the response.

  if (resp.generatedFault ()) {

    Fault fault = resp.getFault ();

    out.println("<b>Fault is:</b>"+ fault.getFaultCode ()

    +" ["+fault.getFaultString ()+"]");

 

  } else {

    Parameter result = resp.getReturnValue ();

    out.println("<b>Response is: </b>"+ result.getValue ()+"");

  }

%>

<font>

</p>

</BODY>

</HTML>

运行这个程序你需要两个Apache SOAP 服务器。一个用于用户跟主机的交互。另一个(又称远程服务器)用来发布第一部分中基于WSDL的服务。在Execute.jsp中硬编码的远程服务器地址(http://localhost:8080/soap/servlet/rpcouter)仅用于演示。实际上你将从WSDL文件中读出远程服务器地址。

SOAP中的简单数据类型和组合数据类型

下面介绍简单数据类型和组合数据类型的区别。我将展示在SOAP中如何封装它们。

简单数据类型包括string, float, integer, enumeration等等。如移动电话的名称就是string类型的。组合数据类型则是简单数据类型的组合体。如学生类型就可能有多个属性:string类型的姓名,int型的学号。

Listing 25就含有复杂数据类型Mobile。稍候你可以在你的SOAP请求中使用这种类型。
Listing 25

1<? xml version="1.0" ?>

2<xsd:schema xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" 

3   xmlns:xsd="http://www.w3.org/1999/XMLSchema">

4   targetNameSpace= "www.mobilephoneservice.com/phonequote">

5 <xsd:element name ="Mobile">

6 <xsd:complexType>

7   <xsd:element name="modelNumber" type="xsd:int">

8   <xsd:element name="modelName" type="xsd:string">

9   <xsd:element name="modelWeight" type="xsd:int">

10  <xsd:element name="modelSize" type="xsd:int">

11  <xsd:element name="modelColor">

12    <simpleType base="xsd:string">

13    <enumeration value="white" />

14    <enumeration value="blue" />

15    <enumeration value="black" />

16    <enumeration value="red" />

17    <enumeration value="pink" />

18    </simpleType>

19  </xsd:element>

20 </complexType>

21 </xsd:element>

22</xsd:schema>

Listing 25的第五行是类型的名称而第六行说明这是个复杂数据类型。复杂数据类型都有属性,七到十二行就是数据类型Mobile的属性。第七行说明Mobile类型有一个名称为modelNumber类型为int的属性。类似的是九、十行是相同类型不同名称的属性。第八行则是名称为modelName类型为string的属性。

十一行复杂一点,因为它包含了一个simpleType的子节点。我们在Mobile类型里面定义了一个简单类型。这个简单类型的名称是modelCOlorenumaration(枚举)类型的。他有一个值为xsd:stringbase属性,这说明了简单类型modelColor基类型是sting。枚举类型说明我们可以在其中选择一个作为属性的值。

SOAP请求中使用组合类型

Listing 26演示了组合类型在SOAP请求中的使用。在Envelope的体中调用了m名称空间的addModel方法。Listing 26使用了Listing 25中定义的Mobile数据类型。

addModel方法有一个Mobile类型的参数。在Mobile之前我们用到了msd名称空间。Listiing 26的节点<SOAP-ENVEnvelope>声明了该名称空间。这是一个在SOAP请求中使用用户自定义类型数据的例子。

1 <SoAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"

2 xmlns:xsd="http://www.w3.org/1999/XMLSchema" 

3 xmlns:msd="www.mobilephoneservice.com/phonequote">

4 <SOAP-ENV:Body>

5   <m:addModel xmlns:m="www.mobilephoneservice.com">

6   <msd:Mobile>

7     <modelNumber>1</modelNumber>

8     <modelName>mlr97</modelName>

9     <modelWeight>10</modelWeight>

10    <modelSize>4</modelSize>

11    <modelColor>white</modelColor>

12  </msd:Mobile>

13  </m:addModel>

14 </SOAP-ENV:Body>

15<SOAP-ENV:Envelope>

总结

现在我们学习了SOAP语法,请求,响应,HTTP绑定以及在SOAP中使用e-mail。你也看到了SOAP服务器是如何响应SOAP客户端的。最后,我简要的讲了一下用户自定义类型数据。自定义类型数据是一个需要子系学习的高级话题,在本系列的下一边文章中我们会更详细的讨论这个话题。而且我也检查了SOAP的交互能力(也就是SOAP如何在不同的卖主中执行的)。

原文链接:http://www-128.ibm.com/developerworks/webservices/library/ws-intwsdl2/index.html

原创粉丝点击