天天看點

Web Service Case Study: 内容供應服務

本文是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媒體/産品的差别在于,在出售方面,傳遞方式更為自由,使用者可以不一定選擇電子方式,可以選擇以CD光牒媒質通過物流送達。對于出售服務,無論是否會員都可以使用,差别可能僅僅在于兩者能夠獲得的價格不同。

通過對這些服務項目的調研和分析,我們認為所有的服務可以基于一個内容引擎,即産品分類目錄引擎,而每項産品擁有多個屬性,分别表示其是否供出借/出租/出售,出售的會員價和非會員價分别是多少。

同時,為了使得POP Digital Online的業務能夠得到更大發展,期望在目前僅有的線上Web界面的基礎上,增添兩項設施,以加速POP Digital Online的普及程度:

  • 提供内容API(類似Amazon.com)接口,使得其他合作夥伴站點能夠包含POP Digital Online的産品目錄,以拓展POP Digital Online的銷售管道。
  • 為了有效管理出借和出租的各種IT媒體/産品,需要開發一個用戶端軟體在使用者的計算機上進行統一管理,杜絕出借和出租的IT媒體/産品被非法使用(如二次出借或逾期使用等),同時該用戶端軟體也是POP Digital Online在每個客戶方的桌面門戶,使用者不僅能夠通過這個用戶端獲得産品目錄(相對線上服務具備更豐富的表現形式和更友善的檢索方式),同時POP Digital Online還通過這一管道,基于每個使用者的購買習慣,向客戶主動提供其可能感興趣的内容。
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
回頁首

解決方案

我們在考察這樣一個應用案例之後,我們可以将這個應用定位為:線上産品銷售商。我們需要解決的問題就是要盡可能地幫助這個線上産品銷售商拓展業務管道,并産生盡可能多的交易事務。針對業務背景,我們将整個服務系統拓展如下:

Figure 1. 内容供應服務

Web Service Case Study: 内容供應服務

其核心是一個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服務的負載。
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
回頁首

資料模組化

資料模型

産品目錄的資料模型可以簡化歸納如下:

Figure 2. 資料模型

Web Service Case Study: 内容供應服務

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. 模式圖示

Web Service Case Study: 内容供應服務

資料表示示例

按照前面我們設計的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"。

Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
回頁首

會話互動設計

我們在前一節給出的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>
           

上面給出的是響應消息。

Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
回頁首

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。
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
回頁首

商業合作夥伴應用

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>
           
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
回頁首

Amazon的實踐

Amazon釋出了一套可以通過兩個接口通路(XML/HTTP以及XML/SOAP)的Web Services。通過這套Web Services,使用者可以使用程式擷取Amazon所提供的各種商品的結構化資料,包括産品名稱、制造商、價格等等。具體的擷取方式包括關鍵詞搜尋以及内容樹浏覽。同時Amazon還提供了一個開發工具包,該工具包包含了使用Perl和Java撰寫的連接配接并使用Amazon Web Services的樣例。

  • Amazon Web Services的介紹網址是: http://associates.amazon.com/exec/panama/associates/ntg/browse/-/1067662/086-9967469-3075005
  • 該工具包的下載下傳網址是: http://images.amazon.com/media/i3d/01/associates/kit.zip
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
回頁首

參考資料

  • 由本文作者撰寫的 《Web服務架構與開放互操作技術》一書,考察了Web服務技術的産生根源、商業驅動的原因以及它需要滿足的那些商業需求,同時它又是如何從技術上對這些商業需求提供保障的。該書以Web服務技術系列為主線,逐一詳細分析解釋包括XML、XML Schema、SOAP、WSDL和UDDI等在内的Web服務核心技術。在分析闡述的同時,使用了大量的執行個體和應用案例以使讀者能夠更形象地了解這些技術和技術的設計思路、設計原則。
  • Web Service 技術/評論網站
    • SimplePage.UDDI-China.ORG, Web服務中文資源。
    • UDDI-China.ORG, 以UDDI為主的Web服務技術網站。
    • WebServices.ORG, Web服務的綜合類技術網站。
    • IBM developerWorks/Web Service Zone, IBM的Web服務技術資源中心
    • MSDN Online Web Services Developer Resources, Microsoft的Web服務的開發者資源網站
    • ITPapers/Web Service, ITPapers的Web服務評論文章
  • 解決開放式應用互動和內建的Web Services系列技術标準規範
    • WS-Security規範, Microsoft, 2001
    • WS-License規範, Microsoft, 2001
    • UDDI執行白皮書, UDDI-China.org, UDDI.org
    • UDDI技術白皮書, UDDI-China.org, UDDI.org
    • UDDI程式員API規範, UDDI-China.org, UDDI.org
    • UDDI資料結構參考, UDDI-China.org, UDDI.org
    • Web Service Description Language (WSDL) 1.0, IBM, 25 Sep 2000
    • SOAP: Simple Object Access Protocol Specification 1.1, IBM, Microsoft, DevelopMentor, 2000
    • XML Schema Part 0: Primer, W3C, 2 May 2001
    • Extensible Markup Language (XML) 1.0 (Second Edition), W3C, 6 Oct 2000
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
回頁首

關于作者

Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
Web Service Case Study: 内容供應服務
柴曉路: 上海得易電子商務技術有限公司( 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等技術比較擅長。