作者:Bilal Siddiqui ([email protected])
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感知机器,它可以产生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: <[email protected]>
From: <[email protected]>
Reply-To: <[email protected]>
Date: SAT, 2 Feb 2002 16:00:00
Message-Id: <[email protected]>
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 18和Listing 19,这两个图展示了MobilePhoneservice的getPrice()方法的SOAP请求和响应。
|
|
|
|
在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-METHO和IMPLEMENT-CLASS)。URN:SERVICE-URN是发布的服务的名称。EXPOSED-METHO服务的方法列表。在本次发布中就是getListOfModels和getPrice。IMPLEMENT-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类型里面定义了一个简单类型。这个简单类型的名称是modelCOlor是enumaration(枚举)类型的。他有一个值为xsd:string的base属性,这说明了简单类型modelColor基类型是sting。枚举类型说明我们可以在其中选择一个作为属性的值。
在SOAP请求中使用组合类型
Listing 26演示了组合类型在SOAP请求中的使用。在Envelope的体中调用了m名称空间的addModel方法。Listing 26使用了Listing 25中定义的Mobile数据类型。
addModel方法有一个Mobile类型的参数。在Mobile之前我们用到了msd名称空间。Listiing 26的节点<SOAP-ENV:Envelope>声明了该名称空间。这是一个在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