本文是Web Service Case Study文章系列的第五篇,在我以前的developerWorks的专栏文章中,我已经系统地介绍了各种Web服务技术标准及其细节,然而Web服务并不仅仅是一种技术,更是一种应用框架,一种系统架构的方式,和一种应用的思想。本文是先前文章的一个延伸,通过一个内容供应服务来考察如何具体设计一个Web服务应用,如何评估Web服务解决方案的适用性等。在这个Web Services案例中,主要通过Web Services的数据发布功能,将产品目录的内容通过标准接口发布出来,以供各种在线系统和桌面应用进行使用。同时如果接入系统的数据模型与发布出来的数据模型有所出入,可以使用XSLT进行数据模型的转换。我将陆续推出这个文章系列,希望大家通过这个系列的文章,能够从实践中掌握Web服务构架。

案例背景简介 - 内容供应服务

在本文中,我们将介入一个传统而经典的Internet Web应用,内容提供商的案例。POP(Professioanl of Professional) Digital Online是一家在线内容供应商,提供IT方面的各种媒体产品供出借、出租和出售。从商业实体的角度来考察,POP Digital Online是由一个IT电子图书馆和一个IT媒体/产品销售网站组成的复合企业。提供的服务包括:

  • 出借IT媒体/产品,包括电子图书、试用版软件、教学课件等,这部分服务所提供的内容和产品都是相对不是非常新的内容和产品,因此借用这类电子图书、试用版软件以及教学课件无需付费,虽然是免费的,但是仅提供给POP Digital Online的用户(会员)使用,要成为POP Digital Online的用户(会员)必须缴纳会费,或购置一定数量的POP Digital Online提供的产品和服务而自动成为会员。
  • 出租IT媒体/产品,这部分服务与出借IT媒体产品是类似的,出租的产品包括:电子图书、软件、教学课件,与出租服务不同的是,出售的图书、课件都是最新的技术,而软件则是正版可用软件,而并非试用版。出租IT媒体产品的前提同样也必须具备POP Digital Online的正式会员资格。值得注意的是,无论是出借还是出租,都只针对纯数字产品,运达客户的方式也只有一种,即通过网络,以电子的方式交付客户。由于仅以电子的方式交付,因此出租和出借的媒体/产品的文件大小将受一些限制,电子图书问题不大,不过软件/教学课件方面,则仅局限于较精简的产品。
  • 出售IT媒体/产品,这部分服务与出租/出借IT媒体/产品的差别在于,在出售方面,交付方式更为自由,用户可以不一定选择电子方式,可以选择以光盘媒质通过物流送达。对于出售服务,无论是否会员都可以使用,差别可能仅仅在于两者能够获得的价格不同。

通过对这些服务项目的调研和分析,我们认为所有的服务可以基于一个内容引擎,即产品分类目录引擎,而每项产品拥有多个属性,分别表示其是否供出借/出租/出售,出售的会员价和非会员价分别是多少。

同时,为了使得POP Digital Online的业务能够得到更大发展,期望在目前仅有的在线Web界面的基础上,增添两项设施,以加速POP Digital Online的普及程度:

  • 提供内容API(类似Amazon.com)接口,使得其他合作伙伴站点能够包含POP Digital Online的产品目录,以拓展POP Digital Online的销售渠道。
  • 为了有效管理出借和出租的各种IT媒体/产品,需要开发一个客户端软件在用户的计算机上进行统一管理,杜绝出借和出租的IT媒体/产品被非法使用(如二次出借或逾期使用等),同时该客户端软件也是POP Digital Online在每个客户方的桌面门户,用户不仅能够通过这个客户端获得产品目录(相对在线服务具备更丰富的表现形式和更方便的检索方式),同时POP Digital Online还通过这一渠道,基于每个用户的购买习惯,向客户主动提供其可能感兴趣的内容。




回页首


解决方案

我们在考察这样一个应用案例之后,我们可以将这个应用定位为:在线产品销售商。我们需要解决的问题就是要尽可能地帮助这个在线产品销售商拓展业务渠道,并产生尽可能多的交易事务。针对业务背景,我们将整个服务系统拓展如下:


Figure 1. 内容供应服务

其核心是一个IT媒体产品目录,然后这个产品目录提供一个公共使用的内容供应接口API,这个内容供应接口API供所有外部应用使用,包括POP Digital Online的网站、POP Digital Online为客户提供的桌面客户端以及POP Digital Online的商业合作伙伴的应用或网站等。

