- 浏览: 12953954 次
- 性别:
- 来自: 大连
文章分类
最新评论
-
sanrenxing_1:
GoEasy 实时推送支持IE6-IE11及大多数主流浏览器的 ...
WindowsPhone消息推送服务 -
张砚辉:
两侧照片绕Y轴旋转后有锯齿,请问锯齿解决方案,很长时间没解决
自定义带倒影和偏转的超炫Gallery -
knight_black_bob:
能不能把你自己的博客整理下分类下,写了这么多 ,都不知道怎么查 ...
Android_View,ViewGroup,Window之间的关系 -
jeasonyoung:
你这个代码实现在iOS8下应该是滑不动的
UISlider 滑块控件—IOS开发 -
wx_hello:
如果能写个可运行的java程序,不胜感激。。。
rs232串口通信原理
商务参考体系结构:企业对消费者
第 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>Kim@somecompany.com</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 中存储的值。管道中“项目定价”阶段后面的各个阶段
发表评论
相关推荐
详细介绍了开发电子商务网站从功能模块分析到数据库设计流程 是一部值得看的文章
描叙电子商务B2C的前后台功能的组成结构,对于设计电子商务网站功能有比较好的参考价值
第9章 电子商务服务业实战 4479.1 网上人才市场实践 4479.2 网上交友实践 4479.3 旅游电子商务实践 447 第10章 Web 2.0应用 44810.1 Blog实践 44810.2 WIKI实践 44810.3 人人网实践 448 第11章 实验中所涉及的数据 ...
第9章 电子商务服务业实战 433 9.1 网上人才市场实践 433 9.2 网上交友实践 433 9.3 旅游电子商务实践 433 第10章 Web 2.0应用 434 10.1 Blog实践 434 10.2 WIKI实践 434 10.3 人人网实践 434 第11章 实验中所涉及的...
基于J2EE的B2C电子商务系统开发.zip基于J2EE的B2C电子商务系统开发.zip基于J2EE的B2C电子商务系统开发.zip基于J2EE的B2C电子商务系统开发.zip基于J2EE的B2C电子商务系统开发.zip基于J2EE的B2C电子商务系统开发.zip...
电子商务:Part2 网上零售B2C.pptx
第三章B2C电子商务.pptx
目 录 ...实践三:旅游电子商务实践 403 第九部分 Web 2.0应用 403 实践一:Blog实践 403 实践二:WIKI实践 403 实践三:校内网实践 403 第十部分 教师管理平台操作说明 403 第十一部分 基础数据 411
B2C电子商务系统:B2C(Business To Customer)是电子商务按交易对象分类中的一种(企业对个人),即表示商业机构对消费者的电子商务。这种形式的电子商务一般以网络零售业为主,主要借助于Internet开展在线销售活动,...
我国电子商务B2C企业的发展趋势和经营策略.doc
目 录 1 DQG-LPG电子商务平台总体结构设计原则与技术路线 1 1.1 设计原则 1 1.2 技术路线 2 2 DQG-LPG电子商务平台体系结构 3 2.1 系统总体集成模型 3 2.2 系统功能结构 4 3 分系统功能设计 5 3.1 B2B 电子商务平台...
B2C电子商务推广方案简析.B2C电子商务推广方案简析.B2C电子商务推广方案简析.
适合练手、课程设计、毕业设计的Java项目源码:基于J2EE的B2C电子商务系统开发(论文+系统+开题报告+答辩PPT).rar 适合练手、课程设计、毕业设计的Java项目源码:基于J2EE的B2C电子商务系统开发(论文+系统+开题...
第7章电子商务信息安全(14) 244 7.1电子商务信息安全需求 245 7.2电子商务安全的常用技术 250 7.3电脑病毒及其防治(14) 266 思考题 272 第8章 电子支付系统(78) 273 8.1 电子支付工具--电子货币(20) 275 8.2 ...
B2C电子商务案例分析 有详细图文结合介绍 供大家学习交流
b2c电子商务网站源码
第三章电子商务交易B2C.docx
第04章B2C电子商务PPT文档.pptx
B2C电子商务交易系统-论文正文B2C电子商务交易系统-论文正文B2C电子商务交易系统-论文正文B2C电子商务交易系统-论文正文B2C电子商务交易系统-论文正文B2C电子商务交易系统-论文正文
(Java毕业设计)基于J2EE的B2C电子商务系统开发(Java毕业设计)基于J2EE的B2C电子商务系统开发(Java毕业设计)基于J2EE的B2C电子商务系统开发(Java毕业设计)基于J2EE的B2C电子商务系统开发(Java毕业设计)基于J2EE的B2C...