一步步打造简单的MVC电商网站BooksStore(1)

一步步打造一个简单的 MVC 电商网站 - BooksStore(一)

本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore

《一步步打造一个简单的 MVC 电商网站 - BooksStore(一)》

《一步步打造一个简单的 MVC 电商网站 - BooksStore(二)》

《一步步打造一个简单的 MVC 电商网站 - BooksStore(三)》

《一步步打造一个简单的 MVC 电商网站 - BooksStore(四)》

简介

主要功能与知识点如下:

分类、产品浏览、购物车、结算、CRUD(增删改查) 管理、发邮件、分页、模型绑定、认证过滤器和单元测试等(预计四篇、周五、下周一和周二)。

【备注】项目使用 VS2015 + C#6 进行开发,有问题请发表在留言区哦,还有,页面长得比较丑,请见谅。

目录

  • 创建项目架构
  • 创建域模型实体
  • 创建单元测试
  • 创建控制器与视图
  • 创建分页
  • 加入样式

一、创建项目架构

1.新建一个解决方案“BooksStore”,并添加以下项目:

BooksStore.Domain:类库,存放域模型和逻辑,使用 EF; BooksStore.WebUI:Web MVC 应用程序,存放视图和控制器,充当显示层,使用了 Ninject 作为 DI 容器; BoosStore.UnitTest:单元测试,对上述两个项目进行测试。  

Web MVC 为一个空的 MVC 项目:

2.添加项目引用(需要使用 NuGet):

这是不同项目需要引用的类库和项目

3.设置 DI 容器

我们通过 Ninject ,创建一个自定义的工厂,一个名为NinjectControllerFactory 的类继承DefaultControllerFactory(默认的控制器工厂)。你也可以在里面添加自定义的代码,改变 MVC 框架的默认行为。

AddBindings() 添加绑定方法,先留空。

public class NinjectControllerFactory : DefaultControllerFactory
 {
 private readonly IKernel _kernel;

 public NinjectControllerFactory()
 {
  _kernel = new StandardKernel();
  AddBindings();
 }

 protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
 {
  return controllerType == null
  ? null
  : (IController) _kernel.Get(controllerType);
 }

 /// <summary>
 /// 添加绑定
 /// </summary>
 private void AddBindings()
 {

 }
 }

4.并且在 Global.asax 中加入一行代码,告诉 MVC 用新建的类来创建控制器对象。

ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());

public class MvcApplication : System.Web.HttpApplication
 {
 protected void Application_Start()
 {
  AreaRegistration.RegisterAllAreas();
  RouteConfig.RegisterRoutes(RouteTable.Routes);

  ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
 }
 }

二、创建域模型实体

1.在图中位置创建一个名为 Book 的实体类。

public class Book
 {
 /// <summary>
 /// 标识
 /// </summary>
 public int Id { get; set; }

 /// <summary>
 /// 名称
 /// </summary>
 public string Name { get; set; }

 /// <summary>
 /// 描述
 /// </summary>
 public string Description { get; set; }

 /// <summary>
 /// 价格
 /// </summary>
 public decimal Price { get; set; }

 /// <summary>
 /// 分类
 /// </summary>
 public string Category { get; set; }
 }

有了实体之后,我们应该创建一个“库”对该实体进行操作,而这种持久化逻辑操作也应该和域模型是进行隔离的。

2.先定义一个接口 IbookRepository,在根目录创建一个名为 Abstract 的文件夹,顾名思义就是应该放置一些抽象的类,如接口。

public interface IBookRepository
 {
 IQueryable<Book> Books { get; }
 }

我们通过该接口就可以得到对应类的相关信息,而不需要去管该数据如何存储,以及存储的位置,这就是存储库模式的本质。

3.接下来,我们就需要对数据库进行操作了,我们使用简单的EF(ORM 对象关系模型) 去对数据库进行操作,所以需要自己通过 Nuget 下载 EF 的类库。