对于这个产品目录而言,由于内容供应接口API的使用者不光有自身商业实体的应用,同时也有其他现存的商业合作伙伴以及潜在的商业合作伙伴的应用系统,这些应用系统的类型是多样的,同时部分尚是未知的。我们不能针对待集成的对象而选择接口的方式,因为很多尚是为止,我们需要的是选择一个接口方式,其能够最大限度地适应应用间的互联,解决应用集成问题。

Web Services是一个非常优秀的候选技术。在Web Services模型下,任意的服务消费者(对应于前述的接口使用者)一方只需理解一种通用的组件接口(即Web Services),就可以利用现有的Internet上的Web Services(即前述的产品目录的内容提供服务),而无需考虑Web Services的内部实现机制,操作平台,开发语言等细节。同时对该服务的调用是通过SOAP消息机制远程调用实现。因此两者之间实现的是松散耦合机制。即使在日后的运作过程中,当Web Services产生了接口上或是功能上的更改,服务消费者一方可以通过Web Services的描述性文档及时地发现这样的更改,自动消化并适应这样的更改。基于Web Services的体系架构给了整个Internet上的商业运作和系统集成一个全新的解决方案,这个解决方案的优越性表现在下面几个方面:

  • 基于现行软硬件基础之上,Web Services体系架构并不是一种全新的系统。企业组织内部的解决方案可以完全保留现状,并且可以采用不同的平台,语言,和对象模型实现。企业为了把自己的服务发布到Web上,只需在原有的基础上按照标准进行封装,而这种封装是基于XML的。我们应该不难想象内容供应服务所提供的产品目录数据应当使用XML来表示。
  • 基于开放平台,Web Services是基于开放标准,如HTTP,XML,SOAP。因此许多支持这些标准协议的应用也同时支持Web Services。所有的Web Services的描述,注册,查找,调用都基于XML格式的消息进行。而基于XML是一种完全的跨平台的标识语言,因此它可以畅通无阻地通过任何Internet协议比如HTTP,SMTP,FTP在Internet上传输。
  • 黑箱实现,跟组件一样,Web Services是黑箱操作,并且可以在不知道Web Services是如何实现的情况下被重用。对于服务消费者而言,如果两个服务提供者实现了同一个服务接口的话,即时他们使用了不同地对象模型实现了Web Services,但是对于服务消费者一方而言,看到的却是相同的封装好的Web Services。
  • 系统集成,通过Web Services,应用程序之间可以很轻松的互连,即使是通过Internet。不同的客户端都可以使用Web Services。同时,Web Services本身也可以互相通讯或者调用别的Web Services所提供的方法。许多设备也可以调用服务,比如基于J2ME的手机可以访问Web Services。
  • 信息描述,发现和集成,Web Services的提供者通过Internet在UDDI注册中心登记了自己所提供的Web Services的描述信息,就有可能被任何Web Services消费者所发现并利用。

如果使用Web Services作为产品目录的数据接口技术,那么我们需要重新对数据模型进行分析,总结出需要对外提供(发布)的数据子模型,然后使用XML进行描述,以提供给外部使用者。

同时为了系统实现的简洁性考虑,发布的数据结构尽可能简单,冗余的数据尽可能少,一些额外的可以通过计算自行生成的数据元素将不会包含在发布的媒体产品数据中。同时,为了考虑使用目标的多样性,发布的数据结构应当尽可能自白,便于其他使用对象进行使用。处于简洁性和多用性的双重考虑,实施的策略是,不应各个使用客户的需要分别提供不同的数据格式,但是提供的数据结构非常简单,便于使用对象进行数据格式的转换并投入自身系统使用。

API设计原则

概括地说,产品目录的内容提供服务遵循的原则有这样几条:

  1. 简单性,由于这是一个对于公共开放的Web服务,它的API的设计首先应当是简单的,要被大量用户接受,要获得比较好的应用,那么API必须简单,没有哪个复杂难用的API会得到大家的广泛接受的。
  2. 可扩展性,作为更新频率较高,开放性较强的Web服务,其API应当具有很好的向后扩展性,当应内部需求的改变或外部需求的改变的需要时,API将根据新的逻辑发生变化,此时不应当将API从根本上推翻重建,而应当具备增量式的可扩展的能力。
  3. 高效性,API应该在坚持简单性的前提下,兼顾高效性,当某些组合操作应用地非常频繁的时候,我们应当为这样的组合操作调用设计一个只需一次交互的单一入口调用,这样能够提升外部应用的效率,同时减轻Web服务的负载。




回页首


数据建模

数据模型

产品目录的数据模型可以简化归纳如下:


Figure 2. 数据模型

