前言
上一篇,我們完成了商品的詳情和商品的管理,這一篇我們來完成最后的一個購物車功能。
購物車,不外乎這幾個功能:添加商品到購物車,刪除購物車中的商品,對購物車中的商品進行結算。
MVC MusicStore中,在Models文件夾中添加了一個ShoppingCart類來處理這一塊的內容
這個類就類似我們的業務邏輯層,所以這里也采用了和它一樣的做法。
取購物車
首先來看一下取購物車這個靜態方法:
public static ShoppingCart GetCart(NancyContext context)
{var cart = new ShoppingCart();cart.ShoppingCartId = cart.GetCartId(context);return cart;
}
取購物車,其實只是給購物車類里面的ShoppingCartId賦值,而ShoppingCartId值是來自GetCartId方法:
public string GetCartId(NancyContext context)
{if (context.Request.Session[CartSessionKey] == null){if (context.CurrentUser != null){context.Request.Session[CartSessionKey] = context.CurrentUser.UserName;}else{Guid tempCartId = Guid.NewGuid();context.Request.Session[CartSessionKey] = tempCartId.ToString();}}return context.Request.Session[CartSessionKey].ToString();
}
在MVC MusicStrore中,這個方法的參數用的是HttpContextBase,而在Nancy中,Nancy有自己的Context
所以自然就是直接用Nancy自帶的Context。這里是每次都會為新用戶創建一個guid存儲在session中
并用這個session作為購物車的唯一標識。
在Nancy中,用到了session的話,需要在啟動器中啟用Session,不然Session會一直是空的。
我們在CustomerBootstrapper類的ApplicationStartup
方法中添加啟動Cookie的代碼,具體如下:
protected override void ApplicationStartup(TinyIoCContainer container,IPipelines pipelines)
{//enable the cookieCookieBasedSessions.Enable(pipelines);//Prevent errors on LinuxStaticConfiguration.DisableErrorTraces = false;
}
購物車商品數量
還記得我們在布局_Layout.cshtml里面還有一個購物車中的商品數量還沒有實現。我們現在把這個功能補上。
在ShoppingCart中添加下面取數的方法,這個方法是根據購物車的id去數據取出相應的數據。
public int GetCount()
{string cmd = "public.get_total_count_by_cartid";var res = DBHelper.ExecuteScalar(cmd, new{cid = ShoppingCartId}, null, null, CommandType.StoredProcedure);return Convert.ToInt32(res);
}
然后我們新建一個ShopCartModule.cs,并在構造函數中添加取數的方法。
Get["/cartsummary"] = _ =>
{var cart = ShoppingCart.GetCart(this.Context);return Response.AsJson(cart.GetCount());
};
最后在_Layout.cshtml中用ajax調用這個方法即可:
$.ajax({url: "/shoppingcart/cartsummary",method: "get",dataType: "json",success: function (res) {$("#cart-status").text('Cart (' + res + ')');}
});
這樣我們就徹底把布局頁完成了。下面是具體的效果
下面就專注購物車的其他實現了。
添加商品到購物車
添加商品到購物車,有這兩種情況:
添加了一個購物車中沒有的商品(要向購物車中插一條記錄)
添加了一個購物車中已經有了的商品(要向購物車中更新一條記錄)
所以我們就可以得到下面的實現(ShoppingCart):
public void AddToCart(Album album)
{string getItemCmd = "public.get_cart_item_by_cartid_and_albumid";var cartItem = DBHelper.QueryFirstOrDefault<Cart>(getItemCmd, new{cid = ShoppingCartId,aid = album.AlbumId}, null, null, CommandType.StoredProcedure);string addToCartCmd = string.Empty;if (cartItem == null){// Create a new cart item if no cart item existsAddCartItem(cartItem, album.AlbumId);}else{UpdateCartItem(cartItem);}
}
在添加之前都要向根據購物車標識和專輯(商品)標識去判斷。此時我們在Module中的實現就比較簡單了
Get["/addtocart/{id:int}"] = _ =>
{int id = 0;if (int.TryParse(_.id, out id)){string cmd = "public.get_album_by_aid";var addedAlbum = DBHelper.QueryFirstOrDefault<Album>(cmd, new{aid = id}, null, null, CommandType.StoredProcedure);var cart = ShoppingCart.GetCart(this.Context);cart.AddToCart(addedAlbum);}return Response.AsRedirect("~/");
};
后臺邏輯處理好了,我們把商品加入購物車的入口在那呢?入口就在商品詳情頁下面的【Add to cart】按鈕
當我們把加入購物車后,可以看到右上角的數量在改變,同時跳轉回了首頁。
購物車首頁
我們已經完成了添加商品到購物車,但是我們還看不到我們購物車里面有些什么商品,所以要有一個購物車首頁。
購物車的首頁,本質就是一個列表,這個列表所列了購物車內的所有商品,包含了這些商品的基本信息和購物車的訂單總金額。
Get["/index"] = _ =>
{var cart = ShoppingCart.GetCart(this.Context);// Set up our ViewModelvar viewModel = new ShoppingCartViewModel{CartItems = cart.GetCartItems(),CartTotal = cart.GetTotal()};// Return the viewreturn View["Index", viewModel];
};
視圖如下 :
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<NancyMusicStore.ViewModels.ShoppingCartViewModel>
@{ViewBag.Title = "Shopping Cart";
}
<h3><em>Review</em> your cart:
</h3>
<p class="button"><a href="javascript:;">Checkout >></a>
</p>
<div id="update-message">
</div>
<table><tr><th>Album Name</th><th>Price (each)</th><th>Quantity</th><th></th></tr>@foreach (var item in Model.CartItems){<tr id="row-@item.RecordId"><td><a href="/store/details/@item.AlbumId">@item.Title</a></td><td>@item.Price</td><td id="item-count-@item.RecordId">@item.Count</td><td><a href="javascript:void(0);" class="RemoveLink" data-id="@item.RecordId">Remove from cart</a></td></tr>}<tr><td>Total</td><td></td><td></td><td id="cart-total">@Model.CartTotal</td></tr>
</table>
具體效果如下所示:
從購物車中刪除商品
刪除購物車中的商品也是同樣的有兩種情況
一種是讓購物車中的商品數量減1
一種是從購物車中直接刪掉商品,不同的是刪除的同時返回了商品的數量,這個數量用于在頁面展示。
public int RemoveFromCart(int id)
{string getItemCmd = "public.get_cart_item_by_cartid_and_recordid";var cartItem = DBHelper.QueryFirstOrDefault<Cart>(getItemCmd, new{cid = ShoppingCartId,rid = id}, null, null, CommandType.StoredProcedure);int itemCount = 0;if (cartItem != null){ if (cartItem.Count > 1){UpdateCartItemCount(cartItem, itemCount); }else{RemoveCartItem(cartItem.RecordId);}}return itemCount;
}
同時還要在購物車列表頁面添加相應的JS處理
@section scripts{<script type="text/javascript">$(function () {$(".RemoveLink").click(function () {var recordToDelete = $(this).attr("data-id");if (recordToDelete != '') {$.post("/shoppingcart/removefromcart", { "id": recordToDelete },function (data) {if (data.ItemCount == 0) {$('#row-' + data.deleteid).fadeOut('slow');} else {$('#item-count-' + data.deleteId).text(data.itemCount);}$('#cart-total').text(data.cartTotal);$('#update-message').text(data.message);$('#cart-status').text('Cart (' + data.cartCount + ')');});}});});</script>
}
最后的話就是結算,下面進入我們的結算操作
購物車結算
購物車結算,也就是提交訂單,也就是填寫一些用戶的相關信息,比如:姓名、地址、聯系電話等等這些信息,見下圖。
我們在Modules文件夾中添加一個CheckOutModule.cs用來處理結算相關的功能。
要結算,必須要登錄,所以我們要首先添加需要授權的這句代碼this.RequiresAuthentication();
然后再考慮其他事情。
提交訂單的后臺操作如下:
Post["/addressandpayment"] = _ =>
{var order = this.Bind<Order>();order.Username = this.Context.CurrentUser.UserName;order.OrderDate = DateTime.UtcNow;string cmd = "public.add_order";var res = DBHelper.ExecuteScalar(cmd, new{odate = order.OrderDate,uname = order.Username,fname = order.FirstName,lname = order.LastName,adr = order.Address,cn = order.City,sn = order.State,pcode = order.PostalCode,cname = order.Country,ph = order.Phone,ea = order.Email,t = order.Total}, null, null, CommandType.StoredProcedure);if (Convert.ToInt32(res) != 0){order.OrderId = Convert.ToInt32(res);var cart = ShoppingCart.GetCart(this.Context);cart.CreateOrder(order);string redirectUrl = string.Format("/checkout/complete/{0}", res.ToString());return Response.AsRedirect(redirectUrl);}return View["AddressAndPayment"];
};
先是創建了一張訂單,這張訂單只包含了一些用戶信息。訂單創建好了之后才去創建訂單明細,最后就是返回訂單完成頁:
創建訂單明細的方法也是寫在Models下面的ShoppingCart中,具體如下:
public int CreateOrder(Order order)
{decimal orderTotal = 0;var cartItems = GetCartItems(); foreach (var item in cartItems){ AddOrderDetails(new OrderDetail{AlbumId = item.AlbumId,OrderId = order.OrderId,UnitPrice = item.Price,Quantity = item.Count});// Set the order total of the shopping cartorderTotal += (item.Count * item.Price);}UpdateOrderTotal(order.OrderId, orderTotal); // Empty the shopping cartEmptyCart();// Return the OrderId as the confirmation numberreturn order.OrderId;
}
這里做的操作主要有三個:
- 把購物車中的商品插入到訂單明細表中
- 更新訂單主表的總金額
- 清空當前的購物車
到這里,我們的NancyMusicStore已經是到了收尾階段。就差部署上線了啊!!
所以在下一篇,將是介紹Nancy的部署,分別在Windows和Linux下部署。
本文也已經同步到 Nancy之大雜燴