4.因为之前定义了接口类,接下来就应该定义实现该接口的类了

  安装完之后,再次建立一个名为 Concrete 的文件夹,存放实例。

  在里面创建一个 EfDbContext 的类,派生于 DbContext,该类会为用户要使用的数据库中的每个表自动的定义一个属性。该属性名为 Books,指定了表名,DbSet<Book> 表示为 Book 实体的表模型,Book 对象相当于 Books 表中的行(记录)。

 public class EfDbContext : DbContext
 {
 public DbSet<Book> Books { get; set; }
 }

  再创建一个EfBookRepository 存储库类,它实现 IBookRepository 接口,使用了上文创建的 EfDbContext 上下文对象,包含了具体的方法定义。

public class EfBookRepository : IBookRepository
 {
 private readonly EfDbContext _context = new EfDbContext();

 public IQueryable<Book> Books => _context.Books;
 }

5.现在只差在数据库新建一张表了。

CREATE TABLE Book
(
 Id INT IDENTITY PRIMARY KEY,
 Name NVARCHAR(100),
 Description NVARCHAR(MAX),
 Price DECIMAL,
 Category NVARCHAR(50)
)

并插入测试数据:

INSERT INTO dbo.Book
 (
  Name ,
  Description ,
  Price ,
  Category
 )
VALUES (
  N'C#从入门到精通' , -- Name - nvarchar(100)
  N'好书-C#从入门到精通' , -- Description - nvarchar(max)
, -- Price - decimal
  N'.NET' -- Category - nvarchar(50)
 )

INSERT INTO dbo.Book
 (
  Name ,
  Description ,
  Price ,
  Category
 )
VALUES (
  N'ASP.NET从入门到精通' , -- Name - nvarchar(100)
  N'好书-ASP.NET从入门到精通' , -- Description - nvarchar(max)
, -- Price - decimal
  N'.NET' -- Category - nvarchar(50)
 )

INSERT INTO dbo.Book
 (
  Name ,
  Description ,
  Price ,
  Category
 )
VALUES (
  N'多线程从入门到精通' , -- Name - nvarchar(100)
  N'好书-多线程从入门到精通' , -- Description - nvarchar(max)
, -- Price - decimal
  N'.NET' -- Category - nvarchar(50)
 )

INSERT INTO dbo.Book
 (
  Name ,
  Description ,
  Price ,
  Category
 )
VALUES (
  N'java从入门到放弃' , -- Name - nvarchar(100)
  N'好书-java从入门到放弃' , -- Description - nvarchar(max)
, -- Price - decimal
  N'java' -- Category - nvarchar(50)
 )

INSERT INTO dbo.Book
 (
  Name ,
  Description ,
  Price ,
  Category
 )
VALUES (
  N'sql从入门到放弃' , -- Name - nvarchar(100)
  N'好书-sql从入门到放弃' , -- Description - nvarchar(max)
, -- Price - decimal
  N'sql' -- Category - nvarchar(50)
 )

INSERT INTO dbo.Book
 (
  Name ,
  Description ,
  Price ,
  Category
 )
VALUES (
  N'sql从入门到出家' , -- Name - nvarchar(100)
  N'好书-sql从入门到出家' , -- Description - nvarchar(max)
, -- Price - decimal
  N'sql' -- Category - nvarchar(50)
 )

INSERT INTO dbo.Book
 (
  Name ,
  Description ,
  Price ,
  Category
 )
VALUES (
  N'php从入门到出家' , -- Name - nvarchar(100)
  N'好书-php从入门到出家' , -- Description - nvarchar(max)
, -- Price - decimal
  N'php' -- Category - nvarchar(50)
 )

测试数据

因为我希望表名为 Book,而不是 Books,所以我在之前的 Book 类上加上特性 [Table("Book")]:

三、创建单元测试

1.做完预热操作后,你可能想立即以界面的的方式进行显示,别急,先用单元测试检查一下我们对数据库的操作是否正常,通过对数据进行简单的读取,检查下连接是否成功。

2.单元测试也需要引入 ef 类库(Nuget)。

3.安装完之后会生成一个 app.config 配置文件,需要额外添加一行连接字符串(在后续的 Web UI 项目里,也需要加上这条信息,不然会提示对应的错误信息)。