Category表示产品目录的分类类别,组成一个目录树,一个Category可以包含多个Category,如同Windows目录一个目录可以包含多个子目录那样。Product作为整个目录树的叶子节点出现,用于表示每个用于出借/出租/出售的IT媒体产品,每个Category下会包含多个Product。

下面给出了这一数据模型的XML Schema表示。同时为了方便理解,我们同时给出了这个XML Schema的模式图示。

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
  <xs:element name="catalog">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="category" type="categoryType" minOccurs="0"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

这个Schema文档并不复杂,我们简单地讲解一下结构,顺便温习一下XML Schema的语法。上面是Schema的第一部分,描述了一个全局元素catalog,这也将是产品目录数据XML表示形式的根元素。catalog元素包含0个或1个子元素category,这个category是整个产品目录数据的根目录。category应用了复合类型categoryType。

 <xs:complexType name="categoryType">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="category" type="categoryType" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="product" type="productType" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
    <xs:attribute name="ID" type="xs:long" use="required"/>
  </xs:complexType> 

第二部分定义了复合类型categoryType。categoryType是一个自递归的类型,应用了categoryType的元素可以包含0到多个同样为categoryType类型的category元素,这就如同目录可以包含下层子目录那般。同时类似目录可以包含文件,应用了categoryType的元素可以包含0到多个类型为productType的product元素。同时应用了categoryType的元素包含一个必须出现的元素name和一个必须出现的属性ID,分别表示category的名称和标识。

 <xs:simpleType name="productTypeEum">
    <xs:restriction base="xs:string">
      <xs:enumeration value="ebook"/>
      <xs:enumeration value="software"/>
      <xs:enumeration value="courseware"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:complexType name="productType">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="type" type="productTypeEum"/>
      <xs:element name="date" type="xs:date"/>
      <xs:element name="canLend" type="xs:boolean"/>
      <xs:element name="canRent" type="xs:boolean"/>
      <xs:element name="canSell" type="xs:boolean"/>
      <xs:element name="memberPrice" type="xs:double"/>
      <xs:element name="generalPrice" type="xs:double" nillable="true" minOccurs="0"/>
      <xs:element name="description" type="xs:string" nillable="true" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="ID" type="xs:long" use="required"/>
  </xs:complexType>
</xs:schema> 

第三部分定义了productType复合类型,productType复合类型被先前的product元素所应用。与categoryType类似,应用productType类型的元素也包含一个必须出现的元素name和一个必须出现的属性ID,分别表示product的名称和标识。同时,该复合类型还包含了一个基于字符串的枚举类型的子元素type,表示product的类别,到底是电子图书("ebook")、软件("software")还是课件("courseware")。date子元素表示product的出品时期。canLend、canRent、canSell分别表示product是否可供出借、出租和出售。memberPrice和generalPrice分别表示会员购买和非会员购买的价格(当然需要canSell的值为true)。而description元素则为product提供了详细信息描述的手段。

下面是产品目录数据的相应的模式图示。


Figure 3. 模式图示

数据表示示例

按照前面我们设计的XML Schema模式,我们可以给出一个数据表示示例:


<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="catelog.xsd">
  <category ID="2002100">
    <name>Web Services</name>
    <category ID="2002101">
      <name>IBM Web services</name>
      <product ID="20021010001">
        <name>WebSphere Application Server 5.0 Professional</name>
        <type>software</type>
        <date>2002-8-8</date>
        <canLend>false</canLend>
        <canRent>false</canRent>
        <canSell>true</canSell>
        <memberPrice>9000</memberPrice>
        <generalPrice>13000</generalPrice>
        <description>IBM的Web Services平台应用服务器中间件</description>
      </product>
      <product ID="20021010002">
        <name>WebSphere Application Server 5.0 Courseware 1.0</name>
        <type>courseware</type>
        <date>2002-9-1</date>
        <canLend>true</canLend>
        <canRent>true</canRent>
        <canSell>true</canSell>
        <memberPrice>3000</memberPrice>
      </product>
    </category>
    <product ID="20021000002">
      <name>Web服务架构与开放互操作技术</name>
      <type>ebook</type>
      <date>2002-7-23</date>
      <canLend>false</canLend>
      <canRent>true</canRent>
      <canSell>true</canSell>
      <memberPrice>42</memberPrice>
    </product>
  </category>
</catalog>

