2002-08-26 17:29
将应用程序的功能封装成为Web Services
黎献勇 李劲
2002 年 5 月
介绍
目前,很多电子商务中的Web应用程序都有与它们的客户端进行交换和事务处理的功能。这些应用程序通常被称之为B2C应用,它们通常使用像Java
servlet, JavaServer
Page这些服务器端的编程技术来动态生成HTML返回给客户端。现在,电子商务应用趋向于将它们的处理流程同其他的电子商务应用的处理流程自动地整合起来。在这种情形下,电子商务要求B2B形式的应用,从而使应用之间达到公开的,简单的,统一的连接和交换。B2B应用更专注于应用之间的信息交换,而不是信息的表示。
Web服务,通过定义一组可以通过互联网调用的相关的商业逻辑,从而可以使电子商务将其应用程序的功能以公开的,统一的方式提供给对方。Web服务通过WSDL来描述,通过SOAP作访问,在商业注册中心(UDDI)发布,从而使开发者和电子商务应用程序可以搜索并定位到该服务。在Web服务开发的过程中有三个清晰的角色定义,它们是服务的提供者(Service
provider),服务的请求者(Service request)和服务的代理(Service broker),图一显示了它们之间的关系。
图一:Web服务
Web服务的提供者使用WSDL来描述和定义那些可以通过编程来访问的应用程序的功能。同时,服务提供者将在UDDI商业注册中心(即服务代理)中发布这些服务的信息使其可以被其他应用访问到。Web服务的请求者通过服务代理找到他们所需的服务后,下载定义服务的文件(WSDL),接下来就可以通过SOAP来访问这些服务了。
在本文中,我们将介绍如何用IBM的开发工具WebSphere Studio Application Developer(WSAD)来定义、发布、定位和调用Web服务。
应用场景
我们的例子描述的是如何将一个已有的基于Web的公司员工电话号码簿的应用程序的部分功能封装成Web服务,这个应用来自于一个我们假想的名为Acme的公司。通过这个已有的Web应用,公司的员工可以通过员工号,名字等等查询到其他员工的信息。只要按照标准输入查询信息,应用程序执行查询后,会将查询结果以Web页面的形式显示出来。很多时候,会有其它的应用程序也需要员工的信息,通常情况下,这些应用的用户通过电话号码簿这个应用来查询到他们所需的员工信息,然后手工的将这些信息复制,粘贴到他们的应用中。假如我们将电话号码簿应用中的员工查询功能封装为Web服务,那么其他的应用就可以通过编程的方式来调用这个服务获取所需的员工信息。这样一来,用户将不需要手工的从各个应用之间来获取和整合信息,从而在整个应用流程中的操作效率也就大大提高了。图2描述了最初的应用流程和使用Web服务整合后的应用流程。
图二: 最初的应用流程和使用Web服务整合后的应用流程。
提供员工信息查询功能的Web服务
在这一部分,我们将描述怎样将已有的基于Web的电话号码簿应用中的员工信息查询功能定义成Web服务并发布它。在这个应用中,我们有一个名为TelephoneDirectory
的Java
Bean,它有一个名为findEmployeeByID的方法,这个方法可以通过给予一个唯一的员工序列号来检索员工的信息。下面的代码片断显示了TelephoneDirectory
Bean的纲要结构。
public class TelephoneDirectory
implements
java.io.Serializable
{
public Employee findEmployeeByID(int
id)
{
}
}
用WSDL定义Web服务
在创建了Web项目,并将TelephoneDirectory
Bean导入后,我们可以通过菜单项中的"文件->新建->Web服务"来启动WSAD的Web服务生成向导,它将内省Directory
Bean并显示其所有可得的公共的方法。我们选择将findEmployeeByID这个方法发布为Web服务,并可通过http://tempuri.org/com.acme.TelephoneDirectory来访问。在缺省状态下,向导会自动在Java类型和返回的XML类型之间选择最佳的的映射,同时用户也可以自己定制Java-to-XML的映射。向导将生成相应的用来定义Web服务的名为Directory-service.wsdl
和Directory-binding.wsdl
的WSDL文件和一个相关的用来规范WSDL的名为TelephoneDirectory-schema.xsd的模式文件。同时,向导还会生成一个名为Directory.isd的部署描述文件,它将在Web服务运行时被使用。图3
显示的是用Web服务生成向导创建Web服务的主要步骤(包括服务的定义,Java Bean方法的选择和Java-to-XML的映射)。
图3: WSAD中的Web服务生成向导
下面的代码段说明了如何在WSDL中定义我们的Web服务。
TelephoneDirectory-service.wsdl
<?xml version="1.0"
encoding="UTF-8"?>
<definitions
name="TelephoneDirectoryService"
targetNamespace="http://localhost:8080/TelephoneDirectoryWeb/wsdl/TelephoneDirectory-service.wsdl"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:binding="http://www.telephonedirectory.com/definitions/TelephoneDirectoryRemoteInterface"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://localhost:8080/TelephoneDirectoryWeb/wsdl/TelephoneDirectory-service.wsdl">
<import
location="http://localhost:8080/TelephoneDirectoryWeb/wsdl/TelephoneDirectory-binding.wsdl"
namespace="http://www.telephonedirectory.com/definitions/TelephoneDirectoryRemoteInterface"/>
<service
name="TelephoneDirectoryService">
<port binding="binding:TelephoneDirectoryBinding"
name="TelephoneDirectoryPort">
<soap:address location="http://localhost:8080/TelephoneDirectoryWeb/servlet/rpcrouter"/>
</port>
</service>
</definitions>
TelephoneDirectory-service.wsdl文件包括了一些定义Web服务的信息,比如说Web服务的名字,Web服务的端口绑定等等。从例子中可以看出,我们将通过SOAP
rpcrouter 这个 servlet来访问Web服务,而 port binding则描述了在哪可以找到如何访问服务的详细信息。
TelephoneDirectory-binding.wsdl
<?xml version="1.0"
encoding="UTF-8"?>
<definitions
name="TelephoneDirectoryRemoteInterface"
targetNamespace="http://www.telephonedirectory.com/definitions/TelephoneDirectoryRemoteInterface"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.telephonedirectory.com/definitions/TelephoneDirectoryRemoteInterface"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsd1="http://www.telephonedirectory.com/schemas/TelephoneDirectoryRemoteInterface">
<import
location="http://localhost:8080/TelephoneDirectoryWeb/wsdl/TelephoneDirectory-schema.xsd"
namespace="http://www.telephonedirectory.com/schemas/TelephoneDirectoryRemoteInterface"/>
<message
name="findEmployeeByIDRequest">
<part name="id" type="xsd:int"/>
</message>
<message
name="findEmployeeByIDResponse">
<part name="result" type="xsd1:com.acme.Employee"/>
</message>
<portType
name="TelephoneDirectory">
<operation name="findEmployeeByID"
parameterOrder="id">
<input message="tns:findEmployeeByIDRequest"
name="findEmployeeByIDRequest"/>
<output message="tns:findEmployeeByIDResponse"
name="findEmployeeByIDResponse"/>
</operation>
</portType>
<binding name="TelephoneDirectoryBinding"
type="tns:TelephoneDirectory">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation
name="findEmployeeByID">
<soap:operation soapAction="" style="rpc"/>
<input
name="findEmployeeByIDRequest">
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://tempuri.org/com.acme.TelephoneDirectory"
use="encoded"/>
</input>
<output
name="findEmployeeByIDResponse">
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://tempuri.org/com.acme.TelephoneDirectory"
use="encoded"/>
</output>
</operation>
</binding>
</definitions>
TelephoneDirectory-binding.wsdl文件中包含了定义Web服务接口的信息。在我们的例子中,接口的名字为TelephoneDirectoryRemoteInterface,它有一个名为TelephoneDirectory的portType,这个端口关联了一个名为findEmployeebyID的操作。
TelephoneDirectory-schema.xsd
<?xml version="1.0"
encoding="UTF-8"?>
<schema attributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="http://www.telephonedirectory.com/schemas/TelephoneDirectoryRemoteInterface"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xsd1="http://www.telephonedirectory.com/schemas/TelephoneDirectoryRemoteInterface">
<complexType
name="com.acme.Employee">
<all>
<element name="phone"
type="string"/>
<element name="lastName"
type="string"/>
<element name="firstName"
type="string"/>
<element name="id"
type="int"/>
</all>
</complexType>
</schema>
TelephoneDirectory-schema.xsd文件中包含了在Web服务中从Java到XML的映射信息,在例子中,名为com.acme.Employee的Java类将被映射为一个完整的XML文档,XML中的每一个元素都对应于类中一个简单的Java类型。这些信息将在TelephoneDirectory-binding.wsdl文件中定义消息类型和格式时被用到。
测试Web服务
WSAD中的Web服务生成向导是一个强大,有效的工具,它不但可以引导您一步一步的创建和定义一个Web服务,还可以帮助您部署和测试生成的Web服务。您可以不需要知道部署和配置Web服务的详细信息,因为向导会自动将新创建的Web服务部署到WSAD自带的WebSphere应用服务器测试环境中,同时帮您生成用来测试的Web客户端应用程序并运行它。图4显示了向导生成的用来测试的客户端例子程序。
图4:WSAD中生成的用来测试的客户端例子程序
从图4中,我们看到客户端例子程序的用户界面由三个HTML部分构成。在左边区域的上部列出了所有可以作为Web服务调用的方法。当选中其中任一方法时,右边区域的上部会显示出一个表格,表格里包含要调用该方法所需的所有参数。用户输入参数值,并点击提交按钮后,相应的Web服务将被调用,结果会显示在底部区域。
将Web服务发布到UDDI注册中心
在利用WSAD自带的测试环境验证我们创建的Web服务成功后,我们准备让其它的应用程序来使用该服务。我们用WSAD中的UDDI
explorer将Web服务发布到IBM Test Registry(要使用IBM的Test Registry,
你需要先到以下网址www-3.ibm.com/services/uddi/testregistry/protect/home.jsp注册)。首先,我们在IBM的Test
Registry中创建一个名为ACME Business的商业实体,接下来,就可以将我们的电话号码簿的Web服务发布到其中了。图5显示了怎样使用UDDI
explorer 来发布我们的Web服务。
图5: 用UDDI Explorer发布Web服务
使用员工信息查询的Web服务
当我们想通过编程的方式从电话号码簿的应用中来检索员工信息,我们需要首先查找到这个Web服务的定义然后调用它们。也就是说,我们将成为这个Web服务的服务请求者。
通过UDDI Registry发现Web服务
我们使用WSAD中的UDDI
explorer来查找电话号码簿这个Web服务。一旦我们在UDDI Registry中找到它,我们将使用导入功能将搜索到的WSDL文档导入到WSAD的工作台中。
图5说明了如何发现、导入Web服务定义文档的过程。
图6:发现、导入UDDI Registry中的WSDL文档
通过SOAP来访问Web服务
通过SOAP来访问Web服务的最常见的方法是使用事先生成的Java
代理对象(Java Proxy
Object)。通过使用WSAD中的Web服务客户端向导,我们可以为电话号码簿这个Web服务生成一个Java代理,它使我们可以通过简单的Java调用来访问Web服务。图7显示了如何使用客户端向导来生成Java代理对象并通过生成的例子代码来访问Web服务。
图7:生成一个Java代理并访问Web服务
总结
Web服务是构建在诸如XML、SOAP、WSDL和UDDI等等这些开放的,技术实现中立的标准之上的。Web服务被看作是下一代Web应用的奠基石,通过Web服务,电子商务应用可以高效的,自动化的整合他们的应用,降低开发费用,获取更多的商机。到此为止,我们已经描述了如何将已有的应用程序的功能封装为Web服务的过程,展示了在一个B2B的例子应用中,如何使用IBM的WebSphere
Studio Application Developer来非常轻松的定义、发布、定位、访问Web服务。
2.下载directory.war文件,该文件包含了本文的例子代码。要运行该例子程序,需要将该文件导入IBM的WebSphere Studio Application Developer工作区,然后您就可以通过Web服务向导生成所需的代码来测试这个应用和Web服务了。
3. 大家对于本文有任何建议以及想到的其他可能的问题,都欢迎到讨论论坛来提出意见或给出评论。
关于作者 黎献勇, 电脑软件业余爱好者,擅长基于XML和Web服务的WebSphere应用设计. 可以通过 lxylxylxylxy@hotmail.com与他联系。 李劲, IBM软件解决方案多伦多实验室应用开发技术中心的部门负责人,他负责从收集用户要求到软件实现及测试的全部设计周期,即收集、分析用户的要求,并在软件以及WebSphere应用开发工具和面向Web应用的交互式设计技术,实现用户的要求和使用方案。 Jin目前的主要工作是Web服务和B2B应用集成,他具有十多年的软件业从业经验,曾多次使用VisualAge实现了IBM的Java和WebSphere应用服务器的客户承诺. 可以通过 jinli@ca.ibm.com与他联系。 |