<connectionStrings>
 <add name="EfDbContext" connectionString="server=.;database=TestDb;uid=sa;pwd=123" providerName="System.Data.SqlClient"/>
 </connectionStrings>

4.当所有前置工作都准备好了的时候,就应该填写测试方法了,因为我插入了 7 条数据,这里我就判断一下从数据库读取出的行数是否为 7 :

[TestMethod]
 public void BooksCountTest()
 {
  var bookRepository=new EfBookRepository();
  var books = bookRepository.Books;

  Assert.AreEqual(books.Count(),7);
 }

5.在该方法体的内部单击右键,你可以看到一个“运行测试”的选项,这时你可以尝试单击它:

从这个符号可以看到,是成功了!

接下来,我们要正式从页面显示我们想要的信息了。

四、创建控制器与视图 

1.先新建一个空的控制器:BookController:

2.需要我们自定义一个 Details 方法,用于后续与界面进行交互。

public class BookController : Controller
 {
 private readonly IBookRepository _bookRepository;

 public BookController(IBookRepository bookRepository)
 {
  _bookRepository = bookRepository;
 }

 /// <summary>
 /// 详情
 /// </summary>
 /// <returns></returns>
 public ActionResult Details()
 {
  return View(_bookRepository.Books);
 }
 }

3.接下来,要创建一个视图 View 了。

4.将 Details.cshtml 的内容替换为下面的:

@model IEnumerable<Wen.BooksStore.Domain.Entities.Book>

@{
 ViewBag.Title = "Books";
}

@foreach (var item in Model)
{
 <div>
 <h3>@item.Name</h3>
 @item.Description
 <h4>@item.Price.ToString("C")</h4>
 <br />
 <hr />
 </div>
}

5.改下默认的路由机制,让他默认跳转到该页面。

6.还有一点需要注意的是,因为我们使用了 Ninject 容器,并且需要对控制器中的构造函数中的参数IBookRepository 进行解析,告诉他将使用哪个对象对该接口进行服务,也就是需要修改之前的 AddBindings 方法:

7.运行的效果大致如下(因为加了点 CSS 样式,所以显示的效果可能有些许不同),结果是一致的。

五、创建分页

1.在 Models 文件夹新增一个 PagingInfo.cs 分页信息类。

/// <summary>
 /// 分页信息
 /// </summary>
 public class PagingInfo
 {
 /// <summary>
 /// 总数
 /// </summary>
 public int TotalItems { get; set; }

 /// <summary>
 /// 页容量
 /// </summary>
 public int PageSize { get; set; }

 /// <summary>
 /// 当前页
 /// </summary>
 public int PageIndex { get; set; }

 /// <summary>
 /// 总页数
 /// </summary>
 public int TotalPages => (int)Math.Ceiling((decimal)TotalItems / PageSize);
 }

2.新增一个 HtmlHelpers 文件夹存放一个基于 Html 帮助类的扩展方法:

public static class PagingHelper
 {
 /// <summary>
 /// 分页
 /// </summary>
 /// <param name="helper"></param>
 /// <param name="pagingInfo"></param>
 /// <param name="func"></param>
 /// <returns></returns>
 public static MvcHtmlString PageLinks(this HtmlHelper helper, PagingInfo pagingInfo, Func<int, string> func)
 {
  var sb = new StringBuilder();
  for (var i = 1; i <= pagingInfo.TotalPages; i++)
  {
  //创建 <a> 标签
  var tagBuilder = new TagBuilder("a");
  //添加特性
  tagBuilder.MergeAttribute("href", func(i));
  //添加值
  tagBuilder.InnerHtml = i.ToString();

  if (i == pagingInfo.PageIndex)
  {
   tagBuilder.AddCssClass("selected");
  }

  sb.Append(tagBuilder);
  }

  return MvcHtmlString.Create(sb.ToString());
 }
 }

3.添加完毕后需要在配置文件内加入该命名空间

4.现在要重新修改BookController.cs 控制器内的的代码,并添加新的视图模型类BookDetailsViewModels.cs,让它继承之前的分页类。