在这个例子中,给出的catalog产品目录是一个Web Services领域的子目录的一个投影。catalog元素下包含一个category子元素,这个子元素即为Web Services领域子目录的根元素,名称为"IBM Web Services",这个目录包含了IBM在Web Services领域的一些产品,在这个category下,包含了两个产品:Websphere Application Server 5.0 professional和Webshpere Application Server 5.0 Courseware 1.0,前者是应用服务器产品,不可出借/出租,仅供出售,同时会员和非会员之间的价格差为4000元;后者则是课件产品,可供出借/出租/出售,非会员不可购买,会员价为3000元。在根目录下,除包含一个category外,还包含一个产品:Web服务架构与开放互操作技术,这是一本电子图书(ebook),该书不可出借,可供出租和出售。

看到这里,细心的读者可能已经发现了一个问题,为什么没有出租的价钱,如果出租不用花钱,岂不是与出借没有差别了。其实并非如此,我们在先前已经表述过:"同时为了系统实现的简洁性考虑,发布的数据结构尽可能简单,冗余的数据尽可能少,一些额外的可以通过计算自行生成的数据元素将不会包含在发布的媒体产品数据中。" 出租的价钱能够通过公式算出,事实上应该说,出租的价钱就是通过公式计算而得出的。

POP Digital Online的出租策略是:

  • 所有产品的出租费用为:每天的租用费用为会员购买价的1/300;

此外,对于一些合作伙伴网站需要引用POP Digital Online的网页进行业务处理的时候,它也只需要对获得的商品ID进行变换,即可获得相关产品的业务处理入口地址。假设ID的值为" 20021000002",那么相关的入口地址即为:"http://www.popdigitalonline.com/process.jsp?productID=20021000002"。





回页首


会话交互设计

我们在前一节给出的XML数据信息块不大,仅包含了两个category和分布于其下的三个product。然而,这仅仅是一个示例,在实际应用中,一个category下可能包含几十,数百的product,而一次查询需要获取的category可能数量就有几十,数百,这样的数据量,使用一次交互传输XML文档显然并不非常有效率,当网络带宽条件不是非常良好的时候,可能根本无法正常传输。因此我们可能需要引入多消息响应以及异步的机制,来实施数据的传送。

除了考虑传输,我们在实际应用中,还需要提供过滤机制,以方便用户增量地获取其感兴趣的数据。增量方式,可以通过对出品时间(date)的过滤来实现,而感兴趣的内容则可以通过对类型(type)、是否可供出借(canLend)、是否可供出租(canRent)、是否可供出售(canSell)等因素的过滤来实现。

API设计

下面我们来设计这个产品目录的内容供应服务的API:getProducts。


  <xs:element name="getProducts" type="getProductsType"/>
  <xs:complexType name="getProductsType">
    <xs:sequence>
      <xs:element name="requestBag">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="requestItem" type="requestItemType" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="requestItemType">
    <xs:sequence>
      <xs:element name="categoryID" type="xs:long"/>
      <xs:element name="productType" type="xs:anySimpleType" minOccurs="0" maxOccurs="3"/>
      <xs:element name="beforeDate" type="xs:date" minOccurs="0"/>
      <xs:element name="afterDate" type="xs:date" minOccurs="0"/>
      <xs:element name="canLend" type="xs:boolean" minOccurs="0"/>
      <xs:element name="canRent" type="xs:boolean" minOccurs="0"/>
      <xs:element name="canSell" type="xs:boolean" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
  <xs:element name="getProductsResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="catalog" maxOccurs="ubounded"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

该API的请求消息的根元素是getProducts元素,而响应消息的根元素则是getProductsResponse元素。getProducts元素包含一个requestBag,这是一个聚集元素包含了多个请求信息项requstItem,每个请求信息项requstItem指明了一个搜索过滤指令。这个搜索指令包含了七个信息项:

  • categoryID是必须出现的条件,指明当前搜索指令应当在哪个category子树中进行,categoryID的值对应与该子树的根category的ID。
  • productType可出现0次或多次,组合表示搜索针对那些产品类型,这些元素之间的关系是或,例如,如果在实例消息中出现两个productType元素,值分别是ebook和courseware,那么搜索结果就可以包含两种产品类型:电子图书(ebook)和课件(courseware)。
  • beforeDate指明搜索结果中的那些产品应当在beforeDate指明的日期之前出品。
  • afterDate则明搜索结果中的那些产品应当在afterDate指明的日期之后出品。
  • canLend指明搜索结果中的那些产品应当包含与canLend的值相同的canLend设定。
  • canRent结果中的那些产品应当包含与canLend的值相同的canRent设定。
  • canSell中的那些产品应当包含与canLend的值相同的canSell设定。

