幸运星空

Lucker的程序人生

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

前言

购物篮模块是PetShop4中最最重的模块之一。在数据库中,与购物篮联系最紧密的就是Cart表了(关于Cart表请参见本系列博文第一篇相关部分)。

购物篮的数据访问层(DAL)

购物篮模块中设计了实体类,这样可以快速为数据库中各字段赋值,体现数据结构的整体性。PetShop4的所有的实体类都保存的项目Model中。

其中的CardItemInfo类与Card表基本对应,可以实现对Card表的快速存取。

购物篮的数据访问是通过Profile工厂模式实现的。工厂模式的基本原理以前面的文章中已有简介,这里用户只要知道如何调用Profile就行了。最终实现对数据库的访问是通过SQLProfileDAL项目中的PetShopProfileProvider类来完成的。该类中有关购物篮的部分方法如下:

/// Retrieve collection of shopping cart items

public IList<CartItemInfo> GetCartItems(string userName, string appName, bool isShoppingCart)

/// Update shopping cart for current user

public void SetCartItems(int uniqueID, ICollection<CartItemInfo> cartItems, bool isShoppingCart)

/// Update activity dates for current user and application

public void UpdateActivityDates(string userName, bool activityOnly, string appName)

/// Retrive unique id for current user

public int GetUniqueID(string userName, bool isAuthenticated, bool ignoreAuthenticationType, string appName)

/// Create profile record for current user

public int CreateProfileForUser(string userName, bool isAuthenticated, string appName)

下图保存购物篮信息的实现流程图:

image

购物篮的业务逻辑层(BLL)

在三层结构中,业务逻辑层处在中间层,是承上启下的一层,它为用户调用提供一个接口,并启动数据访问层来完成用户操作,由于DAL与业务逻辑无关,所以BLL是实现用户数据逻辑处理的关键层.当数据访问层的SQL语句发生变化时,只需要改变DAL层的部分内容,不会影响到BLL等上面层.BLL主要作用就是实现当前业务的操作功能.

系统中所有业务逻辑层的处理类类位于BLL项目下,PepShop4中购物篮功能的业务逻辑主要包括:添加商品到购物篮,移除购物篮中的商品,更新购物篮中的某件商品的数量,清空购物篮,获取购物篮中商品总数及总价格,获得购物篮中某商品的记录等.实现这些操作主要是通过Card类来完成的,Card类的结构如下图:

image

购物篮的界面层(UI)

界面层位于Web项目下,购物篮的界面层文件是:ShoppingCard.aspx.打开该文件的HTML视图,

首先,该页面应用了母版面:MasterPageFile="~/MasterPage.master"

其次,页面上注册了一个用户控件:ShoppingCardControl,注册代码如下:

<%@ Register Src="Controls/ShoppingCartControl.ascx" TagName="ShoppingCartControl" TagPrefix="PetShopControl" %>

接下来在页面上声明了这一控件:

<PetShopControl:shoppingcartcontrol id="ShoppingCartControl1" runat="server"></PetShopControl:shoppingcartcontrol>

打开ShoppingCartControl.ascx控件的设计界面,购物篮商品列表是由一个Reparter控件来呈现的。其中记录显示格式如下:

<ItemTemplate>
            <tr class="listItem">
                <td>
                    <asp:ImageButton ID="btnDelete" runat="server" BorderStyle="None" CausesValidation="false"
                    CommandArgument='<%# Eval("ItemId") %>' CommandName="Del" ImageUrl="~/Comm_Images/button-delete.gif"
                    OnCommand="CartItem_Command" ToolTip="Delete" />
                </td>
                <td style="width:100%;">
                    <a runat="server" href='<%# string.Format("~/Items.aspx?itemId={0}&productId={1}&categoryId={2}", Eval("ItemId"), Eval("ProductId"), Eval("CategoryId")) %>'><%# string.Format("{0} {1}", Eval("Name"), Eval("Type")) %></a>
                </td>
                <td>
                    <asp:TextBox ID="txtQuantity" runat="server" Columns="3" Text='<%# Eval("Quantity") %>' Width="20px"></asp:TextBox>
                </td>
                <td align="right"><%# Eval("Price", "{0:c}")%></td><td>
                   <asp:ImageButton ID="btnToWishList" runat="server" AlternateText="Move to wish list" CausesValidation="false" CommandArgument='<%# Eval("ItemId") %>' CommandName="Move" ImageUrl="~/Comm_Images/button-wishlist.gif" OnCommand="CartItem_Command" ToolTip="Move to wish list" />
                </td>
            </tr>
</ItemTemplate>

显示购物篮界面

需要注意的是,当用户打开购物篮界面时,系统会自动检索用户之前添加过的购物篮信息,并加载到界面上。这一功能是怎样实现的呢?

加载先前购物信息的功能是在页面的“Page_PreRender”事件中完成的。该事件调用“BindCart”方法,其中“BindCart”方法的代码如下:

private void BindCart() {
    ICollection<CartItemInfo> cart = Profile.ShoppingCart.CartItems;
    if (cart.Count > 0) {
        repShoppingCart.DataSource = cart;
        repShoppingCart.DataBind();
        PrintTotal();
        plhTotal.Visible = true;
    }
    else {
        repShoppingCart.Visible = false;
        plhTotal.Visible = false;
        lblMsg.Text = "Your cart is empty.";
    }
}

