SportsStore是《精通ASP.NET MVC3框架(第三版)》中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器、URL优化、导航、分页、购物车、订单、产品管理、图像上传......是不错的MVC实践项目,但该项目不是放在多层框架下开发的,离真实项目还有一段距离。本系列将尝试在多层框架下实现SportsStore项目,并用自己的方式实现一些功能。

本篇为系列第六篇,包括:

■ 8、购物车
    □ 8.1 购物车模型 购物车帮助类
    □ 8.2 添加"放入购物车"按钮
    □ 8.3 显示购物车内容 添加"移除"按钮
    □ 8.4 显示购物车摘要

8、购物车

8.1 购物车模型 购物车帮助类

从逻辑上讲,购物车帮助类不仅仅是针对Product的处理,还需考虑每种Product的数量。我们把这2个因素综合起来封装成一个基本单元:

public class CartLine{public Product Product { get; set; }public int Quantity { get; set; }}

而购物车帮助类的主要工作就是针对这个CartLine集合的各种处理:添加、移除、计算总价、清空等。

using System.Collections.Generic;
using System.Linq;
using MySportsStore.Model;namespace MySportsStore.WebUI.Models
{public class Cart{private List<CartLine> lineCollection = new List<CartLine>();//添加public void AddItem(Product product, int quantity){CartLine line = lineCollection.Where(p => p.Product.Id == product.Id).FirstOrDefault();if (line == null){lineCollection.Add(new CartLine(){Product = product, Quantity = quantity});}else{line.Quantity += quantity;}}//移除public void RemoveLine(Product product){lineCollection.RemoveAll(p => p.Product.Id == product.Id);}//计算总价public decimal ComputeTotalValue(){return lineCollection.Sum(p => p.Product.Price*p.Quantity);}//清空public void Clear(){lineCollection.Clear();}//获取public IEnumerable<CartLine> Lines{get { return lineCollection; }}}
}

8.2 添加"放入购物车"按钮

在显示产品的部分视图中,添加"放入购物车"按钮,把Produect的Id和当前页的URL作为隐藏域传递给控制器方法:

@model MySportsStore.Model.Product<div class="item"><h3>@Model.Name</h3>@Model.Description@using (Html.BeginForm("AddToCart", "Cart")){@Html.HiddenFor(p => p.Id)@Html.Hidden("returnUrl", Request.Url.PathAndQuery)<input type="submit" value="+放入购物车"/>}<h4>@Model.Price.ToString("c")</h4>
</div>

在即将创建的Cart控制器方法中,肯定要用到Cart类的实例,而该实例将贯穿于页面之间,所以应该存放于Session中。首先想到的是通过如下方式获取Cart类的实例:

private Cart GetCart(){Cart cart = (Cart)Session["Cart"];if (cart == null){cart = new Cart();Session["Cart"] = cart;}return cart;}

也可以自定义一个ModelBinder,使之从Session中获取Cart类的实例:

using System.Web.Mvc;
using MySportsStore.WebUI.Models;namespace MySportsStore.WebUI.Extension
{public class CartModelBinder : IModelBinder{private const string sessionKey = "Cart";public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext){Cart cart = (Cart)controllerContext.HttpContext.Session[sessionKey];if (cart == null){cart = new Cart();controllerContext.HttpContext.Session[sessionKey] = cart;}return cart;}}
}

在全局文件Global.asax中把自定义的ModelBinder注册到MVC中:

protected void Application_Start(){......ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());ModelBinders.Binders.Add(typeof(Cart), new CartModelBinder());}

有了如上铺垫,在Cart控制器的方法中参数中,可以有一个类型为Cart的参数,该参数值直接从自定义的CartModelBinder中获取:

using System.Linq;
using System.Web.Mvc;
using MySportsStore.IBLL;
using MySportsStore.Model;
using MySportsStore.WebUI.Models;
using Ninject;namespace MySportsStore.WebUI.Controllers
{public class CartController : BaseController{[Inject]public IProductService ProductService { get; set; }public CartController(){this.AddDisposableObject(ProductService);}public ActionResult Index(Cart cart, string returnUrl){return View(new CartIndexViewModel{//Cart = GetCart(),Cart = cart,ReturnUrl = returnUrl});}//添加到购物车public RedirectToRouteResult AddToCart(Cart cart, int Id, string returnUrl){Product product = ProductService.LoadEntities(p => p.Id == Id).FirstOrDefault();if (product != null){//GetCart().AddItem(product, 1);cart.AddItem(product, 1);}return RedirectToAction("Index", new {returnUrl});}//从购物车移除public RedirectToRouteResult RemoveFromCart(Cart cart, int Id, string returnUrl){Product product = ProductService.LoadEntities(p => p.Id == Id).FirstOrDefault();if (product != null){//GetCart().RemoveLine(product);
                cart.RemoveLine(product);}return RedirectToAction("Index", new {returnUrl});}public ViewResult Summary(Cart cart){return View(cart);}private Cart GetCart(){Cart cart = (Cart)Session["Cart"];if (cart == null){cart = new Cart();Session["Cart"] = cart;}return cart;}}
}

运行:

显示购物车内容 添加"移除"按钮

在显示购物车内容视图页,除了要把购物车内容呈现,在其对应的视图模型中还必须有一个属性,用来存放先前的URL,然后点击页面的"继续购物"按钮,方才可以回到先前的界面。

显示购物车内容视图页的View Model为:

namespace MySportsStore.WebUI.Models
{public class CartIndexViewModel{public Cart Cart { get; set; }public string ReturnUrl { get; set; }}
}

Cart/Index.cshtml视图:

@model MySportsStore.WebUI.Models.CartIndexViewModel@{ViewBag.Title = "Index";Layout = "~/Views/Shared/_Layout.cshtml";
}<table width="50%" align="left"><thead><tr><th align="left">产品名称</th><th align="center">数量</th>          <th align="right">单价</th><th align="right">小计</th><th></th></tr></thead><tbody>@foreach (var line in Model.Cart.Lines){<tr><td align="left">@line.Product.Name</td><td align="center">@line.Quantity</td><td align="right">@line.Product.Price.ToString("c")</td><td align="right">@((line.Quantity * line.Product.Price).ToString("c"))</td><td>@using (Html.BeginForm("RemoveFromCart", "Cart")){@Html.Hidden("Id", line.Product.Id)@Html.HiddenFor(x => x.ReturnUrl)<input class="actionButtons" type="submit" value="移除"/>}</td></tr>}</tbody><tfoot><tr><td colspan="3" align="right">总计:</td><td align="right">@Model.Cart.ComputeTotalValue().ToString("c")</td></tr></tfoot>
</table>
<p align="left" class="actionButtons" style="width: 100%;clear: both"><a href="@Model.ReturnUrl">继续购物</a>
</p>

运行:

8.4 显示购物车摘要

购物车摘要通常放在页面的公共部分,用来显示买了多少件商品,花了多少钱,并提供一个指向购物车显示页的链接,以部分视图的形式存在:

@model MySportsStore.WebUI.Models.Cart@{Layout = null;
}<div id="cart"><span class="caption"><b>购物车明细:</b>@Model.Lines.Sum(x => x.Quantity) 件,@Model.ComputeTotalValue().ToString("c")</span>@Html.ActionLink("结算", "Index", "Cart", new {returnUrl = Request.Url.PathAndQuery}, null)
</div>

然后把这块部分视图放到页面的公共部分,即Views/Shared/_Layout.cshtml中:

<!DOCTYPE html>
<html>
<head><meta charset="utf-8" /><meta name="viewport" content="width=device-width" /><title>@ViewBag.Title</title><link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
</head><body><div id="header" style="height: 200px;">@{Html.RenderAction("Summary", "Cart");}<div class="title">体育用品商店</div></div><div id="categories">@{Html.RenderAction("Menu","Nav");}</div><div id="content">@RenderBody()</div>@Scripts.Render("~/bundles/jquery")@RenderSection("scripts", required: false)</body>
</html>

运行:

至此,购物车功能结束。

源码在这里。

“MVC项目实践,在三层架构下实现SportsStore”系列包括:

MVC项目实践,在三层架构下实现SportsStore,从类图看三层架构

MVC项目实践,在三层架构下实现SportsStore-01,EF Code First建模、DAL层等

MVC项目实践,在三层架构下实现SportsStore-02,DbSession层、BLL层

MVC项目实践,在三层架构下实现SportsStore-03,Ninject控制器工厂等

MVC项目实践,在三层架构下实现SportsStore-04,实现分页

MVC项目实践,在三层架构下实现SportsStore-05,实现导航

MVC项目实践,在三层架构下实现SportsStore-06,实现购物车

MVC项目实践,在三层架构下实现SportsStore-07,实现订单提交

MVC项目实践,在三层架构下实现SportsStore-08,部署到IIS服务器

MVC项目实践,在三层架构下实现SportsStore-09,ASP.NET MVC调用ASP.NET Web API的查询服务

MVC项目实践,在三层架构下实现SportsStore-10,连接字符串的加密和解密

MVC项目实践,在三层架构下实现SportsStore-11,使用Knockout实现增删改查

MVC项目实践,在三层架构下实现SportsStore-06,实现购物车相关推荐

  1. MVC项目实践,在三层架构下实现SportsStore-03,Ninject控制器工厂等

    SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...

  2. MVC项目实践,在三层架构下实现SportsStore-01,EF Code First建模、DAL层等

    SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...

  3. CS通用项目系统搭建——三层架构第一天

    CS通用项目:使用三层架构进行搭建 三层架构: 表现层(UI(User Interface)):展示给用户的层面,包含窗体控件数据等信息. 业务逻辑层(BLL(Business Logic Layer ...

  4. java三层架构项目事例_三层架构实例

    一.概要 在我的上一篇博客中,我们谈了谈分层,到底为什么分层(http://blog.csdn.net/shan9liang/article/details/6836300) 这篇博客,准备用一个小D ...

  5. Javaweb MVC设计模式、Modle发展史、项目分层和三层架构

    文章目录 MVC设计模式 MVC的目的 MVC举例 jsp+servlet+javabean模式 MVC的优点 MVC的缺点 Modle 发展史 项目分层 三层架构 MVC设计模式 MVC模式(Mod ...

  6. 什么是MVC?什么是三层架构?

    什么是MVC MVC是模型(Model).视图(View).控制器(Controller)的简写,是一种软件设计规范. 是将业务逻辑.数据.显示分离的方法来组织代码. MVC主要作用是降低了视图与业务 ...

  7. SSM框架实战详细教程(十四)贯穿项目实战之三层架构

    之前我们的项目足够简单,所以使用的是两层架构,现在为了学习Spring,需要使用行业中常见的三层架构,关于分层开发的原则请看下图:         本次对项目的调整,主要是由之前的controller ...

  8. 三层架构下,优酷视频搜索测试体系很复杂吗?

    作者| 阿里文娱测试开发专家 熙闫 责编 | 夕颜 简介 优酷搜索承担着内容分发场的头部兵的重任,海量的视频内容都要依赖搜索触达和呈现给 用户,而且逐渐扩大范围,开始向阿里文娱全系产品提供搜索服务和能 ...

  9. unity 项目实践经验 和 架构体系

    GameRes游资网授权发布 文 / 吴秦(Tyler) 本次分享总结,起源于腾讯桌球项目,但是不仅仅限于项目本身.虽然基于Unity3D,很多东西同样适用于Cocos.本文从以下10大点进行阐述: ...

最新文章

  1. 在Centos8 中使用Stratis管理本地存储(一)
  2. 数学之美——统计语言模型
  3. HDU4825 Xor Sum —— Trie树
  4. (04741)计算机网络原理,04741计算机网络原理真题_成都英才教育网
  5. 数据产品经理:埋点的设计、管理与应用
  6. 操作系统锁的实现方法有哪几种_「从入门到放弃-Java」并发编程-锁-synchronized...
  7. HTML笔记——bootstrap-select、table、tableExport、layer
  8. [leetcode]5355. T 秒后青蛙的位置
  9. python setup.py install没反应_花了两天,终于把 Python 的 setup.py 给整明白了
  10. 天啦,这才是英国退欧的真相!
  11. 微信公众平台与微信公众平台的区别与联系
  12. 西安交大计算机专业考研复试,2018西安交通大学计算机考研复试分数线_计算机考研分数线...
  13. windows自动开关机教程
  14. mac_m4a转mp3
  15. UCOSIII实时操作系统------软件定时器
  16. APP地推的一些经验
  17. 基于回旋曲线的平行泊车路径规划
  18. [CTF]2021长安战疫 WP
  19. 图像增强系列之图像自动去暗角算法
  20. #9733;一名“标题党”自我修炼的10…

热门文章

  1. 使用mcisendstring重复播放音乐文件
  2. 数字信号处理6:IIR滤波器设计
  3. android shell强制删除文件夹_原来手机中的这些文件可以删除,难怪手机越用越卡!...
  4. mysql变量包括什么意思_什么是mysql变量?
  5. python循环语句for 循环十次_python循环语句for的使用方式,又快又好
  6. 无效的wechatwin.dll文件errcode:126,点击“确定”下载最新版本
  7. echarts vue 柱状图实例_「源码学习」适用于 Vue3 的 ECharts 包装组件
  8. Git Tag及使用
  9. java dns 解析域名解析_java网络学习 java dns 域名解析协议实现
  10. Python 项目中requirements.txt依赖文件的使用