而getProductsResponse元素则包含多个catalog元素以表示搜索结果,每个catalog元素对应于一个requestItem所指定的搜索。

API以SOAP机制实现,SOAP请求消息的Body部分包含getProducts调用,SOAP响应消息的Body部分包含getProductsResponse响应。

由于考虑到网络传输的实时能力,以及网络带宽的限制,我们需要在SOAP之上讨论使这个API具有更大适应性的异步消息机制以及多消息响应的异步消息机制。

异步机制

我在SOAP应用模式:高级消息交换模式一文中已经介绍过:

在异步消息模式下,发送者以异步方式将消息发往接收者,同时期望在一段时间之后获取一些响应。其中,发送者为请求分配了一个标识,并标注了这个请求,这样之后的响应就可以使用这个标识与初始请求进行关联。

在异步消息模式下,请求消息与响应消息在发生时间上是分离的,并且是以两个单向消息来实现的。其中,SOAP发送方的应用程序在发送完SOAP消息之后并不会阻塞并等待响应消息的返回。当最终的响应消息的接收者收到响应消息后,SOAP发送方的应用程序将会通知初始的SOAP发送应用程序。然后它就可以使用接收到的消息中的关联信息与之前发送的某个SOAP消息达成关联。

在请求消息中,消息标识处理器会生成一个唯一的消息标识并将其插入到一个SOAP Header条目中。这作为SOAP请求消息的一部分从服务请求方发送到服务提供方。然后SOAP服务方的内容供应服务将处理这个请求消息,并装配响应消息。其中也将包括一个SOAP Header条目,该条目由消息关联处理器构建,它负责将响应消息与其相关的请求消息设置连接语义。

下面给出了SOAP消息示例(请求消息和响应消息),演示了异步消息的工作原理:


<env:Envelope xmlns:env="http://www.w3.org/2001/12/soap-envelope">
   <env:Header>
     <async:MessageControl xmlns:async="http://asyncsoap.org/requestresponse">
       <async:MessageId>uuid:09233523-345b-4351-b623-5dsf35sgs5d6
         </async:MessageId>
     </async:MessageControl>
   </env:Header>
   <env:Body>
     <cat:getProducts xmlns:cat="http://popdigitalonline.com/schema/catalog.xsd">
       ......
     </cat:getProducts>
   </env:Body>
</env:Envelope> 

上面给出的是请求消息。


<env:Envelope xmlns:env="http://www.w3.org/2001/12/soap-envelope">
   <env:Header>
     <async:MessageControl xmlns:async="http://asyncsoap.org/requestresponse">
       <async:MessageId>uuid:09233523-567b-2891-b623-9dke28yod7m9
         </async:MessageId>
       <async:ResponseTo>uuid:09233523-345b-4351-b623-5dsf35sgs5d6
         </async:ResponseTo>
     </async:MessageControl>
   </env:Header>
   <env:Body>
     <cat:getProductsResponse xmlns:cat="http://popdigitalonline.com/schema/catalog.xsd">
       ......
     </cat:getProductsResponse>
   </env:Body>
</env:Envelope>

上面给出的是响应消息。异步消息的传输机制可以通过消息中间件来完成,例如IBM的Websphere MQ(即以前的MQ Series)就是一个成熟的异步消息中间件产品。

先前我们谈到,一次查询需要获取的category可能数量就有几十,数百,这样的数据量,使用一次交互传输XML文档显然并不非常有效率,当网络带宽条件不是非常良好的时候,可能根本无法正常传输。因此我们还需要考虑使用多条消息进行异步消息响应。

多消息异步

当服务请求方向服务提供方以异步方式提交请求信息后,内容供应服务依请求消息而给出的返回结果可以选择在一段时间之后以多个响应消息的形式返回。以适应连接带宽不是非常良好的网络环境。

多消息异步响应是异步消息的一个扩展。在异步机制中仅有一个响应消息,而这里介绍的多消息异步响应中,接受到请求消息的内容供应服务将会返回多个响应消息。多消息异步响应的实现基本架构与异步机制中给出的实现示例是基本一致的,他们使用了相同的消息关联机制来关联请求消息和响应消息。而为了实现多消息响应,我们可以通过使用一个称为序列化处理器的模块来支持这一特性。序列化处理器确保在每一个响应消息中插入一个唯一的序列号。如果负责返回响应消息的应用程序预先就知道将会生成多少响应消息的话,那么序列化处理器可以使用"N of M"的格式(例如1 of 3, 3 of 3等)来指明有多少响应消息将被返回,以及当前的消息是处于序列中的哪个位置。下面给出了消息示例。