public class BookDetailsViewModels : PagingInfo
 {
 public IEnumerable<Book> Books { get; set; }
 }

修改后的控制器代码:

public class BookController : Controller
 {
 private readonly IBookRepository _bookRepository;
 public int PageSize = 5;

 public BookController(IBookRepository bookRepository)
 {
  _bookRepository = bookRepository;
 }

 /// <summary>
 /// 详情
 /// </summary>
 /// <param name="pageIndex"></param>
 /// <returns></returns>
 public ActionResult Details(int pageIndex = 1)
 {
  var model = new BookDetailsViewModels()
  {
  Books = _bookRepository.Books.OrderBy(x => x.Id).Skip((pageIndex - 1) * PageSize).Take(PageSize),
  PageSize = PageSize,
  PageIndex = pageIndex,
  TotalItems = _bookRepository.Books.Count()
  };

  return View(model);
 }
 }

5.修改视图模型后,对应的视图页也需要修改

@model Wen.BooksStore.WebUI.Models.BookDetailsViewModels

@{
 ViewBag.Title = "Books";
}

@foreach (var item in Model.Books)
{
 <div>
 <h3>@item.Name</h3>
 @item.Description
 <h4>@item.Price.ToString("C")</h4>
 <br />
 <hr />
 </div>
}

<div class="pager">
 @Html.PageLinks(Model, x => Url.Action("Details", new { pageIndex = x }))
</div>

六、加入样式

1.页面的样式简单的设计为 3 大板块,顶部为标题,左侧边栏为分类,主模块将显示具体内容。

我们现在要在 Views 文件夹下创建一个文件 _ViewStart.cshtml,再创建一个 Shared 的文件夹和文件 _Layout.cshtml。

2._Layout.cshtml 这是布局页,当代码执行到 @RenderBody() 时,就会负责将之前 Details.cshtml 的内容进行渲染:

<!DOCTYPE html>

<html>
<head>
 <meta name="viewport" content="width=device-width" />
 <title>@ViewBag.Title</title>
 <link href="~/Contents/Site.css" rel="stylesheet" />
</head>
<body>
 <div id="header">
 <div class="title">图书商城</div>
 </div>
 <div id="sideBar">分类</div>
 <div id="content">
 @RenderBody()
 </div>
</body>
</html>

_ViewStart.cshtml 该文件表示默认的布局页为该视图文件:

@{
 Layout = "~/Views/Shared/_Layout.cshtml";
}

3.网站的根目录下也要添加一个名为 Contents 的文件夹,用于存放 CSS。

body {
}

#header, #content, #sideBar {
 display: block;
}

#header {
 background-color: green;
 border-bottom: 2px solid #111;
 color: White;
}

#header, .title {
 font-size: 1.5em;
 padding: .5em;
}

#sideBar {
 float: left;
 width: 8em;
 padding: .3em;
}

#content {
 border-left: 2px solid gray;
 margin-left: 10em;
 padding: 1em;
}

.pager {
 text-align: right;
 padding: .5em 0 0 0;
 margin-top: 1em;
}

 .pager A {
 font-size: 1.1em;
 color: #666;
 padding: 0 .4em 0 .4em;
 }

 .pager A:hover {
  background-color: Silver;
 }

 .pager A.selected {
  background-color: #353535;
  color: White;
 }

现在,分页也已经有了效果,基本界面就出来了。

