Nancy简单实战之NancyMusicStore(四):实现购物车
前言
上一篇,我們完成了商品的詳情和商品的管理,這一篇我們來(lái)完成最后的一個(gè)購(gòu)物車功能。
購(gòu)物車,不外乎這幾個(gè)功能:添加商品到購(gòu)物車,刪除購(gòu)物車中的商品,對(duì)購(gòu)物車中的商品進(jìn)行結(jié)算。
MVC MusicStore中,在Models文件夾中添加了一個(gè)ShoppingCart類來(lái)處理這一塊的內(nèi)容
這個(gè)類就類似我們的業(yè)務(wù)邏輯層,所以這里也采用了和它一樣的做法。
取購(gòu)物車
首先來(lái)看一下取購(gòu)物車這個(gè)靜態(tài)方法:
public static ShoppingCart GetCart(NancyContext context) {var cart = new ShoppingCart();cart.ShoppingCartId = cart.GetCartId(context);return cart; }取購(gòu)物車,其實(shí)只是給購(gòu)物車類里面的ShoppingCartId賦值,而ShoppingCartId值是來(lái)自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中,這個(gè)方法的參數(shù)用的是HttpContextBase,而在Nancy中,Nancy有自己的Context
所以自然就是直接用Nancy自帶的Context。這里是每次都會(huì)為新用戶創(chuàng)建一個(gè)guid存儲(chǔ)在session中
并用這個(gè)session作為購(gòu)物車的唯一標(biāo)識(shí)。
在Nancy中,用到了session的話,需要在啟動(dòng)器中啟用Session,不然Session會(huì)一直是空的。
我們?cè)贑ustomerBootstrapper類的ApplicationStartup方法中添加啟動(dòng)Cookie的代碼,具體如下:
protected override void ApplicationStartup(TinyIoCContainer container,IPipelines pipelines) {//enable the cookieCookieBasedSessions.Enable(pipelines);//Prevent errors on LinuxStaticConfiguration.DisableErrorTraces = false; }購(gòu)物車商品數(shù)量
還記得我們?cè)诓季謃Layout.cshtml里面還有一個(gè)購(gòu)物車中的商品數(shù)量還沒(méi)有實(shí)現(xiàn)。我們現(xiàn)在把這個(gè)功能補(bǔ)上。
在ShoppingCart中添加下面取數(shù)的方法,這個(gè)方法是根據(jù)購(gòu)物車的id去數(shù)據(jù)取出相應(yīng)的數(shù)據(jù)。
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); }然后我們新建一個(gè)ShopCartModule.cs,并在構(gòu)造函數(shù)中添加取數(shù)的方法。
Get["/cartsummary"] = _ => {var cart = ShoppingCart.GetCart(this.Context);return Response.AsJson(cart.GetCount()); };最后在_Layout.cshtml中用ajax調(diào)用這個(gè)方法即可:
$.ajax({url: "/shoppingcart/cartsummary",method: "get",dataType: "json",success: function (res) {$("#cart-status").text('Cart (' + res + ')');} });這樣我們就徹底把布局頁(yè)完成了。下面是具體的效果
下面就專注購(gòu)物車的其他實(shí)現(xiàn)了。
添加商品到購(gòu)物車
添加商品到購(gòu)物車,有這兩種情況:
添加了一個(gè)購(gòu)物車中沒(méi)有的商品(要向購(gòu)物車中插一條記錄)
添加了一個(gè)購(gòu)物車中已經(jīng)有了的商品(要向購(gòu)物車中更新一條記錄)
所以我們就可以得到下面的實(shí)現(xiàn)(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);} }在添加之前都要向根據(jù)購(gòu)物車標(biāo)識(shí)和專輯(商品)標(biāo)識(shí)去判斷。此時(shí)我們?cè)贛odule中的實(shí)現(xiàn)就比較簡(jiǎn)單了
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("~/"); };后臺(tái)邏輯處理好了,我們把商品加入購(gòu)物車的入口在那呢?入口就在商品詳情頁(yè)下面的【Add to cart】按鈕
當(dāng)我們把加入購(gòu)物車后,可以看到右上角的數(shù)量在改變,同時(shí)跳轉(zhuǎn)回了首頁(yè)。
購(gòu)物車首頁(yè)
我們已經(jīng)完成了添加商品到購(gòu)物車,但是我們還看不到我們購(gòu)物車?yán)锩嬗行┦裁瓷唐?#xff0c;所以要有一個(gè)購(gòu)物車首頁(yè)。
購(gòu)物車的首頁(yè),本質(zhì)就是一個(gè)列表,這個(gè)列表所列了購(gòu)物車內(nèi)的所有商品,包含了這些商品的基本信息和購(gòu)物車的訂單總金額。
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>具體效果如下所示:
從購(gòu)物車中刪除商品
刪除購(gòu)物車中的商品也是同樣的有兩種情況
一種是讓購(gòu)物車中的商品數(shù)量減1
一種是從購(gòu)物車中直接刪掉商品,不同的是刪除的同時(shí)返回了商品的數(shù)量,這個(gè)數(shù)量用于在頁(yè)面展示。
同時(shí)還要在購(gòu)物車列表頁(yè)面添加相應(yīng)的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> }最后的話就是結(jié)算,下面進(jìn)入我們的結(jié)算操作
購(gòu)物車結(jié)算
購(gòu)物車結(jié)算,也就是提交訂單,也就是填寫(xiě)一些用戶的相關(guān)信息,比如:姓名、地址、聯(lián)系電話等等這些信息,見(jiàn)下圖。
我們?cè)贛odules文件夾中添加一個(gè)CheckOutModule.cs用來(lái)處理結(jié)算相關(guān)的功能。
要結(jié)算,必須要登錄,所以我們要首先添加需要授權(quán)的這句代碼this.RequiresAuthentication();
然后再考慮其他事情。
提交訂單的后臺(tái)操作如下:
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"]; };先是創(chuàng)建了一張訂單,這張訂單只包含了一些用戶信息。訂單創(chuàng)建好了之后才去創(chuàng)建訂單明細(xì),最后就是返回訂單完成頁(yè):
創(chuàng)建訂單明細(xì)的方法也是寫(xiě)在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; }這里做的操作主要有三個(gè):
到這里,我們的NancyMusicStore已經(jīng)是到了收尾階段。就差部署上線了啊!!
所以在下一篇,將是介紹Nancy的部署,分別在Windows和Linux下部署。
本文也已經(jīng)同步到 Nancy之大雜燴
總結(jié)
以上是生活随笔為你收集整理的Nancy简单实战之NancyMusicStore(四):实现购物车的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 梦到女婴对我笑是什么意思
- 下一篇: (转)在阿里,我们如何管理代码分支?