<env:Envelope xmlns:env="http://www.w3.org/2001/12/soap-envelope">
   <env:Header>
     <async:MessageControl xmlns:async="http://asyncsoap.org/requestresponse">
       <async:MessageId>uuid:09233523-345b-4351-b623-5dsf35sgs5d6
         </async:MessageId>
     </async:MessageControl>
   </env:Header>
   <env:Body>
     <cat:getProducts xmlns:cat="http://popdigitalonline.com/schema/catalog.xsd">
       ......
     </cat:getProducts>
   </env:Body>
</env:Envelope> 

上面给出的是请求消息。


<env:Envelope xmlns:env="http://www.w3.org/2001/12/soap-envelope">
   <env:Header>
     <async:MessageControl xmlns:async="http://asyncsoap.org/requestresponse">
       <async:MessageId>uuid:09233523-567b-2891-b623-9dke28yod7m9
         </async:MessageId>
       <async:ResponseTo>uuid:09233523-345b-4351-b623-5dsf35sgs5d6
         </async:ResponseTo>
     </async:MessageControl>
   <seq:Sequence xmlns:seq="http://asyncsoap.org/sequence">
       <seq:SequenceNumber>1</seq:SequenceNumber>
     <seq:TotalInSequence>5</seq:TotalInSequence>
     </seq:Sequence>
   </env:Header>
   <env:Body>
     <cat:getProductsResponse xmlns:cat="http://popdigitalonline.com/schema/catalog.xsd">
       ......
     </cat:getProductsResponse>
   </env:Body>
</env:Envelope>

上面给出的是响应消息。





回页首


POP Digital Online桌面应用

为了有效管理出借和出租的各种IT媒体/产品,POP Digital Online计划推出一个POP Digital Online桌面应用程序在用户的计算机上进行统一管理,以杜绝出借和出租的IT媒体/产品被非法使用(如二次出借或逾期使用等),同时该客户端软件也是POP Digital Online在每个客户方的桌面门户,用户不仅能够通过这个客户端获得产品目录(相对在线服务具备更丰富的表现形式和更方便的检索方式),同时POP Digital Online还通过这一渠道,基于每个用户的购买习惯,向客户主动提供其可能感兴趣的内容。

这个桌面引用程序的默认程序行为包括:

  • 第一次运行时,调用内容供应服务的getProducts API,其中包含一个requestItem,其categoryID为整个产品目录的根节点ID,另外beforeDate设置为当前的系统时间,包含三个productType设置,分别设置为ebook、software和courseware,表示所有产品类型都要下载,canLend、canRent和canSell则不加以限制,如此,将可以将当前所有的产品全部下载到本地,可能这个下载过程将通过多个SOAP消息花去一些时间来完成。
  • 然后每次运行的时候,将再次调用内容供应服务的getProducts API,其中同样包含一个requestItem,其categoryID为整个产品目录的根节点ID,而beforeDate设置为当前的系统时间,afterDate设置为上一次调用时的beforeDate的值,包含三个productType设置,分别设置为ebook、software和courseware,canLend、canRent和canSell则不加以限制。如此,即可实现本地数据的增量更新,具体的说,就是将上次下载之后新出品的电子图书、软件和课件的数据下载下来。

同时,用户可以进行个性化设置以影响默认程序行为的执行:

  • 用户可自行设置一些默认参数,包括多个requestItem元素,每个元素都可以对其内部的所有参数进行设置,例如包括productType、canLend、canRent、canSell等。这些设置值将替换默认程序行为中使用的对应元素的设置值。例如,如果用户首先通过程序界面将本地数据库中的所有不可出借/出租的产品(也就是仅供出售)清除,然后设置了两个requestItem,第一个requestItem的categoryID为整个产品目录的根节点ID,productType设置成为ebook和courseware、canLend设置成为"true",而第二个requestItem的categoryID也为整个产品目录的根节点ID,productType设置成为ebook和courseware、canRent设置成为"true",那么以后每次增量更新时,该桌面应用将仅仅下载新出品的可供出借或可供出租的电子图书和课件,仅供出售的产品以及所有软件将不再下载到本地。

当POP Digital Online桌面应用更新完数据之后,用户可以使用这个桌面程序自由地租借、购买各种POP Digital Online提供的IT媒体产品,同时,POP Digital Online将根据用户的购买历史记录,统计所有用户的购买习惯,而向各个用户主动发送其有可能购买的产品广告。

