商務參考體系結構:企業對消費者 (B2C電子商務實踐) 第 7 章:ConsolidatedRetail.Com 的功能 (全文結束)...
商務參考體系結構:企業對消費者
第 7 章:ConsolidatedRetail.Com 的功能Microsoft Corporation
2001年5月
摘要:本章介紹了 ConsolidatedRetail.com 應用程式的功能,同時提供了虛擬碼和實際程式碼示例來詳細說明處理流程。
簡介
現在,您對解決方案的各個組成部分已經有了總體瞭解,可以開始檢查站點提供的具體功能了。本章探討了解決方案的以下幾個方面,並著重討論了為每個功能區編寫程式碼時所面臨的內在問題:
- 表示服務
- 使用者身份驗證和使用者配置檔案的維護
- 產品目錄
- “購物籃”管理
- 訂單處理
閱讀本章的各個小節時,您將瞭解具體功能的實現方法,以及如何在您自己的企業對消費者 (B2C) 解決方案中重新利用 ConsolidatedRetail.com 應用程式的部分或全部內容。
表示服務
ConsolidatedRetail.com 站點中的表示服務由 XSLISAPI 過濾器提供。面臨的主要開發問題在於:如何在每個 PASP 指令碼中生成合適的 XML,以及如何建立合適的 XSL 樣式表將 XML 表示為 HTML(或其它表示格式)。
ConsolidatedRetail.com 中來自 PASP 檔案的 XML 輸出
在 ConsolidatedRetail.com 站點中,每個 PASP 檔案都生成格式相同的 XML 文件。這是通過在站點的每一頁中加入對 Common.asp 檔案的 Include 引用,並呼叫其 PageStart 過程實現的。
Common.asp 檔案中的 PageStart
Sub PageStart(strPageNameWithExtension) ' 除去 pasp 副檔名 Dim strPageName strPageName = Trim(Left(strPageNameWithExtension, _ InstrRev(strPageNameWithExtension, _ ".") - 1)) 'XML 標頭 Response.Write _ "<?xml-stylesheet type=""text/xsl" _ " server-config=""" & _ strPageName & "-Config.xml"" href=""" & _ strPageName & "-IE5.xsl""?>" '頁元素的根。 '結束標記在“PageEnd”子例程中生成。 Response.Write "<page pagename="" _ " & strPageNameWithExtension & """>" & vbcrlf End Sub
此過程為 PASP 檔案將要生成的文件建立 XML 標頭。在每個 PASP 指令碼的末尾,將呼叫 PageEnd 過程來生成 <page> 的結束標記並完成 XML 文件。下面列出了 PageEnd 過程中的相關程式碼:
Sub PageEnd()
'為了表達得更為清楚,這裡省略了有關目錄、登出和錯誤訊息的程式碼
Call XMLEndTag("page")
End Sub
XMLEndTag 過程是 Common.asp 中的眾多 XML Helper 過程之一。(有關詳細資訊,請參考本章中的“XML Helper 過程”一節。)它使用以下程式碼生成 XML 結束標記:
Sub XMLEndTag(strTagName)
Response.Write mc_strStartTag & mc_strForwardSlashTag & _
Lcase (Replace(strTagName, mc_strBlank,_
mc_strUnderScore)) & _
mc_strEndTag & vbCrLf
End Sub
使用 PageStart 和 PageEnd 過程生成的 XML 文件類似於以下程式碼示例:
<?xml-stylesheet type="text/xsl"
server-config="filename-Config.xml"
href="filename-IE5.xsl"?>
<page pagename="filename.pasp">
<!-- XML 內容 -->
</page>
XML Helper 過程
除了上面提到的 XMLEndTag 過程之外,Common.asp 還包含多個與 XML 有關的實用程式例程。使用這些過程可以生成一些標記,這些標記將用於 ConsolidatedRetail.com 站點中的 PASP 頁所生成的 XML 文件。
雖然在許多情況下,對所需的 XML 字元(例如 "<" 和 ">",請注意不包括引號)進行硬編碼更為有效,但是,在各種 XML 生成過程中,大量 XML 字元常量均在 Common.asp 中進行宣告。這樣可增加程式碼的可讀性,同時有助於除錯。這些常量是:
Const mc_strStartTag = "<"
Const mc_strEndTag = ">"
Const mc_strForwardSlashTag = "/"
Const mc_strUnderScore = "_"
Const mc_strBlank = " "
以下 XML 生成過程使用了這些常量:
-
XMLBegTag:此實用程式根據 strTagName 引數編寫一個 XML 開始標記(例如 <page>)。
-
XMLEndTag:此實用程式(在上文中已經做過介紹)根據 strTagName引數編寫一個結束標記(例如 </page>)。
-
XMLEmptyTag:此實用程式根據 strTagName 引數編寫一個空 XML 標記(例如 <page/>)。
-
XMLTag:此實用程式根據 strTagName 和 strTagValue 引數編寫一個包含值的 XML 標記(例如 <page>myvalue</page>)。
-
GetXMLFromRS:此實用程式建立記錄集的 XML 表示。
- GetXMLFromRSRow:此實用程式建立記錄集中當前行的 XML 表示。
此外,還有許多其它過程(統稱為 xxxWithDsplyNm)用於生成包含 displayname 屬性的 XML 標記,例如:
<f_name displayname="First Name">Joe</f_name>
標記的顯示名稱基於標記名,從 CatalogDefinitionProperties 應用程式級字典物件變數中檢索。
要全面瞭解 XML Helper 過程提供的功能,請檢視 Common.asp 中的原始碼。
ConsolidatedRetail.com 站點中的 XSL 樣式表
如前所述,每頁都有一個相關聯的“檔名”-Config.xml 檔案,該檔案列出了要應用於每種客戶端瀏覽器或裝置型別的 XSL 樣式表。在本實現方案中,只支援 Microsoft® Internet Explorer 5.5,儘管可以建立替代樣式表並將新增到站點來解決這一問題。
每個 PASP 頁的 XSL 檔案被命名為“頁名”-IE5.xsl(其中“頁名”是 PASP 頁的非版本特定名稱),該檔案包含該頁資料專用的 XSL 程式碼。但是,為了使站點保持統一的外觀,需要在一個單獨的 XSL 檔案(名為 UI_layout-IE5.xsl)中定義所有頁的公共使用者介面 (UI) 元素。該檔案儲存在 Include 目錄下。每一頁專用的 XSL 檔案使用 XSL Include 指令將 UI_layout-IE5.xsl 中的表示邏輯合併到當前頁的呈現形式中,如以下程式碼段所示:
<xsl:include href="include\UI_layout-IE5.xsl"/>
使用 UI_layout-IE5.xsl 中的模板
UI_layout-IE5.xsl 檔案包含幾個模板。page 模板將應用於每個 PASP 頁所生成的 XML 文件中的 <page> 元素。該模板引用 Stylesheet.css 級聯樣式表,並建立一個包含五行的 HTML 表,總體頁將基於該 HTML 表。系統呼叫 UI_layout-IE5.xsl 檔案中的其它模板來填充這些行。
表的第一行包含對 pageheader 模板的呼叫(該模板在後面的指令碼中定義)。該模板呈現頁首標題,包括連結到“購物籃”、“配置檔案”和“主頁”的圖象。
第二行用於建立距第三行的間距,而第三行包含對 main 模板的呼叫。該模板包含呈現頁左側菜單面板(包括搜尋表單)所需的邏輯。main 模板依次呼叫 getCatalogsForUser 模板、Exceptions 模板以及 advertising 或 profilemenu 模板(這取決於是否存在 advertising 或 profilemenu XML 元素)。
表的第四行與第二行類似,用於建立距第五行的間距;第五行則呼叫了 pagefooter 模板。該模板呈現頁的底部面板,包括版權宣告。
UI_layout-IE5.xsl 中的 page 模板如以下程式碼所示。可在 UI_layout-IE5.xsl 中檢視 pageheader、main、pagefooter 和其它用於呈現站點中的頁的模板。
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="*|/">
<xsl:apply-templates/></xsl:template>
<xsl:template match="text()|@*"><xsl:value-of select="."/></xsl:template>
<xsl:template match="page">
<html>
<head>
<title>ConsolidatedRetail.com</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css"/>
</head>
<body bgcolor="#ceb6d5" leftmargin="0" marginwidth="0" topmargin="0" marginheight="0" onload="Focus()">
<table width="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td>
<xsl:call-template name="pageheader"/>
</td>
</tr>
<tr>
<td height="10"/>
</tr>
<tr>
<td>
<xsl:call-template name="main"/>
</td>
</tr>
<tr>
<td height="10"/>
</tr>
<tr>
<td>
<xsl:call-template name="pagefooter"/>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
<!-- 為了表達得更為清楚,此處省略了其它模板的程式碼 -->
</xsl:stylesheet>
呈現 Index.pasp
您可以檢查 Index.pasp 頁,以檢視站點中各個頁之間的組合關係。Index.pasp 頁是站點的預設頁(即主頁)。Index.pasp 包含執行以下任務的程式碼:
- 用值 Index.pasp 定義一個名為 mc_strPageName 常量。
- 呼叫 Common.asp 中的 PageStart 過程,以建立相應的 <page> 開始標記。
- 使用 XMLEmptyTag 過程建立空的 <advertising/> 標記。
- 呼叫 PageEnd 過程建立 </page> 結束標記。
以下程式碼執行上述任務:
<!--#include file = "include/Site_Const.asp" -->
<!--#include file = "include/Common.asp"-->
<%
Const mc_strPageName = "Index.pasp"
Sub Main()
Call PageStart(mc_strPageName)
XMLEmptyTag(mc_strAdvertisingMenu)
Call PageEnd()
End Sub
Call Main()
%>
此程式碼生成以下 XML 文件:
<?xml-stylesheet type="text/xsl"
server-config="Index-Config.xml"
href="Index-IE5.xsl"?>
<page pagename="Index.pasp">
<advertising/>
<getcatalogsforuser>
<selectiontitle>瀏覽目錄:</selectiontitle>
<catalog>
<catalogname>書</catalogname>
</catalog>
<catalog>
<catalogname>硬體</catalogname>
</catalog>
</getcatalogsforuser>
<profile/>
<exceptions></exceptions>
</page>
這些 XML 程式碼將被傳遞到 XSLISAPI 過濾器,該過濾器確定在 Index-Config.xml 中指定相應的樣式表。XSLISAPI 過濾器檢查 HTTP 請求標頭資訊以確定瀏覽器的型別和版本。然後,對瀏覽器資訊與 Index-Config.xml 中的相應樣式表進行比較。如果未找到匹配條目,則應用預設樣式表 (Index-IE5.xsl)。
Index-Config.xml 類似於以下程式碼:
<?xml version="1.0" ?>
<server-styles-config>
<!-- 對於 HDML 3.0 瀏覽器 -->
<device target-markup="HDML 3.0">
<stylesheet href="Index-HDML3.xsl"/>
</device>
<!-- 對於 WML 1.1 瀏覽器 -->
<device target-markup="WML1.1">
<stylesheet href="Index-WML11.xsl"/>
</device>
<!-- 對於 IE 4.0 瀏覽器 -->
<device browser="IE" version="4.0">
<stylesheet href="Index-IE5.xsl"/>
</device>
<!-- 對於 IE 5.0 瀏覽器 -->
<device browser="IE" version="5.0">
<stylesheet href="Index-IE5.xsl"/>
</device>
<!-- 對於 MME 瀏覽器 -->
<device browser="MME">
<stylesheet href="Index-WML11.xsl"/>
</device>
</server-styles-config>
從 Internet Explorer 5.0 瀏覽器收到請求時,使用 Index-IE5.xsl 樣式表將頁作為 HTML 呈現。(Index-Config.xml 檔案中的其它條目只是作為例證;ConsolidatedRetail.com 站點中並不提供相應的樣式表。)
Index-IE5.xsl 類似於以下程式碼:
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:include href="include\UI_layout-IE5.xsl"/>
<xsl:template match="*|/"><xsl:apply-templates/></xsl:template>
<xsl:template match="text()|@*"><xsl:value-of select="."/></xsl:template>
<xsl:template name="pageleft"/>
<xsl:template name="pagecenter">
<script language="JavaScript">
<![CDATA[
function Focus(){
document.formSearch.txtSearchPhrase.focus()
}
]]>
</script>
<table width="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="#ffffff">
<tr>
<td width="11">
<img src="/china/msdn/images/spacer.gif" width="1" height="1" border="0"/>
</td>
<td valign="top" class="content-text">
<table width="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td valign="top" colspan="3" class="content-text">
<p class="headline-text-purple">歡迎來到 ConsolidatedRetail.com</p>
<p>歡迎來到本站點,您在這裡可以方便地購買到所需的任何商品。</p>
<p align="center"><a href="Registration.pasp"><img src="/china/msdn/images/home_freeshipping.gif" width="271" height="46" vspace="5" border="0"/></a><br/><br/></p>
</td>
</tr>
<tr>
<td valign="top" class="content-text">
<p><b> </b>
<br/> <img src="/china/msdn/images/spacer.gif" width="200" height="1" border="0"/></p>
</td>
<td width="1" bgcolor="#ceb6d5">
<img src="/china/msdn/images/spacer.gif" width="1" height="1" border="0"/>
</td>
<td width="125" align="right" valign="top" class="content-text">
<img src="/china/msdn/images/giftregistries.gif" width="118" height="30" border="0"/><br/>
<p>在不久的將來就可實現此功能。</p>
</td>
</tr>
</table>
</td>
<td width="11">
<img src="/china/msdn/images/spacer.gif" width="1" height="1" border="0"/>
</td>
</tr>
</table>
</xsl:template>
<xsl:template name="pageright"/>
</xsl:stylesheet>
此樣式表包含上文介紹的 UI_layout-IE5.xsl 樣式表。UI_layout-IE5.xsl 樣式表用於呈現頁的公共 UI 元素。在此示例中,XML 文件包含 <advertising/> 標記。因此,UI_layout-IE5.xsl 也使用 advertising 模板來呈現頁的右側面板。所得到的索引頁類似於圖 7-1。
圖 7-1:索引頁
ConsolidatedRetail.com 站點按照上文所述的方法呈現 PASP 頁。使用這種方法(在 PASP 檔案中生成 XML 內容,在 XSL 樣式表中定義表示形式),您可以輕鬆更改用於顯示頁面的樣式表,而不會影響 PASP 檔案中的業務邏輯。因此,這個解決方案十分靈活,便於重用。
使用者身份驗證和使用者配置檔案的維護
Microsoft® Commerce Server 2000 支援可擴充套件的配置檔案系統,可以儲存大量使用者資料。該使用者資料(或使用者配置檔案)可以包含收貨人地址和聯絡人資訊。客戶可以使用這些配置檔案來儲存個人資料,其中包括收貨人地址和聯絡人資訊,這樣他們就不必在每次訪問站點時都要重新輸入此類資訊。公司則可以將配置檔案資訊用於商業分析和開展有針對性的廣告宣傳活動。
要建立和維護配置檔案,使用者必須登入到站點並在站點上註冊。這將建立一個唯一使用者 ID,用於標識使用者以及從資料庫中檢索相應的配置檔案資訊。使用者的 ID 儲存在客戶端瀏覽器上的 cookie 中。如果使用者未登入,cookie 將包含與匿名使用者相關的使用者 ID,此時配置檔案資訊不可用。當用戶登入時,將檢索相應的使用者 ID 並將其寫入 cookie,這樣,在後面的會話過程中就能夠使用配置檔案資訊。
請注意,此站點要求將瀏覽器配置為允許 cookie。如果使用者使用配置為允許每會話 cookie(即不儲存到使用者硬碟上的 cookie)的瀏覽器來訪問此站點,而不儲存 cookie,則使用者將能夠登入到站點,也能使用站點,但是不能將產品放到購物籃中。如果根本不允許 cookie,則使用者將不能訪問此站點。
使用者註冊
使用者可以使用 Registration.pasp 頁註冊到此站點。使用 Registration-IE5.xsl 樣式表呈現該頁時,該頁包含一個向自身發回資料的表單。Registration.pasp 頁包含執行以下任務的程式碼:
- 檢查表單中的資料以確定 Mode 和 ProcessAction 引數。Mode 引數用於指定註冊完成後應將使用者重定向到的頁(預設值是 Acct.pasp)。ProcessAction 引數用於確定是顯示登錄檔單以便允許使用者註冊,還是將表單發回以進行處理。
- 將註冊資料傳送到 PutUserObject,以便建立新的配置檔案。PutUserObject 在 Profile.asp 標頭檔案中定義。
- 將使用者重定向到 Acct.pasp 頁(或 Mode 引數所指定的其它頁)。
- Registration.pasp 頁使用 MSCSAppFrameWork 應用程式級變數從查詢字串中檢索 Mode 和 ProcessAction 值,如以下程式碼段所示:
strPageMode = _ Application("MSCSAppFrameWork").RequestString( _ "Mode", Null, , , True, True, 0, Null) strProcessingAction = _ Application("MSCSAppFrameWork").RequestString( _ "ProcessAction", Null, , , True, True, 0, Null)
Mode 通常為空,這表示使用者已成功註冊,應重定向到帳戶管理頁 (Acct.pasp)。在某些情況下,Mode 包含其它頁的名稱,應將使用者重定向到該頁。例如,如果匿名使用者在註冊前將產品新增到了購物籃,您可能希望在使用者註冊後將使用者重定向到“結帳”頁。
ProcessAction 引數用於確定使用者是從站點中的另一頁進入註冊頁的,還是從註冊頁本身進入的。如果是前一種情況,將會呈現登錄檔單;如果是後一種情況,則會使用登錄檔單的內容來註冊使用者。如果 ProcessAction 引數是 EditUserObject,則可以使用該頁上表單中的資料來註冊使用者。
- 然後,指令碼將檢索表單資料並將資料傳遞到 PutUserObject 函式,該函式在 Profile.asp 標頭檔案中定義。該標頭檔案包含了管理使用者配置檔案的各種過程,站點中的各頁將要用到這些過程。PutUserObject 函式用於新增或更新使用者配置檔案,並返回指示成功或失敗的布林值。如果成功建立了使用者,則允許使用者登入並將其重定向到另一頁。如果失敗(例如由於指定的使用者名稱已存在),則重新顯示 Registration.pasp 頁,並顯示錯誤訊息指出問題所在。
- 程式碼呼叫 Common.asp 中的 GetUserID函式來檢索使用者 ID。該函式用於更新現有使用者,本章稍後將對其進行詳細討論。用於註冊新使用者的下一行重要程式碼將檢查是否存在具有指定使用者名稱的使用者:
Set objMSCSProfile = _ Application("MSCSProfileService").GetProfile(strUserName, _ _ mc_strUserObject, blnReturnCode) If Not (objMSCSProfile Is Nothing) Then Call AddException(m_varrExceptions, 1, _ "使用者名稱已存在。", mc_strPageName) Set objMSCSProfile = Nothing
- 如果尚未使用過該使用者名稱,程式碼將生成一個 GUID(唯一使用者 ID)並新增該使用者,同時呼叫 ProfileService 物件的 CreateProfile 方法。來自注冊表單的值將賦給配置檔案:
strUserID = GenerateGUID() Set objMSCSProfile = _ Application("MSCSProfileService").CreateProfile( _ strUserName, mc_strUserObject) objMSCSProfile.Fields(mc_strGeneralInfo).Value _ (mc_strUser_ID) = cstr(strUserID) objMSCSProfile.Fields(mc_strAccountInfo).Value _ (mc_strAccount_Status) = CInt(1) objMSCSProfile.Fields(mc_strGeneralInfo).Value _ ("user_type") = strUserType objMSCSProfile.Fields(mc_strGeneralInfo).Value _ (mc_strUser_Security_Password) = strPassword
- 該頁剩餘部分中的大多數程式碼用於更新現有使用者物件。最後,更新配置檔案物件,函式返回 True:
objMSCSProfile.Update Set objMSCSProfile = Nothing PutUserObject = True
該函式執行完畢後,新使用者就註冊到了站點資料庫。
- 使用者註冊後,Registration.pasp 將瀏覽器重定向到 Acct.pasp(如果 Mode 引數是 NULL)或 Mode 引數所指定的其它頁:
If blnRegistered Then If IsNull(strPageMode) Then Response.redirect "Acct.pasp?Mode=" & strPageMode Else Response.Redirect strPageMode & "?Mode=" & strPageMode End If End If
對使用者進行身份驗證
已註冊的使用者必須登入並通過身份驗證,才能訪問其配置檔案資訊。如上文中所述,Registration.pasp 中的程式碼將使新註冊的使用者自動登入。但是,使用者再次登入時,必須提供使用者名稱和口令才能通過身份驗證。
注意:在本應用程式示例中,登入詳細資訊是使用 HTTP 協議以純文字格式傳遞的。但在實際站點中,應使用安全超文字傳輸協議 (HTTPS) 對安全憑據進行加密。
使用者可以使用 Login.pasp 頁登入。與 Registration.pasp 一樣,此頁向自身傳送資料並使用 Profile.asp 的功能來處理資料。Login.pasp 頁包含執行以下任務的程式碼:
- 檢查表單中的資料以確定 Mode 和 ProcessAction 引數。Mode 引數用於指定登入完成後應將使用者重定向到的頁(預設值是 Acct.pasp)。ProcessAction 引數用於指定是顯示使用者憑據表單以便允許使用者登入,還是將表單發回以進行處理。
- 從該表單檢索使用者憑據。
- 將憑據傳遞到 Profile.asp 中的 Login 函式。
- 將使用者重定向到 Acct.pasp 頁(或 Mode 引數所指定的其它頁)。
- Login.pasp 中最重要的程式碼是對 Profile.asp 中 Login 函式的呼叫:
blnLoginSuccessful = Login(strUserName, strPassword)
-
Login 函式用於校驗使用者的使用者名稱和口令,並以 cookie 的形式將身份驗證單傳送到客戶端瀏覽器。該函式執行的第一個任務是使用以下程式碼建立並初始化 AuthManager 物件:
Set objMSCSAuthMgr = _ Server.CreateObject(mc_strAuthManager) Call objMSCSAuthMgr.Initialize _ (Application("MSCSDictConfig").s_SiteName)
- 然後,該程式碼將從前一登入中刪除使用者現有的所有身份驗證單:
If objMSCSAuthMgr.IsAuthenticated Then call objMSCSAuthMgr.SetAuthTicket _ ("", blnCookieSupport, _ Application("MSCSDictConfig")._ i_FormLoginTimeOut) End If
- 檢查並確保提供的使用者名稱非空後,程式碼將使用應用程式級 MSCSProfileService 物件為具有指定名稱的使用者載入配置檔案:
Set objMSCSProfileObject = Application("MSCSProfileService").GetProfile(strUserName,
mc_strUserObject, blnReturnCode) - 如果為已註冊的使用者找到了匹配的配置檔案,則檢索口令和使用者 ID,並將口令與使用者提供的口令進行比較:
strProfilePassword = _ objMSCSProfileObject(mc_strGeneralInfo).Value _ (mc_strUser_Security_Password) strUserID = objMSCSProfileObject(mc_strGeneralInfo). _ Value (mc_strUser_ID) If CStr(strProfilePassword) = CStr(strPassword) Then ...
- 在以匿名方式瀏覽時能夠將產品新增到購物籃,這是 ConsolidatedRetail.com 站點的設計特色之一。如果使用者在登入前就將產品新增到了購物籃,則已給該使用者簽發了一張匿名配置檔案單。AuthManager 物件現在要檢索此單據,以便將匿名使用者的購物籃內容傳輸到已通過身份驗證的使用者的購物籃:
strProfileUserID = _ objMSCSAuthMgr.GetUserID(mc_bytProfileTicketType)
- 為使用者簽發一個新單據(通過身份驗證的使用者單據),將匿名 cookie 設定為空白值,從而將其刪除:
Call objMSCSAuthMgr.SetAuthTicket _ (strUserID, blnCookieSupport, _ Application("MSCSDictConfig"). _ i_FormLoginTimeOut) Call objMSCSAuthMgr.SetUserID(mc_bytAuthTicketType, _ strUserID) Call objMSCSAuthMgr.SetUserID(mc_bytProfileTicketType, "") Call objMSCSAuthMgr.SetProfileTicket("", blnCookieSupport)
- 最後,傳輸匿名購物籃中的所有產品,並宣告登入成功:
If (Len(strProfileUserID) > 0) Then ' 從匿名會話獲取配置檔案 ' 物件 Set objMSCSUnRegProfileObject = Application( _ "MSCSProfileService").GetProfilebykey( _ mc_strUser_ID, strProfileUserID, _ mc_strUserObject, blnReturnCode) ' 如果返回匹配的匿名配置檔案 If Not (objMSCSUnRegProfileObject Is Nothing) Then ' 將購物籃內容從匿名 ID 傳輸到已註冊的 ' ID Call MoveBasketItems(strProfileuserid, strUserID) ' 從配置檔案儲存區中刪除匿名配置檔案 Call Application("MSCSProfileService"). _ DeleteProfileByKey(mc_strUser_ID, _ strProfileUserID, mc_strUserObject) End If Set objMSCSUnRegProfileObject = Nothing End if ' 返回表示成功登入的值 Logon = True
在之後的會話過程中,使用者為每個請求提供身份驗證 cookie,這樣,程式碼就可以檢索到使用者的配置檔案資訊。
檢索和更新配置檔案資訊
此站點允許使用者在多個頁上檢視和編輯其配置檔案資訊。由於各頁均使用類似的程式碼更新使用者配置檔案中的欄位,因此本章只詳細討論 UserProfile.pasp 頁。您也可以檢視 EditAddressBook.pasp 和 ChangePasswd.pasp 中的程式碼,它們執行類似的功能。
UserProfile.pasp 頁包含一個表單,使用者可在該表單中檢視和更改名字、姓氏、電子郵件地址和電話號碼的配置檔案值。其設計思路類似於上文所述的 Registration.pasp 頁。UserProfile.pasp 頁包含執行以下任務的程式碼:
- 檢查 ProcessingAction 查詢字串的值。如果值為 EditUserObject,則該頁已將表單內容傳送給自身,必須更新配置檔案。
- 從查詢字串中檢索表單值。
- 將表單值傳遞到 Profile.asp 中的 PutUserObject 函式。
- 將配置檔案值轉換為 XML 格式。
- 如上文所述,PutUserObject 函式用於在收到使用者名稱時註冊新使用者。如果未收到使用者名稱,則該函式假定使用者已存在並嘗試更新現有配置檔案中的資料。
- 要訪問配置檔案,PutUserObject 使用 Common.asp 中的 GetUserID 函式從身份驗證單中檢索當前使用者的 ID,如下所示:
Function GetUserID() Dim objMSCSAuthMgr '身份驗證管理器 Dim strUser_ID ' 從身份驗證管理器中 ' 檢索到的使用者 ID ' 將 AuthManager 物件例項化和初始化。 Set objMSCSAuthMgr = _ Server.CreateObject(mc_strAuthManager) Call objMSCSAuthMgr.Initialize _ (Application("MSCSDictConfig").s_SiteName) strUser_ID = Null ' 如果使用者已通過身份驗證且身份驗證單未 ' 超時 If objMSCSAuthMgr.IsAuthenticated Then ' 獲取進行身份驗證時所用的唯一登入 ID。 strUser_ID = _ objMSCSAuthMgr.GetUserID(mc_bytAuthTicketType) ' 否則,如果使用者以匿名方式進行瀏覽 Else ' 獲取配置檔案使用者 ID(即 GUID)。 ' 如果 getuserid 方法返回空字串 ' 將該字串轉換為 Null strUser_ID = _ objMSCSAuthMgr._ GetUserID(mc_bytProfileTicketType) If not isNull(strUser_ID) Then If len(trim(strUser_ID)) = 0 Then strUser_ID = Null End If End If End If ' 返回新的 GUID 或當前已通過身份驗證的 ' 使用者名稱 GetUserID = strUser_ID Set objMSCSAuthMgr = Nothing End Function
- 為了檢索使用者配置檔案,Profile.asp 中的 PutUserObject 函式程式碼使用了 ProfileService 物件的 GetProfileByKey 方法:
Set objMSCSProfile = Application("MSCSProfileService").GetProfilebyKey( _ mc_strUser_ID, strUserID, mc_strUserObject, blnReturnCode)
- 最後,程式碼更新該使用者的配置檔案欄位:
objMSCSProfile.Fields(mc_strGeneralInfo).Value( _ mc_strFirst_Name) = strFirstName objMSCSProfile.Fields(mc_strGeneralInfo).Value( _ mc_strLast_Name) = strLastName objMSCSProfile.Fields(mc_strGeneralInfo).Value( _ mc_strEmail_Address)= strEmailAddress objMSCSProfile.Fields(mc_strGeneralInfo).Value( _ mc_strTel_Number) = strTelNumber objMSCSProfile.Fields(mc_strGeneralInfo).Value( _ mc_strWork_Number) = strWorkNumber objMSCSProfile.Fields(mc_strGeneralInfo).Value( _ mc_strWork_Extension) = strWorkExtension objMSCSProfile.Fields(mc_strProfileSystem).Value( _ mc_strDate_Last_Changed) = Now objMSCSProfile.Update
- 更新配置檔案後,UserProfile.pasp 中的程式碼呼叫 GetUserObjectXML 過程,將整個使用者配置檔案作為 XML 呈現(實際上只顯示 UserProfile-IE5.xsl 中引用的欄位,但是可以在不更改程式碼的情況下,對該樣式表進行修改以顯示其它配置檔案資訊)。GetUserObjectXML 過程使用 ProfileService 物件的 GetProfileByKey 方法來檢索使用者的配置檔案。然後,使用 Include/common.asp 中的 XML Helper 例程呈現資料。GetUserObjectXML 例程類似於以下程式碼:
Sub GetUserObjectXML() Dim objMSCSProfile Dim strUserID Dim Field Dim Group Dim blnReturnCode Const c_strProfile = "userobject" strUserID = GetUserID If Not IsNull(strUserID) Then ' 使用指定架構初始化配置檔案服務並連線到配置檔案儲存區 If Not Application("MSCSProfileService") Is Nothing Then ' 使用配置檔案服務檢索使用者的配置檔案物件,並將該物件指派 ' 給函式的返回值 Set objMSCSProfile = Application("MSCSProfileService") _ .GetProfilebyKey(mc_strUser_ID, GetUserID, _ mc_strUserObject, blnReturnCode) If Not objMSCSProfile Is Nothing Then Call XMLBegTag(c_strProfile) For Each Group In objMSCSProfile.Fields Call XMLBegTag(Group.Name) For Each Field In Group.value Call XMLTag(Field.Name, Field.Value) Next Call XMLEndTag(Group.Name) Next Call XMLEndTag(c_strProfile) End If Set objMSCSProfile = Nothing End If End If End Sub
此過程將生成以下 XML 輸出:
<?xml-stylesheet type="text/xsl"
server-config="UserProfile-Config.xml"
href="UserProfile-IE5.xsl"?>
<page pagename="UserProfile.pasp">
<profilemenu/>
<pagemode/>
<userobject>
<accountinfo>
<org_id/>
<account_status>1</account_status>
<user_catalog_set/>
<date_registered/>
</accountinfo>
<advertising>
<campaign_history/>
</advertising>
<businessdesk>
<partner_desk_role/>
</businessdesk>
<generalinfo>
<user_id>
{8A7D56E9-DABA-499A-96B8-1F8DD93D032B}
</user_id>
<logon_name>Kim</logon_name>
<user_security_password>
password
</user_security_password>
<email_address>[email protected]</email_address>
<user_type>1</user_type>
<user_title/>
<last_name></last_name>
<first_name></first_name>
<tel_number></tel_number>
<tel_extension/>
<fax_number></fax_number>
<fax_extension></fax_extension>
<user_id_changed_by/>
</generalinfo>
<profilesystem>
<date_last_changed>
2/8/2001 11:57:13 PM
</date_last_changed>
<date_created>2/8/2001 11:57:13 PM</date_created>
</profilesystem>
</userobject>
<!—該頁的其餘內容由 Common.asp 生成 -->
<getcatalogsforuser>
<selectiontitle>瀏覽目錄:</selectiontitle>
<catalog>
<catalogname>書籍</catalogname>
</catalog>
<catalog>
<catalogname>硬體</catalogname>
</catalog>
</getcatalogsforuser>
<profile auth="auth"/>
<exceptions></exceptions>
</page>
ConsolidatedRetail.com 站點提供了有效的配置檔案功能,並演示了建立、檢索和更新使用者配置檔案資訊的基本方法。使用 Commerce Server Management Desk,您可以擴充套件此功能以建立自定義配置檔案屬性,並且可以使用配置檔案資訊為各個使用者提供站點個性化服務。有關使用 Commerce Server 2000 配置檔案功能的詳細資訊,請參考 Commerce Server 2000 文件。
產品目錄
為使用者提供瀏覽產品目錄的簡單方法,是設計電子商務站點時最重要的設計目標之一。ConsolidatedRetail.com 站點通過以下三種方式實現這一目標:
- 目錄始終在使用者介面中列出。
- 使用者可以通過分層的類別結構進行瀏覽。
- 使用者可以在目錄中搜索特定的字串。
當前使用者相關目錄集中的目錄始終列在使用者介面的左側窗格中。這是通過在 Common.asp 的 PageEnd 過程中加入確定並顯示可用目錄的程式碼來實現的:
- 該過程建立並初始化 CatalogSet 物件,然後呼叫其 GetCatalogsForUser 方法,傳遞 MSCSProfileService 應用程式級變數引用的 ProfileService 物件、當前使用者(可能是匿名使用者)的 ID 以及要使用的預設目錄集名(如果未給使用者指派特定目錄集):
Set objCatalogSets = _ Server.CreateObject(mc_strCatalogSets) Call objCatalogSets.Initialize _ (Application("MSCSDictConfig"). _ s_CatalogConnectionString, _ Application("MSCSDictConfig")._ s_TransactionsConnectionString) Set rsCatalogs = objCatalogSets.GetCatalogsForUser( _ Application("MSCSProfileService"), GetUserID & "", _ GetDefaultCatalogSet)
- 這將返回一個 ADO 記錄集物件,可以使用標準記錄集程式設計技術(例如檢查檔案結束 (EOF) 標記和使用 MoveNext 方法)瀏覽此物件:
Do While Not rsCatalogs.Eof Call XMLBegTag(c_strCatalog) Call getXMLFromRSwithdsplynm(rsCatalogs) Call XMLEndTag(c_strCatalog) rsCatalogs.MoveNext Loop
- 使用 UI_layout-IE5.xsl 樣式表呈現該程式碼生成的 XML 時,所得到的網頁將目錄集中每個目錄的名稱顯示為到 Category.pasp 的連結。生成的 XML 段類似於以下內容:
<catalog> <catalogname>書籍</catalogname> </catalog> <catalog> <catalogname>硬體</catalogname> </catalog>
目錄瀏覽功能
ConsolidatedRetail.com 解決方案中的目錄是以分層結構實現的。“書籍”和“硬體”這兩個目錄分別包含若干類別。“書籍”目錄還包含一個子類別層。產品可以儲存在目錄的任何一層上。
ConsolidatedRetail.com 站點中用於瀏覽目錄資料的頁是 Category.pasp。可以在兩種模式下使用該頁:根級模式或類別模式。在根級模式下,該頁從指定目錄的根來檢索產品和類別。在類別模式下,該頁從指定的類別來檢索產品、子類別和父類別。
該頁包含執行以下任務的程式碼:
- 使用 MSCSAppFrameWork 物件檢索請求字串中傳遞的 txtCatalog 和 txtCategory 值。如果未找到 txtCatalog 值,則該頁將使用者重定向到 Index.pasp。
- 呼叫PageStart 生成頁的 XML 標頭。
- 從 MSCSCatalogManager 應用程式變數檢索指定目錄的 ProductCatalog 物件,並將目錄名寫入 <searchscope> XML 元素。
- 將目錄屬性作為 XML 呈現。這樣,可以在使用者介面中呈現諸如目錄名這樣的屬性。
- 確定是否在請求字串中傳遞類別名。如果未指定類別名,則該頁從目錄的根來檢索類別和產品並將其轉換為 XML 格式。如果提供了類別,則該頁從提供的類別來檢索資料並將資料轉換為 XML 格式。
- 呼叫 PageEnd 過程來關閉 XML 文件。
在使用 Commerce Server 目錄物件檢索目錄資訊前,該頁使用以下程式碼來建立 <searchscope> 元素:
Call XMLTag(c_strSearchScope, strCatalogName)
UI_layout-IE5.xsl 樣式表使用此元素將當前目錄名傳遞到搜尋功能,然後限定搜尋範圍。(本章稍後將對搜尋功能進行詳細討論。)
實際目錄資料是使用 Commerce Server 自動化物件的分層結構進行檢索的。分層結構的頂層是 CatalogManager 物件,用於對目錄系統進行所有程式訪問。CatalogManager 物件包含一些 ProductCatalog 物件,這些物件代表站點中的目錄。在 Category.pasp 中,MSCSCatalogManager 應用程式級變數的 GetCatalog 方法用於檢索指定的目錄,如以下程式碼段所示:
Set objMSCSPrdCat = Application("MSCSCatalogManager"). _
GetCatalog(strCatalogName)
使用 GetCatalogAttributes 方法,可以將 ProductCatalog 物件的屬性作為 ADO 記錄集進行檢索。Category.pasp 中的程式碼使用此方法將記錄集中的每一行傳遞到 Common.asp 中的 GetXMLFromRSWithDsplyNm例程,該例程將行轉換為 XML 格式:
Set rsProperties = _
objMSCSPrdCat.GetCatalogAttributes
If Not (rsProperties.Eof And rsProperties.Bof) Then
Call XMLBegTag(c_strGetCatalogAttributes)
Do While Not rsProperties.Eof
'獲取記錄集行的 xml 版本
Call GetXMLFromRSWithDsplyNm(rsProperties)
rsProperties.MoveNext
Loop
Call XMLEndTag(c_strGetCatalogAttributes)
End If
這將生成以下格式的 XML 程式碼段:
<getcatalogattributes>
<catalogname>書籍</catalogname>
<locale>8</locale>
<startdate>12/8/1999</startdate>
<enddate>12/8/2006</enddate>
<variantid>ISBN</variantid>
<productid>標題</productid>
<currency>USD</currency>
<weightmeasure>lbs</weightmeasure>
<catalogid>1</catalogid>
<customcatalog>False</customcatalog>
<freetextindexcreated>2/8/2001 11:56:22 PM</freetextindexcreated>
<producttableupdated>2/8/2001 11:53:37 PM</producttableupdated>
</getcatalogattributes>
也可以使用記錄集物件來代表目錄根中的類別。RootCategories 方法用於從 Category.pasp 中檢索這些類別,如以下程式碼段所示(請注意,Fields 集合屬性用於從記錄集中檢索指定的資料欄位):
Set rsCategories = objMSCSPrdCat.RootCategories
'為了表達得更為清楚,此處省略了一些程式碼
Do While Not rsCategories.Eof
Call XMLBegTag(c_strRootCategory)
Call XMLTagWithDsplyNm("catalogname", objMSCSPrdCat.catalogname)
Call XMLTagWithDsplyNm("categoryname", _
rsCategories.fields("CategoryName").Value)
Call XMLEndTag(c_strRootCategory)
rsCategories.MoveNext
Loop
這將生成一個 XML 程式碼段,如下所示:
<rootcategory>
<catalogname>書籍</catalogname>
<categoryname>商業軟體</categoryname>
</rootcategory>
<rootcategory>
<catalogname>書籍</catalogname>
<categoryname>開發工具</categoryname>
</rootcategory>
<rootcategory>
<catalogname>書籍</catalogname>
<categoryname>特色產品</categoryname>
</rootcategory>
...
與之類似,對於目錄根中的產品,可以使用 RootProducts 方法對包含這些產品的記錄集進行檢索:
Set rsProducts = objMSCSPrdCat.RootProducts
為 rsProducts 記錄集中的每個產品生成的 XML 類似於以下程式碼:
<book>
<oid>64</oid>
<definitionname>SDKBook</definitionname>
<cy_list_price displayname="價格">19.99</cy_list_price>
<originalprice displayname="購買價">19.99</originalprice>
<i_classtype>4</i_classtype>
<parentoid>-1</parentoid>
<productid>
Microsoft Age of Empires II: The Age of Kings: Inside Moves
</productid>
<variantid/>
<title displayname="標題">Microsoft Age of Empires II: The Age of Kings: Inside Moves</title>
<isbn displayname="ISBN">0-7356-0513-0</isbn>
<description>在令人激動的新版 Microsoft Age of Empires 中,您將掌握能夠幫助您奪取勝利的所有關鍵性戰略策略、技巧和計謀!MICROSOFT AGE OF EMPIRES II: AGE OF KINGS: INSIDE MOVES 向您展示在從羅馬帝國滅亡到中世紀的數千年中如何為生存、富強而奮鬥。</description>
<image_filename>boxshots/press/2388.gif</image_filename>
<image_height>120</image_height>
<image_width>120</image_width>
<author displayname="作者">Microsoft Corporation</author>
<name displayname="名稱">Microsoft Age of Empires II: The Age of Kings: Inside Moves</name>
<pagecount displayname="頁數">280</pagecount>
<producturl displayname="產品資訊Url">a href=http://mspress.microsoft.com/prod/books/2388.htm target =_a http://mspress.microsoft.com/prod/books/2388.htm /a</producturl>
<publication_year displayname="出版年份">1999</publication_year>
<publisher displayname="出版者">Microsoft Press</publisher>
<reading_level displayname="閱讀級別:">所有級別</reading_level>
<catalogname>書籍</catalogname>
</book>
如果程式碼需要下鑽到更深的目錄並檢索其中某個類別的內容,可以使用 Category物件。Category.pasp 頁使用 Category 物件訪問指定類別的內容。該物件使用 ProductCatalog 物件的 GetCategory 方法進行例項化,如以下程式碼段中所示:
Set objMSCSCategory = _
objMSCSPrdCat.GetCategory(strCategoryName)
您可以使用 Products 屬性將類別中的產品作為記錄集檢索:
Set rsProducts = objMSCSCategory.products
Category 物件還提供 ChildCategories 屬性來檢索子類別的記錄集,提供ParentCategories 屬性返回父類別的記錄集。
無論它們在分層結構中的位置如何,您都可以使用 Commerce Server Business Desk 來建立產品目錄中類別和產品間的關係。Category 物件提供 RelatedCategories 和 RelatedProducts 屬性來檢索包含相應內容的記錄集。您在 Category.pasp 中可以看到有關如何使用這些物件的示例。
檢視產品
用於呈現目錄資料的 Category-IE5.xsl 樣式表會生成 HTML,這樣,在使用者單擊特定產品的“獲取詳細資料”連結時,將請求 Product.pasp 頁。該頁將顯示所選產品的特定資料。
Product.pasp 中的程式碼開頭部分與 Category.pasp 很相似。該程式碼在請求字串中檢索目錄、產品 ID 和可選的產品變數值。如果沒有目錄或產品 ID 引數,則將使用者重定向到 Index.pasp。然後,程式碼呼叫 PageStart 開始為該頁生成 XML。
使用 GetProduct 方法從目錄物件檢索 Commerce Server 產品物件時,程式碼變得有趣起來:
Set objMSCSPrd = objMSCSPrdCat.GetProduct(strProductID)
您可以使用 GetProductProperties 方法在記錄集物件中檢索產品的一些屬性,如產品名和價格:
Set rsProduct = objMSCSPrd.GetProductProperties
Commerce Server 目錄中的產品支援變體(如顏色或大小不同的產品)。您可以使用 Variants 屬性將特定產品的變數列表作為記錄集檢索。此外,還可以使用 RelatedProducts 和 RelatedCategories 屬性來檢索任何相關的產品或類別。利用這些屬性可以建立連結,獲得交叉銷售機會。Product.pasp 頁中使用所有這些屬性來為產品生成 XML 資料,下面列出了一段 XML 程式碼。然後使用 Product-IE5.xsl 樣式表來呈現這些資料。
<getproduct>
<book>
<catalogname>書籍</catalogname>
<definitionname>SDKBook</definitionname>
<cy_list_price displayname="價格">19.99</cy_list_price>
<originalprice displayname="購買價">19.99</originalprice>
<i_classtype>4</i_classtype>
<productid>Microsoft Age of Empires II: The Age of Kings: Inside Moves</productid>
<variantid/>
<author displayname="作者">Microsoft Corporation</author>
<description>在令人激動的新版 Microsoft Age of Empires 中,您將掌握能夠幫助您奪取勝利的所有關鍵性戰略策略、技巧和計謀!MICROSOFT AGE OF EMPIRES II: AGE OF KINGS: INSIDE MOVES 向您展示在從羅馬帝國滅亡到中世紀的數千年中如何為生存、富強而奮鬥。</description>
<image_filename>boxshots/press/2388.gif</image_filename>
<image_height>120</image_height>
<image_width>120</image_width>
<isbn displayname="ISBN">0-7356-0513-0</isbn>
<name displayname="名稱">Microsoft Age of Empires II: The Age of Kings: Inside Moves</name>
<pagecount displayname="頁數">280</pagecount>
<producturl displayname="Product Info. Url">a href=http://mspress.microsoft.com/prod/books/2388.htm target =_a http://mspress.microsoft.com/prod/books/2388.htm /a</producturl>
<publication_year displayname="出版年份">1999</publication_year>
<publisher displayname="出版者">Microsoft Press</publisher>
<reading_level displayname="閱讀級別:">所有級別</reading_level>
<title displayname="標題">Microsoft Age of Empires II: The Age of Kings: Inside Moves</title>
</book>
</getproduct>
搜尋目錄
除了提供使用者用於瀏覽目錄的頁面之外,一個高效的站點還應提供搜尋功能。在 ConsolidatedRetail.com 站點中,使用者可以輸入搜尋標準,在目錄中搜索特定產品。
使用 Commerce Server 2000 中的搜尋功能可以在當前目錄中進行搜尋,也可以在基於當前使用者的目錄集中進行搜尋。搜尋功能是在 SearchResults.pasp 中實現的,SearchResults.pasp 包含執行以下任務的程式碼:
- 從查詢字串中檢索搜尋短語、目錄、要返回的行數和開始位置引數(根據需要為返回的行數和開始位置引數賦予預設值,並在未提供搜尋短語的情況下產生異常)。
- 如果未指定目錄,則檢索基於當前使用者配置檔案的目錄集。
- 在指定目錄或使用者目錄集的目錄列表中搜索指定的搜尋短語。
- 將搜尋結果作為 XML 呈現。
搜尋目錄的實際程式碼使用應用程式級 MSCSCatalogManager 物件的 FreeTextSearch 方法來檢索記錄集中的搜尋結果。此方法接受以下引數:
- 搜尋短語
- 要搜尋的目錄列表(以逗號分隔)
- 應返回的屬性列表(以逗號分隔)
- 作為結果排序依據的屬性列表
- 表示按升序進行排序的布林值
- 開始進行搜尋的記錄號
- 要返回的號碼或行數
- 輸出引數,表示實際返回的總行數
如果使用者未指定目錄,將把當前使用者的預設目錄集作為記錄集進行檢索,並將每個目錄名連線成以逗號分隔的字串:
Set objCatalogSets = Server.CreateObject(mc_strCatalogSets)
Call objCatalogSets.Initialize _
(Application("MSCSDictConfig").s_CatalogConnectionString, _
Application("MSCSDictConfig").s_TransactionsConnectionString)
Set rsCatalogs = objCatalogSets.GetCatalogsForUser _
(Application("MSCSProfileService"), GetUserID & "", _
GetDefaultCatalogSet)
strCatalogsToSearch = ""
If Not (rsCatalogs.EOF And rsCatalogs.BOF) Then
Do While Not rsCatalogs.EOF
strCatalogsToSearch = strCatalogsToSearch & "," & _
rsCatalogs.Fields("CatalogName").Value & ""
rsCatalogs.MoveNext
Loop
strCatalogsToSearch = Trim(Mid(strCatalogsToSearch, 2))
End If
或者,如果指定了目錄,只需將目錄名賦給 strCatalogsToSearch 變數即可:
strCatalogsToSearch = strCatalogName
最後,呼叫 FreeTextSearch 方法:
Set rsProducts = _
Application("MSCSCatalogManager").FreeTextSearch _
(strSearchPhase, strCatalogsToSearch, , _
"CatalogName, CategoryName, DefinitionName, _
OriginalPrice, cy_list_price, i_ClassType,
ProductID, Description, image_filename, _
image_width, image_height, Name", _
"i_ClassType, CatalogName", _
True, _
lngSearchStartPos, _
lngSearchRowToReturn, _
lngTotalRecordsInQuery)
該頁上其餘的程式碼只是將 FreeTextSearch 返回的記錄集中的行轉換為 XML 格式,這樣,XSLISAPI 應用程式就可以呈現搜尋結果,以便進行顯示。為搜尋結果生成的 XML 具有以下格式:
<searchscope>書籍</searchscope>
<searchstring>Age of Empires</searchstring>
<searchcount>4</searchcount>
<searchrowstoreturn>15</searchrowstoreturn>
<searchstartpos>1</searchstartpos>
<searchresults>
<book>
<catalogname>書籍</catalogname>
<definitionname>SDKBook</definitionname>
<originalprice displayname="購買價">19.99</originalprice>
<cy_list_price displayname="價格">19.99</cy_list_price>
<i_classtype>4</i_classtype>
<productid>Microsoft Age of Empires II: The Age of Kings: Inside Moves</productid>
<description>在令人激動的新版 Microsoft Age of Empires 中,您將掌握能夠幫助您奪取勝利的所有關鍵性戰略策略、技巧和計謀!MICROSOFT AGE OF EMPIRES II: AGE OF KINGS: INSIDE MOVES 向您展示在從羅馬帝國滅亡到中世紀的數千年中如何為生存、富強而奮鬥。</description>
<image_filename>boxshots/press/2388.gif</image_filename>
<image_width>120</image_width>
<image_height>120</image_height>
<name displayname="名稱">Microsoft Age of Empires II: The Age of Kings: Inside Moves</name>
</book>
<!-- 為了表達得更為清楚,此處省略了其它結果 -->
<selectiontitle>根據搜尋標準 'Age of Empires' 找到的產品。</selectiontitle>
</searchresults>
“購物籃”管理
與大多數 B2C 站點一樣,ConsolidatedRetail.com 解決方案使用購物車或購物籃的概念將使用者選定要購買的產品集中在一起。無論是已登入的使用者還是匿名使用者,ConsolidatedRetail.com 都允許他們向購物籃新增產品;但是匿名使用者在結帳前必須登入。
向購物籃中新增產品
當用戶在 Product.pasp 頁上單擊“新增到購物車”連結時,會將產品和數量資訊傳送給 _additem.asp 頁。在將使用者重定向到顯示購物籃內容的 Basket.pasp 頁之前,該頁包含執行以下任務的程式碼:
- 檢索查詢字串中記錄的類別、產品、變數和目錄值。
- 校驗在查詢字串中傳遞的數量值(如果未傳遞數量,則新增專案的 1 個例項)。
- 將使用者的購物籃載入一個 OrderGroup 物件。
- 如果產品已在購物籃中列出,則將指定的數量新增到現有條目;否則為此產品建立新條目。
- 將使用者重定向到 Basket.pasp。
_additem.asp 頁呼叫 Basket.asp 標頭檔案中的 LoadBasket 函式來檢索包含當前使用者購物籃的 OrderGroup 物件。LoadBasket 函式類似於以下程式碼:
Function LoadBasket(strUserID)
Dim objMSCSOrderGroup
Set objMSCSOrderGroup = Server.CreateObject( _
mc_strOrderGroup)
Call objMSCSOrderGroup.Initialize(Application( _
"MSCSDictConfig").s_TransactionsConnectionString, _
strUserID)
Call objMSCSOrderGroup.LoadBasket()
Set LoadBasket = objMSCSOrderGroup
Set objMSCSOrderGroup = Nothing
End Function
請注意:OrderGroup 物件是通過傳遞 MSCSDictConfig 應用程式變數中定義的事務連線字串和當前使用者的使用者 ID 來建立和初始化的。(使用者 ID 取自 Profile.asp 標頭檔案中的 GetGuaranteedUserID 函式。對於已登入的使用者,將返回通過身份驗證的使用者 ID,對於匿名使用者,則返回配置檔案使用者 ID。)
然後,呼叫 OrderGroup 物件的 LoadBasket 方法來檢索與當前使用者相關聯的購物籃內容。
載入購物籃後,_additem.asp 中的程式碼搜尋購物籃中的明細專案,檢視是否列出了請求的產品。如果產品已在購物籃中,則在訂單上增加指定的數量,如下所示:
blnSkuMatched = False
'如果明細專案存在
If objMSCSOrderGroup.Value("total_lineitems") > 0 Then
'迴圈搜尋每個明細專案,查詢匹配項
For Each colItem in objMSCSOrderGroup.Value _
("OrderForms").Value("default").Items
If IsNull(strVariantID) Then
If (Trim(Cstr(colItem.product_id)) = _
Trim(Cstr(strProductID))) And _
IsNull(colItem.product_variant_id) Then
blnSkuMatched = True
Exit For
End If
Else
If (Trim(Cstr(colItem.product_id)) = _
Trim(Cstr(strProductID))) And _
Trim(Cstr(colItem. _
product_variant_id)) = _
Trim(Cstr(strVariantID))) Then
blnSkuMatched = True
Exit For
End If
End If
Next
If blnSkuMatched Then
' 如果專案已在購物籃中,則將新的專案數量加到
' 現有專案數量上
colItem.Quantity = colItem.Quantity + intProductQty
'儲存新的購物籃
Call objMSCSOrderGroup.SaveAsBasket()
...
如果產品未在購物籃中列出,則程式碼呼叫 AddItemToBasket 區域性函式,將其新增到購物籃中。AddItemToBasket 函式建立一個字典物件來表示該專案,並使用 OrderGroup 物件的 AddItem 方法將該專案新增到購物籃中。然後,使用 SaveAsBasket 方法儲存購物籃。AddItemToBasket 函式的程式碼類似於以下程式碼:
Function AddItemToBasket(objMSCSOrderGroup, _
strProductID, _
strCatalogName, intProductQty, _
strVariantID, strCategoryName)
Dim objMSCSProductDictionary
'建立產品字典
Set objMSCSProductDictionary = _
Server.CreateObject(mc_strDictionary)
objMSCSProductDictionary.lineitem_uid = GenerateGUID()
objMSCSProductDictionary.product_id = strProductID
objMSCSProductDictionary.product_catalog = strCatalogName
objMSCSProductDictionary.Quantity = intProductQty
If Not IsNull(strVariantID) Then
objMSCSProductDictionary.product_variant_id = _
strVariantID
End If
If Not IsNull(strCategoryName) Then
objMSCSProductDictionary.product_category = _
strCategoryName
End If
Call objMSCSOrderGroup.AddItem(objMSCSProductDictionary)
Call objMSCSOrderGroup.SaveAsBasket()
Set objMSCSProductDictionary = Nothing
End Function
請注意:新增專案是通過建立一個表示該專案的字典物件,然後將該專案傳遞給 OrderGroup(表示購物籃)的 AddItem 方法來實現的。
更新購物籃後,_additem.asp 中的程式碼將使用者重定向到 Basket.pasp。
檢視購物籃
使用者可以使用 Basket.pasp 頁檢視和編輯購物籃的內容。Basket.pasp 包含執行以下任務的程式碼:
- 檢查購物籃的完整性。
- 檢索使用者的使用者 ID(從身份驗證單或匿名配置檔案單中檢索)。
- 如果使用者的購物籃非空,則使用 PAGBasket 管道來檢索要顯示的購物籃資訊。
- 將明細專案總計數寫入 <totallineitems> XML 標記。
- 使用 Commerce Server DictionaryXMLTransforms 物件將購物籃內容轉換為 XML,並將其寫入響應。
該頁通過使用以下程式碼載入使用者的購物籃並檢查購物籃中是否包含產品:
Set objMSCSOrderGroup = LoadBasket(strUserID)
'檢查購物籃中是否包含專案
If Not IsBasketEmpty(objMSCSOrderGroup) Then
blnBasketIsEmpty = False
End If
Include/basket.asp 中的 IsBasketEmpty 函式檢查 OrderGroup 中是否包含專案。如果購物籃包含產品,則將購物籃傳遞給 PAGBasket 管道以便為顯示做準備:
Set objMSCSPipelines = Application("MSCSPipelines")
intErrorLevel = _
RunMtsPipeline(objMSCSPipelines.PAGBasket, _
objMSCSPipelines.LogFolder & strUserID & _
".log", _
objMSCSOrderGroup)
PAGBasket 管道
管道用於配置一系列元件,這些元件將以固定順序對一個業務物件進行操作。管道的操作分為幾個“階段”。在本示例中,PAGBasket 管道包含的元件對 OrderGroup 物件進行操作,該物件表示使用者的購物籃。您可以使用 Commerce Server 管道編輯器來檢視 PAGBasket 管道的配置,只需要開啟站點上“管道”資料夾中的 PAGBasket.pcf 檔案即可。PagBasket 管道如圖 7-2 所示。
圖 7-2:PAGBasket 管道
每次顯示購物籃時,PAGBasket 管道收集顯示購物籃所需的所有資料並進行必要的計算。除了在顯示購物籃之前執行該管道之外,在結帳過程的最後階段也要執行它,以便進行必要的計算來建立最終訂單總計。
產品資訊階段
該管道從“產品資訊”階段開始執行。此階段用於管理產品資訊,涉及以下兩個元件:
-
QueryCatalogInfo:QueryCatalogInfo 元件為訂單中的每個專案從目錄系統中檢索產品資訊。它將檢索到的資訊新增到訂單表單中的每個專案字典。
- RequiredProdInfo:RequiredProdInfo 元件檢查 OrderForm 中 items 集合的所有專案,並刪除 delete 鍵設定為 1 的所有專案。
訂單初始化階段
然後進入“訂單初始化”階段,初始化 OrderGroup 中的相應值。此階段只涉及一個元件:RequiredOrderInitCy。首先,RequiredOrderInitCy 確保 order_id 鍵有值。如果沒有值,RequiredOrderInitCy 將生成一個唯一訂單 ID,並將其賦給此鍵。然後,為了確保訂單完整性,該元件將把 NULL 值賦給各 total 鍵,將其初始化。最後,對於 items 集合中的每個專案,RequiredOrderInitCy 將儲存在 quantity 中的值複製到 _n_unadjusted 鍵,初始化未打折的專案數量,並將 _oadjust_adjustedprice (專案的總費用)初始化為零。
訂單檢查階段
“訂單檢查”階段校驗顯示的訂單是否有效以及是否包含後續處理所需的所有條目。此階段只涉及一個元件:RequiredOrderCheck。RequiredOrderCheck 元件確保 OrderForm 的專案列表不為空。
專案定價階段
“專案定價”階段為訂單表單中的每個專案設定 _iadjust_regularprice。此階段涉及以下兩個元件:
- DefaultItemPriceCy:對於訂單表單中的每個專案(即 items 集合中的每個專案),DefaultItemPriceCy 將 _iadjust_regularprice 鍵指派給 the _cy_product_list_price 中儲存的值。管道中“專案定價”階段後面的各個階段