MVC项目实践,在三层架构下实现SportsStore-06,实现购物车
2014-06-28 10:55
417 查看
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个因素综合起来封装成一个基本单元:
而购物车帮助类的主要工作就是针对这个CartLine集合的各种处理:添加、移除、计算总价、清空等。
8.2 添加"放入购物车"按钮
在显示产品的部分视图中,添加"放入购物车"按钮,把Produect的Id和当前页的URL作为隐藏域传递给控制器方法:
在即将创建的Cart控制器方法中,肯定要用到Cart类的实例,而该实例将贯穿于页面之间,所以应该存放于Session中。首先想到的是通过如下方式获取Cart类的实例:
也可以自定义一个ModelBinder,使之从Session中获取Cart类的实例:
在全局文件Global.asax中把自定义的ModelBinder注册到MVC中:
有了如上铺垫,在Cart控制器的方法中参数中,可以有一个类型为Cart的参数,该参数值直接从自定义的CartModelBinder中获取:
运行:
显示购物车内容 添加"移除"按钮
在显示购物车内容视图页,除了要把购物车内容呈现,在其对应的视图模型中还必须有一个属性,用来存放先前的URL,然后点击页面的"继续购物"按钮,方才可以回到先前的界面。
显示购物车内容视图页的View Model为:
Cart/Index.cshtml视图:
运行:
8.4 显示购物车摘要
购物车摘要通常放在页面的公共部分,用来显示买了多少件商品,花了多少钱,并提供一个指向购物车显示页的链接,以部分视图的形式存在:
然后把这块部分视图放到页面的公共部分,即Views/Shared/_Layout.cshtml中:
运行:
至此,购物车功能结束。
源码在这里。
“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-05,实现导航
- MVC项目实践,在三层架构下实现SportsStore-07,实现订单提交
- MVC项目实践,在三层架构下实现SportsStore-01,EF Code First建模、DAL层等
- MVC项目实践,在三层架构下实现SportsStore-02,DbSession层、BLL层
- MVC项目实践,在三层架构下实现SportsStore-04,实现分页
- MVC项目实践,在三层架构下实现SportsStore-09,ASP.NET MVC调用ASP.NET Web API的查询服务
- MVC项目实践,在三层架构下实现SportsStore,从类图看三层架构
- MVC项目实践,在三层架构下实现SportsStore-03,Ninject控制器工厂等
- MVC项目实践,在三层架构下实现SportsStore-10,连接字符串的加密和解密
- MVC项目实践,在三层架构下实现SportsStore-03,Ninject控制器工厂等
- MVC项目实践,在三层架构下实现SportsStore-11,使用Knockout实现增删改查
- MVC项目实践,在三层架构下实现SportsStore-01,EF Code First建模、DAL层等
- MVC项目实践,在三层架构下实现SportsStore-08,部署到IIS服务器
- 三层架构模式(MVC)案例:购物车实现
- asp.net mvc中自行搭建实现工厂模式的spring.net+三层架构 (15-4-20)
- MVC架构 项目实践
- Spring Boot / Spring MVC 入门实践 (三) : 入门项目介绍与用户注册登录的实现
- 基于MVC和三层架构,用jsp-Servlet-JavaBean实现登录和注册
- 应用node.js+mongodb数据库实现一个mvc架构的web项目
- 三层架构(MVC)实现简单登陆注册验证(含验证码)