这种主动式的购买趋向预测可以通过两种方式:

  1. 类别预测,统计用户最喜欢购买那些category下的哪些类别的产品,例如可以根据统计用户jerry经常购买IBM Web Services类别下的courseware产品,那么以后当有新的IBM Web Services的Courseware出品的时候,POP Digital Online将在第一时间将该产品信息"Push"给jerry。
  2. 购买相关性预测,统计购买产品A与购买产品B的并发出现次数,通过这么一张二维统计表格(当然具体存贮是按照稀疏表的存储方式)统计两两产品间的数据关联度,然后可设置阚值,所有关联度(并发购买次数)大于设置阚值的被认为是具备一定相关性。如果用户jerry购买了产品A,而产品A与产品C/产品D的关联度都大于阚值,那么产品C和产品D也将被推荐给用户jerry。




回页首


商业合作伙伴应用

POP Digital Online的内容供应服务不仅被自身的在线Web应用以及桌面应用所使用,同时POP Digital Online的商业合作伙伴站点能够通过集成内容供应服务包含POP Digital Online的产品目录,以帮助POP Digital Online拓展产品销售渠道。

对于那些具有简单的商业应用和流程的商业合作伙伴而言,他们可能仅仅需要通过Web Services接口将产品目录数据获取,然后在自身的网站服务上将这个产品目录使用HTML表现,同时相关的业务处理链接都指向POP Digital Online。而对于那些拥有自身成熟完整系统的,则可能首先通过Web Services接口将产品目录数据获取,然后将获取得数据转换到自身的目录数据模型,存入自身的数据库(可能是关系数据库,也可能是XML Repository),然后再表现在自身的服务网站上,其中相关的业务处理链接将首先指向自身的服务,以便进行统一业务管理和支付处理(可能包含两个商业实体之间的代理费用的结算),当然最终的业务处理可能还是由这个负责统一业务管理和支付处理的服务转发给最终的POP Digital Online的相关业务服务。