添加商品到购物篮

protected void Page_PreInit(object sender, EventArgs e) {
    if (!IsPostBack) {
        string itemId = Request.QueryString["addItem"];
        if (!string.IsNullOrEmpty(itemId)) {
            Profile.ShoppingCart.Add(itemId);
            Profile.Save();
            // Redirect to prevent duplictations in the cart if user hits "Refresh"
            Response.Redirect("~/ShoppingCart.aspx", true);
        }
    }
}

其中语句:Profile.ShoppingCart.Add(itemId);是功能操作的关键语句,该语句的实现流程如下:

调用BLL项目中Cart类中的Add方法→调用Profile项目中PetShopProfileProvider类的SetPropertyValues方法
→调用同类中的SetCartItems方法向购物篮中添加商品信息
→调用SQLProfileDAL项目中的PetShopProfileProvider类的CreateProfileForUser方法添加用户的配置信息

更改商品数量

protected void BtnTotal_Click(object sender, System.Web.UI.ImageClickEventArgs e) {
    TextBox txtQuantity;
    ImageButton btnDelete;
    int qty = 0;
    foreach (RepeaterItem row in repShoppingCart.Items) {
        txtQuantity = (TextBox)row.FindControl("txtQuantity");
        btnDelete = (ImageButton)row.FindControl("btnDelete");
        if (int.TryParse(WebUtility.InputText(txtQuantity.Text, 10), out qty)) {                  
            if (qty > 0)
                Profile.ShoppingCart.SetQuantity(btnDelete.CommandArgument, qty);
            else if (qty == 0)
                Profile.ShoppingCart.Remove(btnDelete.CommandArgument);
        }

    }
    Profile.Save();
    BindCart();
}

计算商品总价

private void PrintTotal() {
    if (Profile.ShoppingCart.CartItems.Count > 0)
        ltlTotal.Text = Profile.ShoppingCart.Total.ToString("c");
}

移除购物篮中的商品

protected void CartItem_Command(object sender, CommandEventArgs e) {
    switch (e.CommandName.ToString()) {
        case "Del":
            Profile.ShoppingCart.Remove(e.CommandArgument.ToString());
            break;
        case "Move":
            Profile.ShoppingCart.Remove(e.CommandArgument.ToString());
            Profile.WishList.Add(e.CommandArgument.ToString());
            break;
    }
    Profile.Save();
    BindCart();
}

匿名用户到验证用户购物篮的转移

PetShop4中一个重要的特点是它允许用户不登录时就可以选择商品,并可以将商品添加到购物篮,然后当用户登录后,再将用户登录前选择的商品保存到验证过的个性配置中。

.Net 3.5提供了一种匿名登录的方法,它会为用户自动生成一个UserName,当匿名用户选择商品到购物篮中是地,系统自动在Profile表中保存这个匿名用户的名字,保存用户的购物篮,当用户登录后,只需要将表中的用户名替换掉就行了。

要实现此功能,首先,在Web.config中激活:

<anonymousIdentification enabled="true"/>
<profile automaticSaveEnabled="false" defaultProvider="ShoppingCartProvider">
    <providers>
        <add name="ShoppingCartProvider" connectionStringName="SQLProfileConnString" type="PetShop.Profile.PetShopProfileProvider" applicationName=".NET Pet Shop 4.0"/>
        <add name="WishListProvider" connectionStringName="SQLProfileConnString" type="PetShop.Profile.PetShopProfileProvider" applicationName=".NET Pet Shop 4.0"/>
        <add name="AccountInfoProvider" connectionStringName="SQLProfileConnString" type="PetShop.Profile.PetShopProfileProvider" applicationName=".NET Pet Shop 4.0"/>
    </providers>
    <properties>
        <add name="ShoppingCart" type="PetShop.BLL.Cart" allowAnonymous="true" provider="ShoppingCartProvider"/>
        <add name="WishList" type="PetShop.BLL.Cart" allowAnonymous="true" provider="WishListProvider"/>
        <add name="AccountInfo" type="PetShop.Model.AddressInfo" allowAnonymous="false" provider="AccountInfoProvider"/>
    </properties>
</profile>

其次是要正确处理匿名迁移,系统中使用Profile_MigrateAnonymous事件来处理,此事件一般在Global.asax文件中。

void Profile_MigrateAnonymous(Object sender, ProfileMigrateEventArgs e) {
    ProfileCommon anonProfile = Profile.GetProfile(e.AnonymousID);

    // Merge anonymous shopping cart items to the authenticated shopping cart items
    foreach (CartItemInfo cartItem in anonProfile.ShoppingCart.CartItems)
        Profile.ShoppingCart.Add(cartItem);

    // Merge anonymous wishlist items to the authenticated wishlist items
    foreach (CartItemInfo cartItem in anonProfile.WishList.CartItems)
        Profile.WishList.Add(cartItem);

    // Clean up anonymous profile
    ProfileManager.DeleteProfile(e.AnonymousID);
    AnonymousIdentificationModule.ClearAnonymousIdentifier();
    // Save profile
    Profile.Save();
}

posted on 2008-12-21 15:37  Lucker  阅读(671)  评论(0编辑  收藏  举报