【 以下文字转载自 New_board 讨论区 】
发信人: FrankCH (终有绿叶衬), 信区: New_board
标 题: [范文][WebServices]30分钟创建WebService
发信站: BBS 水木清华站 (Thu Sep 18 18:08:29 2003), 转信
30分钟创建WebService(1)
作者:宁凯编译 本文选自:赛迪网 2002年09月10日
您或许已经听到了很多有关Web Service的宣传,而您对这些缩写词很可能已经是头晕眼花了。那么,Web Service到底是什么?您又该如何使用Web Service?下面我们就是要揭开Web Service的神秘面纱并且演示如何循序渐进的建立、配置、使用和得到Web Service。
基本的Web Service并不是很难创建。为了证明这一点,我将向您演示如何在30分钟左右的时间里构建一个Web Service。在后面的文章中,我们将对Web Service进行更深一步的钻研同时更详细的解释下列主题:
● SOAP 消息
● WSDL的定义及其与代码的关系
● 将service发布到一个UDDI目录
● Exposing legacy applications as Web Services
● 高级主题(例如安全性)
下面,我们首先介绍Web Service的定义,接着再演示一个简单的调用和执行Web Service的Java
类。我们的所有示例都是使用Java来描述的。我们使用一套免费的工具和Systinet的运行环境创建了我们的示例。尽管您并不需要使用这些产品来理解示例,但是我们还是强烈推荐,如果可能的话还是应该这样做。我们引入的概念和我们创建的代码具有通用性并与所使用的工具相对独立。我们假定您对XML已经有所了解,但是对Web Service却是一无所知。
我们确信J2EE是一种最成熟的用于业务逻辑实现的体系结构。我们的目标就是将Web
Service作为现有J2EE组件模型的自然扩展引入其中,提供具有基于XML的工业标准协议和统一的组件描述与发明。这使得现有的基于J2EE的系统比以前有了更加广阔的应用范围,同时在公共信息系统的典型异构环境中这也使J2EE成为核心业务逻辑实现的更优选择。
Web Service——程序定义
Web Service是一种具有下列功能的软件组件:
● 可以通过SOAP 接口(Simple Object Access Protocol简单对象访问协议) 接口来进行访问 。
● 它是使用WSDL(Web Service Description Language,Web Service描述语言 ) 文档形式描述的接口。
SOAP是扩展的XML消息协议,它形成了Web Service的基础。SOAP
提供一种简单而又一致的机制支持一个应用向另一应用发送XML消息。SOAP消息是一种从SOAP发送者到接收者单向传送。任何应用都能够以发送者或接收者的身份参与信息的交换。SOAP消息也可以组合来支持多种通信行为,这其中包括请求/响应、请求响应、单向异步消息或者事件通知。SOAP这种高级协议只定义了消息结构和很少的几条消息处理规则。它完全独立于潜在的传输协议,因此SOAP消息可以通过HTTP、 JMS或者邮件传输协议进行交换。目前HTTP协议是SOAP消息使用最为频繁的传输协议。我们将在本文的后半部分举出一些SOAP消息的示例 。
WSDL 是一种XML文档,它包含了一组描述Web Service 的定义。WSDL 提供了访问和使用Web Service所需的全部信息。WSDL文档描述Web Service将做些什么,它如何进行通信以及它的位置在哪里。您可以在开发阶段使用WSDL文档创建您自己的服务接口。包括Systinet
WASP在内的一些SOAP的实现也可以在运行时间使用WSDL来支持动态通信。
安装软件
需求:我们假定您的机器上已经安装了Java 1.3.x SDK 和标准的HTTP浏览器。环境变量JAVA_HOME应该指向您的Java 1.3.x SDK 安装目录。
如果您想按照演示程序进行,你还需要从Systinet下载WASP Advanced。将下载得到的压缩包解压缩到本地硬盘(最好是C:)并运行WASP Advanced BIN目录下的安装程序。
在示例中,我们假定已经将WASP解压缩到c:\wasp-advanced 目录。您还需要下载,(演示源代码)demo sources
也将其解压缩到目录c:\wasp_demo。如果您选择了不同目录名称,请正确更新env.bat(将环境变量WASP_HOME改为指向WASP的安装目录,将WASP_DEMO指向演示程序的目录)。
我们将按照下列步骤创建一个简单的Web Service:
● 创建Web Service 业务逻辑。首先我们需要编写一个Java类来实现Web Service 业务逻辑,这种情况下,我们的业务逻辑将是一个可以模拟股票报价服务的简单的Java类。
● 配置同SOAP server 相关的Java 类。 接下来我们需要将Java类转变成Web。我们将演示如何使用WASP配置工具配置同SOAP server相关的Java 类。
● 生成客户访问(client access)类。 客户应用程序使用代理对象访问Web Service。在请求时间,代理接受来自应用的Java 方法调用并将其转换成XML消息。代理接收SOAP 返回消息,将其转换成Java 对象然后将结果返回给客户应用程序。
● 客户应用程序的开发。 客户应用程序把代理看作是有助于Web Service通信的标准Java对象。
注意:我们在命令行命令中使用MS Windows符号,如果您的环境是基于UNIX,请对这些代码进行适当的调整。
好了,我们下面就以一个实现股票报价查询功能的简单的Java类开始吧。 请看下列的Java代码:
注意:本例中所提到的所有源代码都可以在解压缩文件demo sources后得到的src子目录中找到。它们位于com.systinet.demos.stock 包中。
/*
* StockQuoteService.java
*
* Created on Sat 13th Oct 2001, 15:25
*/
package com.systinet.demos.stock;
/**
* Simple stock quote service
* @author zdenek
* @version 1.0
*/
public class StockQuoteService {
public double getQuote(String symbol) {
if(symbol!=null && symbol.equalsIgnoreCase("SUNW"))
return 10;
if(symbol!=null && symbol.equalsIgnoreCase("MSFT"))
return 50;
if(symbol!=null && symbol.equalsIgnoreCase("BEAS"))
return 11;
return 0;
}
public java.util.LinkedList getAvailableStocks() {
java.util.LinkedList list = new java.util.LinkedList();
list.add("SUNW");
list.add("MSFT");
list.add("BEAS");
return list;
}
}
图 1: Web Service 代码 (StockQuoteService.java)
我们的示例虽然是另外一种简单的股票报价系统(我们已经见到过很多这样的系统,开发人员应该是目前已注册的商业人员),但是它却可以演示说明如何容易的创建和配置Web Service。我们的示例中,我们将要检索三种股票(BEAS, MSFT 和 SUNW)的价格。
将我们定义的类转换成Web Service的最简方式就是编译我们的Java类,然后 使用配置工具将其配置为运行时间的Web Service。
注意: 您可以在解压缩文件demo sources后得到的BIN子目录中找到所有的程序。
注意: 在运行演示程序之前,你需要安装Systinet SOAP框架。请参见本文档的Installation 一章循序渐进的进行安装。
首先,我们使用startserver.bat 程序启动Web Service 运行服务器。然后编译StockQuoteService.java 并使用deploy.bat命令行程序将编译过的类配置成SOAP服务器。
接下来,我们打开HTTP浏览器中的管理控制台(administration console)以便确保一切正常工作。单击更新按钮将显示配置在服务器上的所有包列表。我们应该使用配置在服务器上的StockQuoteService观察包StockService。注意 Web
Service运行时间将自动生成WSDL文件并在
http://localhost:6060/StockQuoteService/ 公布以供使用。
<?xml version='1.0'?>
<wsdl:definitions name='com.systinet.demos.stock.StockQuoteService'
targetNamespace='
http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/stock/' xmlns:mime='
http://schemas.xmlsoap.org/wsdl/mime/' xmlns:wsdl='
http://schemas.xmlsoap.org/wsdl/' xmlns:soap='
http://schemas.xmlsoap.org/wsdl/soap/' xmlns:xsi='
http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='
http://www.w3.org/2001/XMLSchema' xmlns:ns0='
http://idoox.com/containers' xmlns:http='
http://schemas.xmlsoap.org/wsdl/http/' xmlns:tns='
http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/stock/' xmlns:SOAP-ENC='
http://schemas.xmlsoap.org/soap/encoding/'> <wsdl:message name='StockQuoteService_getQuote_Request'>
<wsdl:part name='p0' type='xsd:string'/>
</wsdl:message>
<wsdl:message name='StockQuoteService_getQuote_Response'>
<wsdl:part name='response' type='xsd:double'/>
</wsdl:message>
<wsdl:message name='StockQuoteService_getAvailableStocks_Request'/>
<wsdl:message name='StockQuoteService_getAvailableStocks_Response'>
<wsdl:part name='response' type='ns0:LinkedList'/>
</wsdl:message>
<wsdl:portType name='StockQuoteService'>
<wsdl:operation name='getAvailableStocks'>
<wsdl:input name='getAvailableStocks' message='tns:StockQuoteService_getAvailableStocks_Request'/>
<wsdl:output name='getAvailableStocks' message='tns:StockQuoteService_getAvailableStocks_Response'/>
</wsdl:operation>
<wsdl:operation name='getQuote' parameterOrder='p0'>
<wsdl:input name='getQuote' message='tns:StockQuoteService_getQuote_Request'/>
<wsdl:output name='getQuote' message='tns:StockQuoteService_getQuote_Response'/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name='StockQuoteService' type='tns:StockQuoteService'>
<soap:binding transport='
http://schemas.xmlsoap.org/soap/http' style='rpc'/>
<wsdl:operation name='getAvailableStocks'>
<soap:operation soapAction='' style='rpc'/>
<wsdl:input name='getAvailableStocks'>
<soap:body use='encoded' encodingStyle='
http://schemas.xmlsoap.org/soap/encoding/' namespace='
http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/stock/'/> </wsdl:input>
<wsdl:output name='getAvailableStocks'>
<soap:body use='encoded' encodingStyle='
http://schemas.xmlsoap.org/soap/encoding/' namespace='
http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/stock/'/> </wsdl:output>
</wsdl:operation>
<wsdl:operation name='getQuote'>
<soap:operation soapAction='' style='rpc'/>
<wsdl:input name='getQuote'>
<soap:body use='encoded' encodingStyle='
http://schemas.xmlsoap.org/soap/encoding/' namespace='
http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/stock/'/> </wsdl:input>
<wsdl:output name='getQuote'>
<soap:body use='encoded' encodingStyle='
http://schemas.xmlsoap.org/soap/encoding/' namespace='
http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/stock/'/> </wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name='JavaService'>
<wsdl:port name='StockQuoteService' binding='tns:StockQuoteService'>
<soap:address location='
http://localhost:6061/StockQuoteService/'/> </wsdl:port>
</wsdl:service>
</wsdl:definitions>
图2:生成的WSDL文件 (StockQuoteService.wsdl)
WSDL文件包含所配置Web Service的完整描述。WSDL文件主要有三个部分:
●
WHAT部分,由元素types(类型),message(消息),和portType(端口类型)组成,它定义了客户和服务器之间交换的消息和数据类型。消息是SOAP的基本通信元素。消息可以由一个或多个部分组成,每一部分表示某一类型的参数。在我们的股票报价Java类的每一个模型中,有两种消息(输入和输出)。既然我们没有在示例中使用复杂的或者组合的类型,这个WSDL文档中也就不会含有组合类型定义(不必担心,在今后的例子里我们会看到很多组合类型定义)。所有的消息在一个名为portType(端口类型)的实体中被分组形成operations(操作)。portType(端口类型)表示接口-Web Service支持的一组具体操作。Web Service可以拥有不同portType(端口类型)表示的多个接口。请看WSDL样本文件中的StockQuoteService portType。它包含了两个操作:getAvailableStocks
和getQuote。为了调用方法getQuote,客户(client)发送StockQuote_getQuote_Request 消息。(您可以在文件的前面部分找到消息的定义)。请注意StockQuote_getQuote_Request 消息是由一个名为p0的输入参数部分组成,它被定义为XML Schema string类型(xsd:string)。Web
Service应该使用StockQuote_getQuote_Response 消息予以回应。这条消息中包含一个名为response的返回值部分,它是XML Schema double类型 (xsd:double)。
● HOW部分,是由binding元素组成,它描述了我们定义的Web Service的技术实现细节。元素binding将一个 portType 绑定到特定的通信协议(本例中,就是基于HTTP的SOAP协议)。因为我们使用了SOAP,我们将使用大量的用于SOAP的WSDL
可扩展元素来定义我们自己SOAP绑定的细节。(请注意本部分的许多元素使用soap命名空间的前缀。这些元素就是WSDL的SOAP扩展)。元素soap:operation中的属性
soapAction是一个特定的HTTP属性,它可以用来指定SOAP消息的意图。它包含消息路由参数或者取值来帮助SOAP运行时间判定执行哪一个应用或者方法。这个属性中设定的取值也必须在SOAP请求消息的HTTP头部字段中的属性SOAPAction加以指定。我们的例子中,这个属性并没有包含取值。SOAP绑定要求我们为portType中的每一个操作指定通信的类型。SOAP支持两种通信类型: RPC(远程过程调用) 和 Document(文件)。
RPC(远程过程调用)类型支持消息的自动编解码并允许开发人员使用方法调用来表示一条请求,其中要使用一组参数并返回包含返回值的一条响应。Document (文档)类型不支持消息的自动编解码。这种类型假定SOAP消息的内容是格式良好的XML
数据。SOAP绑定也要求我们要指定如何使用XML来表述我们自己的消息。我们或者使用literal 值或者encoded 数据类型。属性use='literal'表示SOAP运行时间应该发送XML描述的数据。属性 use='encoded' 表示SOAP
运行时间应该串行化数据以便我们使用某一特定的编码类型。编码类型定义了一组规则来表述XML的编程语言类型。这个例子中,我们使用SOAP在其规范的第5部分中所定义的编码类型。其他的编码类型当然也可以使用。
● 最后是WHERE 部分,由元素service组成,聚集了port类型、binding(绑定)和Web Service的实际位置 (a URI)。检查WSDL文档最末端的元素service。
正如您所看到的, WSDL文件对Web Service进行了完整的描述。有了这个WSDL 文件,我们就具备了用于创建客户应用所需的全部信息。这个要创建的客户应用可以访问我们自己的股票报价Web Service。
实现一个Java web service的客户端程序(client)
客户端程序使用Java的代理组件绑定到远端Web Service。 当使用Systinet WASP时,WSDL文件就会在运行时间生成这个代理。我们需要一个Java接口来保持对这个动态创建对象的引用。我们或者自己创建接口,或者使用WASP的WSDLCompiler生成我们所需的接口。
接口的创建是比较容易的,这是因为唯一的要求就是接口方法必须是Web Service业务逻辑Java类的方法的子集。
我们来看看下面的代码。首先,客户端程序(client)创建对象WebServiceLookup。通过调用方法lookup,这个对象将被用于创建Web Service代理。方法lookup需要两个参数:WSDL文件的引用和引用代理实例的Java接口的类。方法lookup method返回调用Web Service的代理。
/**
* Stock Client
*
* @created July 17, 2001
* @author zdenek
*/
package com.systinet.demos.stock;
import org.idoox.wasp.Context;
import org.idoox.webservice.client.WebServiceLookup;
public class StockClient {
/**
* Web service client main method.
* Finds the web service and
* @param args not used.
*/
public static void main( String[] args ) throws Exception {
// lookup service
WebServiceLookup lookup = (WebServiceLookup)Context.getInstance(Context.WEBSERVICE_LOOKUP);
// bind to StockQuoteService
StockQuoteServiceProxy quoteService = (StockQuoteServiceProxy)lookup.lookup(
"
http://localhost:6060/StockQuoteService/",
StockQuoteServiceProxy.class
);
// use StockQuoteService
System.out.println("Getting available stocks");
System.out.println("------------------------");
java.util.LinkedList list = quoteService.getAvailableStocks();
java.util.Iterator iter = list.iterator();
while(iter.hasNext()) {
System.out.println(iter.next());
}
System.out.println("");
System.out.println("Getting SUNW quote");
System.out.println("------------------------");
System.out.println("SUNW "+quoteService.getQuote("SUNW"));
System.out.println("");
}
}
图3: Web Service 客户端代码(StockClient.bat)
30分钟创建WebService(7)
作者:宁凯编译 本文选自:赛迪网 2002年09月10日
运行程序runJavaclient.bat。这个程序将会运行WSDLcompiler 来生成Java接口,然后它将编译并运行客户端应用程序。您应该可以从控制台上看到方法getAvailableStocks和方法getQuote的输出。
开发并运行JavaScript Web Service 客户端应用程序
注意: 目前,JavaScript Web Service 客户端应用程序要求安装微软IE 6.0 (Microsoft Internet Explorer 6.0) 或者安装了微软XML解析器3.0 sp2 (Microsoft XML Parser 3.0 SP2)的Microsoft Internet Explorer 5.0。
我们可以使用程序runJScriptClient.bat生成一个基于浏览器的JavaScript客户端应用程序。这个程序将打开IE浏览器并显示所生成的HTML页面。您就可以从这一页面调用Web Service的所有方法。
简介SOAP 消息
现在我们可以使用WASP Administration console(WASP)查看在客户端和服务器之间交换的SOAP消息。首先,我们需要在浏览器中打开控制台。然后单击刷新按钮将会看到所有的配置包。我们应该看到我们自己的 StockQuoteService Web Service
已经配置到服务器上。单击"enable"链接激活所有SOAP请求的调试(在管理控制台的StockQuoteService 部分的"Debug is OFF:"标签附近)。然后再次运行Java Web Service 客户端程序runJavaclient.bat 并单击管理控制台中的链接"show SOAP
conversation"。这将会打开浏览器窗口并显示两对输入输出SOAP消息。
==== INPUT ====
http://localhost:6060/StockQuoteService/ ==== 11/7/01 3:45 PM =
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Envelope xmlns:ns0="
http://schemas.xmlsoap.org/soap/envelope/"> <ns0:Body
ns0:encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="
http://www.w3.org/2001/XMLSchema" xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="
http://schemas.xmlsoap.org/soap/encoding/"> <ns0:getAvailableStocks
xmlns:ns0="
http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/stock/"/> </ns0:Body>
</ns0:Envelope>
==== CLOSE =====================================================================
==== OUTPUT ====
http://localhost:6060/StockQuoteService/ ======================
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Envelope xmlns:ns0="
http://schemas.xmlsoap.org/soap/envelope/"> <ns0:Body
ns0:encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="
http://www.w3.org/2001/XMLSchema" xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="
http://schemas.xmlsoap.org/soap/encoding/"> <ns0:getAvailableStocksResponse
xmlns:ns0="
http://idoox.com/wasp/tools/java2wsdl/output/com/systinet /demos/stock/">
<response xsi:type="ns1:LinkedList" xmlns:ns1="
http://idoox.com/containers"> <item xsi:type="xsd:string">SUNW</item>
<item xsi:type="xsd:string">MSFT</item>
<item xsi:type="xsd:string">BEAS</item>
</response>
</ns0:getAvailableStocksResponse>
</ns0:Body>
</ns0:Envelope>
==== CLOSE =====================================================================
==== INPUT ====
http://localhost:6060/StockQuoteService/ ==== 11/7/01 3:45 PM =
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Envelope xmlns:ns0="
http://schemas.xmlsoap.org/soap/envelope/"> <ns0:Body
ns0:encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="
http://www.w3.org/2001/XMLSchema" xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="
http://schemas.xmlsoap.org/soap/encoding/"> <ns0:getQuote
xmlns:ns0="
http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/stock/"> <p0 xsi:type="xsd:string">SUNW</p0>
</ns0:getQuote>
</ns0:Body>
</ns0:Envelope>
==== CLOSE =====================================================================
==== OUTPUT ====
http://localhost:6060/StockQuoteService/ ======================
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Envelope xmlns:ns0="
http://schemas.xmlsoap.org/soap/envelope/"> <ns0:Body
ns0:encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="
http://www.w3.org/2001/XMLSchema" xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="
http://schemas.xmlsoap.org/soap/encoding/"> <ns0:getQuoteResponse
xmlns:ns0="
http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/stock/"> <response xsi:type="xsd:double">10.0</response>
</ns0:getQuoteResponse>
</ns0:Body>
</ns0:Envelope>
==== CLOSE =====================================================================
Figure 4: SOAP messages
SOAP messages follow the following basic structure:
<ENVELOPE attrs>
<HEADER attrs>
<directives/>
</HEADER>
<BODY attrs>
<payload/>
</BODY>
<FAULT attrs>
<errors/>
</FAULT>
</ENVELOPE>
消息的内容包含在标记ENVELOPE中。这个简单的例子中,我们的SOAP消息仅仅包含了一个BODY部分。还可以有另外两个,即HEADER部分和FAULT部分。
HEADER部分通常用来传播各种上下文语境信息(例如支付细节、交易内容和安全可信度等)。如果出现错误,FAULT部分应该携带并传送有关错误本质的信息。BODY部分携带并传送主要的信息(我们的例子里,就是指股票的价格和相关数据)。
一般说来,SOAP并不制定BODY部分的规则。我们已经提到了两种可行的BODY部分类型:Document(文档)和RPC(远程过程调用)。文档类型除了XML的标准规则之外并没有严格的格式要求。而远程过程调用类型定义了使用相关参数组成方法调用的规则。SOAP规范推荐但是并没有指定SOAP消息中表示类型数据的基本框架(编码类型)。SOAP编码类型基于在XML Schema,部分2建议中所定义的数据类型,它包含了编程语言的原类型,例如int、float, double
或者string。SOAP编码也定义了在原类型之上构建复杂类型的规则(例如,数组和结构等)。我们的例子中,(使用远程过程调用和SOAP编码),输入消息的BODY部分 包含了被调用的方法名和编码后的参数:
<ns0:getQuote
xmlns:ns0="
http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/stock/"> <p0 xsi:type="xsd:string">SUNW</p0>
</ns0:getQuote>
The output message contains the result of the method call:
<ns0:getQuoteResponse
xmlns:ns0="
http://idoox.com/wasp/tools/java2wsdl/output/com/systinet/demos/stock/"> <response xsi:type="xsd:double">10.0</response>
</ns0:getQuoteResponse>
撤消
最后我们应该运行undeploy.bat来把我们的简单服务从服务器上撤消。
小结
在这篇文章中,我们充满希望的演示并论证了创建简单的Web Service其实并不困难。实际上,使用Web Service的好处之一就是Web Service相对容易创建和配置。在创建我们自己的股票交易系统的过程中,我们已经介绍了一些基本的概念,这其中包括SOAP 和
WSDL。我们也演示了如何构建SOAP消息并且创建和分析了WSDL文件,它提供了如何与Web Service相互作用的指导。在下一篇文章中,我将在此基础之上建立并检查SOAP是如何处理复杂类型、错误消息和远程引用的。
(责任编辑 Sunny)
--
FROM 61.48.33.191