对于这样的处理流程,可以选择的一种方式是:

  • 使用平台提供的Web Services开发工具构建Web Services连接模块;
  • 将通过Web Services连接获取到的产品目录数据通过程序生成内部数据类(可能使用DOM/SAX直接对XML进行处理,也可能利用Web Services工具自动生成处理模块直接将Web Services接口获取的XML数据转换成内部数据类),同时通过处理模块(可能是Java,也可能是C#程序)将这些内部数据类转换成自身系统的数据结构,存入具有一致数据模型的数据库中。
  • 然后页面呈现模块读出数据库中的数据,与HTML可视代码组合呈现给用户。

这是通常的处理方式,简单有效,不过也有一些缺点,例如当POP Digital Online的数据模型发生更新之后,就不得不修改程序以适应数据模型的变化。

而另一种方法就是将可变部分从程序代码中脱离出来,使用类Script的语言,比如XSLT来完成数据模型的映射,这样当数据模型发生变化的时候,可以不用修改程序,而只要替换XSLT文件就可以完成,如此应用系统就不需要因为维护而重新编译而暂停服务,同时XSLT的修改比较容易验证,也不会影响到其他模块。

在本节我就将后一种方法详细展开讨论(因为与XML技术更加相关),给出使用XSLT进行数据模型转换的方法。

不同的数据模型

假设POP Digital Online的某个合作伙伴IP(IT Product)Shopping Mall内部采用的销售目录的数据结构如下(使用XML Schema),IP Shopping Mall的应用系统具备接口能够接收满足下列XML Schema的产品数据。


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
  <xs:element name="node" type="nodeType"/>
  <xs:simpleType name="nodeTypeEum">
    <xs:restriction base="xs:string">
      <xs:enumeration value="directory"/>
      <xs:enumeration value="item"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:complexType name="nodeType">
    <xs:sequence>
      <xs:element name="node" type="nodeType" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="date" type="xs:date" minOccurs="0"/>
      <xs:element name="price" type="xs:double" minOccurs="0"/>
      <xs:element name="description" type="xs:string" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="type" type="nodeTypeEum" use="required"/>
    <xs:attribute name="ID" type="xs:string" use="required"/>
  </xs:complexType>
</xs:schema>

这个数据模型与POP Digital Online的数据模型是大同小异的,差别在于POP Digital Online使用不同的元素类型来区分两种结点category和product,而IP Shopping Mall则统一使用相同的元素类型来定义两种结点,同时使用一个attribute: type来区分彼此。同时,IP Shopping Mall中仅接收可购买的数据,因此POP Digital Online中提供的数据中,不可购买的(仅供出借或出租)产品将不会在IP Shopping Mall中陈列。

同时按照POP Digital Online与IP Shopping Mall的商业协约,通过IP Shopping Mall购买POP Digital Online的产品,将直接以会员价成交。

使用XSLT进行数据转换

下面我们首先给出将通过POP Digital Online获取的IT媒体产品数据转换成IP Shopping Mall所能接收的数据模型的XSLT文档。


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
  <xsl:apply-templates select="//catalog/category" />
</xsl:template>

第一部分是初始部分,从POP Digital Online数据的文档根元素开始,将catalog下的category元素应用后面的模版进行转换,按照元素匹配的情况来看,应当匹配到的是下面这组模版match="category"。


<xsl:template match="category">
  <node type="directory">
    <xsl:attribute name="ID">POP#<xsl:value-of select="@ID"/></xsl:attribute>
    <name><xsl:value-of select="name" /></name>  
    <xsl:apply-templates select="category" />
    <xsl:apply-templates select="product" />
  </node>  
</xsl:template>

第二部分是category的转换模版,当进入category结点转换时,首先在目标文档中生成类型为"directory"的结点node,然后将name子元素复制到目标文档,将ID稍做变换复制入目标文档,接着在category下分别针对category子元素和product子元素应用适当的模版,对于前者即应用自身,这是一个递归的过程,对于后者则应用后面的模版match="product"。


<xsl:template match="product">
  <xsl:if test="canSell='true'">
     <node type="item">
       <xsl:attribute name="ID">POP#<xsl:value-of select="@ID"/></xsl:attribute>
       <name><xsl:value-of select="name" /></name>  
       <date><xsl:value-of select="date" /></date>
       <price><xsl:value-of select="memberPrice" /></price>
       <description><xsl:value-of select="description" /></description>
     </node>
  </xsl:if>
</xsl:template>
</xsl:stylesheet>

第三部分是product的转换模版,当进入product结点转换时,首先判断这个product的canSell属性是否为"true"(即可供出售,当然也可以选择在POP Digital Online的API中设置过滤条件以屏蔽不供销售的产品),如果不为"true"那么丢弃,如果为"true"那么在目标文档中生成类型为"item"的结点node,然后将name子元素、date子元素、description子元素复制到目标文档,将ID稍做变换复制入目标文档,将memberPrice复制变成目标文档的price子元素。

最后我们给出将最开始给出的POP Digital Online数据示例进行转换后而得到的符合IP Shopping Mall数据模型的数据文档。


<?xml version="1.0" encoding="UTF-8"?>
<node type="directory" ID="POP#2002100">
  <name>Web Services</name>
  <node type="directory" ID="POP#2002101">
    <name>IBM Web services</name>
    <node type="item" ID="POP#20021010001">
      <name>WebSphere Application Server 5.0 Professional</name>
      <date>2002-8-8</date>
      <price>9000</price>
      <description>IBM Web Services平台应用服务器中间件</description>
    </node>
    <node type="item" ID="POP#20021010002">
      <name>WebSphere Application Server 5.0 Courseware 1.0</name>
      <date>2002-9-1</date>
      <price>3000</price>
      <description/>
    </node>
  </node>
  <node type="item" ID="POP#20021000002">
    <name>Web服务架构与开放互操作技术</name>
    <date>2002-7-23</date>
    <price>42</price>
    <description/>
  </node>
</node>





回页首


Amazon的实践

Amazon发布了一套可以通过两个接口访问(XML/HTTP以及XML/SOAP)的Web Services。通过这套Web Services,用户可以使用程序获取Amazon所提供的各种商品的结构化数据,包括产品名称、制造商、价格等等。具体的获取方式包括关键词搜索以及内容树浏览。同时Amazon还提供了一个开发工具包,该工具包包含了使用Perl和Java撰写的连接并使用Amazon Web Services的样例。





回页首


参考资料





回页首


关于作者

柴晓路: 上海得易电子商务技术有限公司( DealEasy)CIO、XML Web Sevices技术顾问, WS-I Working Group成员、 UDDI-China.org创始人,UDDI Advisory Group成员,IBM developerWorks专栏作家,CSDN名家专栏专栏作家。2000年获复旦大学计算机科学硕士学位,曾在国际计算机科学学术会议(ICSC)、亚太区XML技术研讨会(XML Asia/Pacific'99)、中国XML技术研讨会(北京)、计算机科学期刊等各类国际、国内重要会议与期刊上发表论文多篇。专长于Web Services技术架构、基于XML的系统集成和数据交换应用及方法,同时对数据库、面向对象技术及CSCW等技术比较擅长。

 
Logo

开源、云原生的融合云平台

更多推荐