本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • MVC+EasyUI+三层新闻网站建立 验证码生成(三)

    我们在项目中的NewWeb.Common类库里面建立一个类用来存放生成验证码的代码. 这里我类的名字叫 ValidateCode 生成验证码(ValidateCode)类的代码: using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; using Syste

  • MVC+EasyUI+三层新闻网站建立 主页布局的方法(五)

    MVC新闻网站建立,实现主页布局. 首先建立Home控制器,然后再建立Index视图. 和前面登录页面一样也需要引入几个文件. 接着就是找到你下载的easyui文件夹里面的demo里面的layout里面的full 浏览器运行后右键查看代码把里面的body里面的代码复制到Index视图的body里面去.没找到的可以直接复制下面的代码. <body class="easyui-layout"> <div data-options="region:'north',

  • MVC+EasyUI+三层新闻网站建立 实现登录功能(四)

    MVC新闻网站建立,实现登录功能 首先在数据库中建立一张UserInfo表. 注:以下讲的这些可以用动软代码生成器直接生成,但是对于新手来说还是动手敲一下的好,了解以下实现的过程. 然后在Model中建立UserInfo的实体层. public class UserInfo { public int Id { get; set; } public string UserName { get; set; } public string UserPwd { get; set; } public st

  • MVC+EasyUI+三层新闻网站建立 后台登录界面的搭建(二)

    新闻网站建立,后台登录界面的搭建 首先我们在Controllers里面新添加一个控制器就叫LoginController,右键点击Controllers添加控制器就可以了(注意后面一定是Controller结尾,这是一种约定) 其次:右键点击index建立Index视图.(不选择使用母版页) 现在我们就可以在Index视图中设计我们的登录页面了. 这里需要我们引入几个Css样式和JS文件 简单的进行登录界面的布局 <html> <head> <meta name="

  • MVC4制作网站教程第四章 添加栏目4.1

    好几天没时间写了.今天有写时间在学一点. 今天状态也不是很好,晕晕沉沉的写吧. 序 一.用户 二.用户组 三.栏目 3.1添加栏目 首先添加[CategoryController]控制器, 那么我想我的视图里,首先显示的应该是栏目类型,这里应该是一个下拉框,用户可以选择"一般栏目","单页栏目","外部链接".那么首先应该在[CategoryController]添加一个属性,用来返回栏目类型列表. #region Attribute publi

  • MVC+EasyUI+三层新闻网站建立 建站准备工作(一)

    这一次的项目是建立一个小型的新闻发布网站,所以就不需要用一些高大上的框架.三层+MVC+easyUI就足够了. 首先:搭建起项目框架 其次:到easyui官网去下载easyUI 我这里用的是我在很久的项目中用过的版本jquery-easyui-1.5.2 下载链接:http://www.jeasyui.com/download/list.php 最后就是把easyui引入到项目中去. 现在Content文件夹下建立一个叫EasyUi的文件夹,把需要用到的文件复制到其中,具体如下图所示: 以上就是

  • MVC4制作网站教程第四章 浏览栏目4.2

    序 一.用户 二.用户组 三.栏目 3.1添加栏目 3.2浏览栏目 浏览栏目这块做个一个树形列表,添加栏目的左侧部分只写了句"左侧列表"就是指这个树形列表,等我们写完替换一下就可以了. 先在[CategoryController]里面添加[ManagePartialTree]action,这里的Partial用来说明是分部视图 /// <summary> /// 栏目列表局部树视图 /// </summary> /// <returns></r

  • MVC4制作网站教程第四章 更新栏目4.3

    序  一.用户  二.用户组  三.栏目 3.1添加栏目 3.2浏览栏目  3.3更新栏目 上次在树形列表里面点击栏目名称后跳转到详细信息页面~/Category/ManageDetails/id.在详细页面里点修改,来完成栏目资料修改. 先打开[CategoryController]添加[ManageDetails(int id)]action /// <summary> /// 栏目详细资料 /// </summary> /// <param name="id&

  • MVC+EasyUI+三层新闻网站建立 tabs标签制作方法(六)

    MVC新闻网站建立,完成tabs标签的制作. 首先对 Center 进行一个简单的布局 <!--------------中间布局开始----------------> <div data-options="region:'center',title:'Center'" > <div class="easyui-tabs" style="width:700px;height:250px" fit="true&

  • 一步步打造简单的MVC电商网站BooksStore(2)

    一步步打造一个简单的 MVC 电商网站 - BooksStore(二) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore <一步步打造一个简单的 MVC 电商网站 - BooksStore(一)> <一步步打造一个简单的 MVC 电商网站 - BooksStore(二)> <一步步打造一个简单的 MVC 电商网站 - BooksStore(三)> <一步步打造一个简单的 MVC 电商网站 -

随机推荐