2019独角兽企业重金招聘Python工程师标准>>>
电子商务网站(C#版)
通过一个在线的电子商务网站(网上书店销售系统)的实例,来讲述如何采用ASP.NET 3.5+SQL Server 2010的模式定制一个小型的电子商务平台。系统采用了模块化的设计方法,根据用户的需求及程序的应用与维护的易用性,将系统各个部分置于不同的模块当中,方便了程序的扩展与维护,同时建立了程序功能复用的基础。
本章介绍的系统–网上书店销售平台属于B2C电子商务网站,它能够绕过中介(如批发商、销售商或经销商)建立与客户的直接关系。该网站可以为用户提供商品(书籍)的详细信息,支持用户在线购买商品(书籍),并提交自己的订单。同时,用户可以提交商品评论和网站建议。网上书店销售平台使购买书籍变得更方便、更容易。
通过学习,读者还可以完成网上手机销售系统、网上音像店、在线首饰、网上购物等类似系统的设计。
通过阅读,读者可以学习到:
购物车的实现机制。
LINQ查询技术。
数据库操作的O/R映射机制。
网站中的搜索技术。
实现GridView控件的多种应用。
系统总体设计
本章设计的是一个简单的网上书店销售系统,使用ASP.NET 3.5技术开发,结构是浏览器/服务器(B/S)的网络数据库应用系统。 需求分析
网上书店销售平台是一个完整的B2C电子商务网站。在本系统中,主要包括用户登录和注册功能、图书搜索功能、书籍信息管理功能、新书推荐和本站新闻模块、用户留言功能、购物车和订单管理功能等。
用户登录和注册功能:包括用户登录和注册,管理员登录和用户管理等。
图书搜索功能:通过图书类别搜索图书。
书籍信息管理功能:包括所有书籍的浏览和单本图书详细信息的浏览等。如果是管理员,还可在后台对书籍进行添加、修改、删除等操作。
新书推荐和本站新闻模块:首页的两大功能,支持管理员在后台编辑这两项功能。
用户留言功能:用于用户与管理员的交互,当用户需要某本书但网站中没有时,用户可以通过留言告诉管理员。用户有什么好的提议,也可以用此方法告诉管理员。管理员可以在后台对用户留言进行浏览、编辑和删除。
购物车和订单管理功能:当用户选择书籍后,可放入购物车,然后通过订单管理功能实现最终付款。购物车和订单管理功能主要包括添加书籍到购物车、浏览购物车中的书籍,以及提交订单。如果是管理员,还可在后台查看用户的订单。
系统功能结构
按照本网站的系统功能设计,可以把系统划分为用户管理模块、用户搜索模块、书籍信息管理模块、新书推荐与本站新闻模块、用户留言模块以及购物车和订单管理模块。系统功能如图
构建开发环境
前面提到过本系统使用ASP.NET 3.5构建B/S系统的项目。ASP.NET 3.5是基础.NET 3.5框架上的Web应用开发技术,其开发工具是VS 2008,所以本例要用到的开发工具及数据库如下:
基于.NET Framework 3.5版的Visual Studio 2010。
Microsoft SQL Server 2010数据库。
数据库操作使用LINQ技术。
系统预览
系统最大的特点是分为普通用户和管理员两个操作入口,默认登录页是Default.aspx,在浏览器中的效果如图11.2所示。首页会显示网站的新闻和新书推荐,默认只推荐一本新书。用户可以通过单击图书名链接打开图书的详细信息页面,如图
说明:网站最上面的一行菜单,使用Menu控件完成,起到网站的导航作用,一般称为导航菜单。
如果是用户登录,直接在导航菜单下的用户名和密码处输入注册信息,单击"登录"按钮就可以登录。如果是新用户,则单击"注册"链接,转到注册页面,注册时需要填写如图11.4所示的各个字段。如果是管理员登录,则需要单击导航菜单栏中的"管理员登录"链接,打开管理员登录界面,如图11.5所示。登录后的效果与普通用户显示的界面不同,仔细查看它的导航菜单,如图
系统数据库设计
数据库用来存储和管理网上书店销售平台所需的数据,对整个系统的实现起着极其重要的作用。下面介绍一下系统数据库的设计。
数据表设计(1)
考虑网上书店销售平台的实际需要,本系统至少需要的数据包括用户数据、书籍数据、用户留言、订单数据、新书推荐。
(1)用户表(UserInfo):用来存储用户的数据,如用户ID、用户名、用户密码、用户地址、E-mail等。表的字段说明如表11.1所示。
表1 用户表(UserInfo)
字段名称 |
数据类型 |
字段大小 |
是否主键 |
是否为空 |
说明 |
UserName |
nchar |
50 |
是 |
否 |
用户ID |
Name |
nchar |
50 |
否 |
是 |
用户名 |
Password |
nchar |
30 |
否 |
是 |
用户密码 |
|
nchar |
50 |
否 |
是 |
电子邮件 |
Address |
nchar |
50 |
否 |
是 |
地址 |
DateTime |
DateTime |
N/A |
否 |
是 |
注册时间 |
(2)图书信息表(BookInfo):用来存储图书信息,如用图书名、图书ID、图书价格、图书出版社等。字段说明如表11.2所示。
表2 图书信息表(BookInfo)
字段名称 |
数据类型 |
字段大小 |
是否主键 |
是否为空 |
说明 |
BookID |
nchar |
30 |
是 |
否 |
书籍ID |
BookName |
nchar |
30 |
否 |
是 |
书籍名 |
BookAddress |
nchar |
30 |
否 |
是 |
出版社 |
BookPrice |
int |
N/A |
否 |
是 |
价格 |
BookDate |
DateTime |
N/A |
否 |
是 |
出版日期 |
BookPeople |
nchar |
30 |
否 |
是 |
作者 |
BookSay |
nchar |
300 |
否 |
是 |
对书籍的简介 |
BookPhoto |
nchar |
50 |
否 |
是 |
图书的封面 |
数据表设计(2)
(3)新书推荐表(NewBook):用来存储推荐图书的图书名、图书ID、图书价格等。字段说明如表11.3所示。
表3 新书推荐表(NewBook)
字段名称 |
数据类型 |
字段大小 |
是否主键 |
是否为空 |
说明 |
NewBookID |
int |
N/A |
是 |
否 |
新书ID |
BookID |
nchar |
30 |
否 |
是 |
与书ID关联 |
NewBookName |
nchar |
50 |
否 |
是 |
新书名 |
NewBookSay |
nchar |
300 |
否 |
是 |
新书描述 |
NewBookPhoto |
nchar |
50 |
否 |
是 |
新书封面 |
(4)图书订单表BookOrder:用来存储用户购买图书的图书名,图书价格,图书数量,订单用户的姓名等,字段说明如表11.4所示。
表4 图书订单表(BookOrder)
字段名称 |
数据类型 |
字段大小 |
是否主键 |
是否为空 |
说明 |
OrderID |
int |
N/A |
是 |
否 |
订单ID |
BookName |
nchar |
50 |
否 |
是 |
书籍名 |
BookID |
nchar |
30 |
否 |
是 |
书籍的ID |
BookPrice |
int |
N/A |
否 |
是 |
价格 |
UserName |
nchar |
50 |
否 |
是 |
用户名 |
DateTime |
DateTime |
N/A |
否 |
是 |
下订单的时间 |
BookNum |
int |
N/A |
否 |
是 |
购买数量 |
(5)用户留言表(UserMessage):用来存储用户留言内容、留言主题、留言的用户名等,字段说明如表11.5所示。
表5 用户留言表(UserMessage)
字段名称 |
数据类型 |
字段大小 |
是否主键 |
是否为空 |
说明 |
MessageID |
int |
N/A |
是 |
否 |
留言ID |
Title |
nchar |
50 |
否 |
是 |
留言主题 |
|
nchar |
50 |
否 |
是 |
留言者邮箱 |
MsContent |
nchar |
300 |
否 |
是 |
留言内容 |
Name |
nchar |
50 |
否 |
是 |
用户名 |
DateTime |
DateTime |
N/A |
否 |
是 |
留言时间 |
表关系设计
在本系统数据库中,各个表之间的关系比较简单,表之间的引用关系也比较简单,用户留言表为单独的一张表。最终的表关系设计如图
表实体映射–O/R
本章使用LINQ查询数据库,并实现完全面向对象的操作。所以需要把数据库中的所有表都映射到应用程序中。映射步骤如下。
选择"视图"|"服务器资源管理器"命令,打开服务器资源管理器窗口。
右键单击"数据连接"节点,在弹出的快捷菜单中选择"添加连接"命令,要连接的就是本例需要的数据库BookManager。添加完毕后,单击"确定"按钮回到服务器资源管理器。
从表Tables节点中可以看到当前数据库下的所有表。
在网站根目录下添加一个LINQ to SQL Classes类,会自动打开设计视图,如图11.8所示。
把Tables节点下的所有表拖放到设计视图,单击"保存"按钮,保存所有的映射类。
本例使用的拖放方式直接生成了数据表到数据类的映射。这些映射关系以XML的形式保存在应用程序下,如下面的代码所示。而类文件保存在BookManagerDataClasses.designer.cs中。
代码位置:见光盘中本章源代码的BookShopMarket/App_Code/ BookManagerDataClasses. dbml.layout文件。
01 <?xml version="1.0" encoding="utf-8"?> 02 <ordesignerObjectsDiagram dslVersion="1.0.0.0" absoluteBounds="0, 0, 11, 8.5" 03 name="BookManagerDataClasses"> 04 <DataContextMoniker Name="/BookManagerDataClassesDataContext" /> 05 <nestedChildShapes> 06 <classShape Id="71ae7541-73b7-4f69-8f4e- 14dca9b99636" absoluteBounds= "4.75, 3, 2, 07 2.1228255208333335"> 08 <DataClassMoniker Name="/BookManagerData ClassesDataContext/BookInfo" /> 09 <nestedChildShapes> 10 <elementListCompartment Id="e8ad1c7f- 4011-44ed-9c09-b7e480f7ffcd" 11 absoluteBounds="4.7650000000000006, 3.46, 1.9700000000000002, 1.56282552083 33335" 12 name="DataPropertiesCompartment" titleTextColor=" Black" itemTextColor= "Black" /> 13 </nestedChildShapes> 14 </classShape> 15 ………………………………… 16 </nestedChildShapes> 17 </ordesignerObjectsDiagram>
类文件BookManagerDataClasses.designer.cs,部分代码如下所示。
1 #pragma warning disable 1591 2 using System.Reflection; 3 [System.Data.Linq.Mapping.BookDataBase Attribute(Name="BookManager")] //定义数据库 4 5 public partial class BookManagerDataClassesDataContext : System.Data.Linq. DataContext 6 { 7 [Table(Name="dbo.BookInfo")] //定义表 8 public partial class BookInfo : INotifyPropertyChanging, InotifyProperty Changed 9 { 10 private static PropertyChangingEventArgs emptyChangingEventArgs = 11 new PropertyChangingEventArgs(String.Empty); 12 private string _BookID; 13 } 14 …………………… 15 }
开发前准备工作
本例使用了母版页设计,普通用户登录和管理员登录后各使用了两种母版。为了统一操作的方便,在开发前,就需要把母版及母版内容设计好。
在当前项目中添加一个母版页MasterPage.master,让其为管理员的页面服务。在母版页中添加一个Menu导航控件和一个XmlDataSource数据源组件。母版页的设计代码如下所示。这里的代码一定要把table表格设计好,否则母版页的嵌套很可能失败。
代码位置:见光盘中本章源代码的BookShopMarket/MasterPage.master。
01 <table height="237" cellSpacing="0" borderColorDark= "#cccccc" cellPadding="5" 02 width="95%" align="center" borderColorLight="#000000" border="1"> 03 <tr bgColor="#cccccc"> 04 <td vAlign="center" bgColor="#cccccc" colSpan="2" height="5%"> 05 <asp:Menu ID="Menu1" runat="server" 06 DataSourceID="XmlDataSource1" BackColor=" #E3EAEB" 07 DynamicHorizontalOffset="2" Font-Names=" Verdana" Font-Size="1.2em" 08 ForeColor="#666666" Height="16px" Orientation="Horizontal" 09 StaticSubMenuIndent="10px" Width="563px"> 10 <StaticSelectedStyle BackColor="#1C5E55" /> 11 <StaticMenuItemStyle HorizontalPadding ="5px" VerticalPadding= "2px" /> 12 <DynamicHoverStyle BackColor="#666666" ForeColor="White" /> 13 <DynamicMenuStyle BackColor="#E3EAEB" /> 14 <DynamicSelectedStyle BackColor="#1C5E55" /> 15 <DynamicMenuItemStyle HorizontalPadding="5px" 16 VerticalPadding="2px" /> 17 <DataBindings> 18 <asp:MenuItemBinding DataMember ="siteMapNode" 19 NavigateUrlField="url" TextField="title" /> 20 </DataBindings> 21 <StaticHoverStyle BackColor="#666666" ForeColor="White" /> 22 </asp:Menu> </tr> 23 <tr bgColor="#cccccc"> 24 <td height="5%" colSpan="2" align="left" valign="top"> 25 <uc1:Login ID="Login1" runat="server" /> 26 </tr><tr> <td height="90%" colSpan="2"> 27 <asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server"> 28 </asp:ContentPlaceHolder></td> </tr> 29 </table> 30 <asp:XmlDataSource ID="XmlDataSource1" runat="server" 31 DataFile="~/AdminMenu.xml" XPath="siteMapNodes/siteMapNode"> 32 </asp:XmlDataSource>
第5~22行代码是一个Menu菜单控件,用来设计页面的布局。
第30~32行代码使用了XmlDataSource控件,数据源来自XML文件AdminMenu.xml。在获取数据时使用了XPath="siteMapNodes/siteMapNode",来获取内容节点。
用户界面的母版由MasterPage2.master完成,数据来自UserMenu.xml,所采用的样式和方法都与MasterPage.master一样,所以这里不再给出代码。
会员管理模块实现
会员管理模块主要包括会员注册模块、会员登录模块、管理员登录模块、用户信息的编辑与删除。在网络销售系统中,只有注册后的用户才可以下订单买书。
会员注册模块(1)
在项目BookManager中添加一个页面Register.aspx,打开该页面的设计视图。在设计视图中添加控件,包括登录名(UserName)、真实姓名(Name)、密码(PassWord)、确认密码(Psd)、邮箱(Email)和用户地址(Address),在对各个控件添加验证控件。用户注册页面Register.aspx的设计视图如图
该页面的HTML代码如下所示,关键数据要求必须填写,两次密码输入必须相同,所以这里添加了ASP.NET的验证控件RequiredFieldValidator(必填控件)和CompareValidator(比较控件)。
代码位置:见光盘中本章源代码的BookShopMarket/Register.aspx文件。
01 <td class="style4" colspan="2">用户注册</td> 02 <td class="style2">登录名*</td><td class="style3"> 03 <asp:TextBox ID="UserName" runat=" server"></asp:TextBox> 04 <asp:Button ID="RepeatBtn" runat=" server" CausesValidation="False" 05 onclick="RepeatBtn_Click" Text="是否存在?" Width="80px" /> 06 <asp:RequiredFieldValidator ID=" RequiredFieldValidator1" runat="server" 07 ControlToValidate="username" ErrorMessage="登录名不为空 08 "></asp:RequiredFieldValidator> 09 </td> <td class="style2"> 10 真实姓名*</td> 11 <td class="style3"> 12 <asp:TextBox ID="Name" runat="server"></asp:TextBox> 13 <asp:RequiredFieldValidator ID=" RequiredFieldValidator2" runat="server" 14 ControlToValidate="name" ErrorMessage="姓名不为空"> </asp:RequiredField Validator> 15 </td> <td class="style2"> 密码*</td> <td class="style3"> 16 <asp:TextBox ID="PassWord" runat="server" 17 TextMode="Password"></asp:TextBox> 18 <asp:RequiredFieldValidator ID=" RequiredFieldValidator3" runat="server" 19 ControlToValidate="password" ErrorMessage="密码不为空 20 "></asp:RequiredFieldValidator> 21 </td> <td class="style2"> 确认密码*</td> <td class="style3"> 22 <asp:TextBox ID="Psd" runat="server" TextMode=" Password"></asp:TextBox> 23 <asp:CompareValidator ID="CompareValidator1" runat="server" 24 ControlToCompare="password" ControlToValidate="psd" 25 ErrorMessage="确认密码错误"></asp:CompareValidator> 26 </td> <td class="style2"> 邮箱*</td> <td class="style3"> 27 <asp:TextBox ID="Email" runat="server"></asp:TextBox> 28 <asp:RegularExpressionValidator ID="RegularExpressionValidator1" runat ="server" 29 ControlToValidate="email" ErrorMessage="邮箱输入有误" 30 ValidationExpression="w+ ([-+.']w+)*@w+([-.]w+)*.w+([-.]w+)*"> 31 </asp:RegularExpressionValidator> 32 ……………………
第6~8行代码是一个必填控件,如果它针对的username文本框没有任何输入,则验证无法通过。
第23~25行代码是一个比较控件,它对用户两次输入的密码进行对比,如果不相同,验证也无法功过。
会员注册时,包括两个功能:判断用户名是否存在;实现用户注册。这里我们分两部分讲解。
会员注册模块(2)
1.判断用户名是否存在
用户填写登录名后,需要先处理用户名重名的问题,在UserLogin.cs类中完成。打开UserLogin.cs,添加如下代码所示的方法。
说明:所有的处理类默认都放在App_Code文件夹下。
代码位置:见光盘中本章源代码的BookShopMarket/App_Code/UserLogin.cs文件。
01 //判断用户注册时,用户名是否存在,参数为登录名 02 public static int RepeatName(string name) 03 { 04 BookManagerDataClassesDataContext book = 05 new BookManagerDataClassesDataContext(); //数据上下文 06 try 07 {//是否存在数据 08 UserInfo user = book.UserInfos.Where (u => u.UserName == name).First(); 09 if (user !=null) 10 return 1; //返回1 11 else 12 return 0; //返回0 13 } 14 catch 15 { 16 return 0; //返回0 17 } 18 }
第8行代码使用LINQ查询实体类是否有符合条件的对象。
第16行代码表示如果查询过程中发生错误,则返回0,表示查询不到。
此代码的作用查看是该用户名是否存在,如果存在,则返回一个大于0的整数,打开Register.aspx.cx文件,添加"是否存在"按钮的事件处理函数,此处用了一个RepeatName()方法,因为在"提交"按钮中,也要对重名进行判断。实现代码如下所示。
代码位置:见光盘中本章源代码的BookShopMarket/Register.aspx.cs文件。
01 protected void RepeatBtn_Click(object sender, EventArgs e) 02 { 03 bool ReName = RepeatName(); //判断用户名是否存在 04 } 05 public bool RepeatName() 06 { 07 string name = UserName.Text; //获取用户的输入 08 if (UserLogin.RepeatName(name) > 0) //判断用户是否存在 09 { 10 Response.Write("<script>alert('用户名存在')</script>"); 11 return false; 12 } 13 else 14 { 15 Response.Write("<script>alert('恭喜你,用户名不存在')</script>"); 16 return true; 17 } 18 }
第8行代码首先调用UserLogin类的RepeatName方法判断用户名是否存在。
第10行代码和第15行代码是Web中通用的弹出对话框方式,这和Windows程序不同,请读者一定注意。
会员注册模块(3)
2.实现用户注册
添加用户"提交"按钮的事件,提交前一定要先判断是否已经存在此用户,这里直接调用前面的方法就可以,然后再实现添加新用户功能。在UserLogin类中添加新用户的功能,代码如下所示。
代码位置:见光盘中本章源代码的BookShopMarket/App_Code/UserLogin.cs文件。
01 public static void Add(UserInfo user) 02 { 03 BookManagerDataClassesDataContext book = 04 new BookManagerDataClassesDataContext(); //数据上下文 05 book.UserInfos.InsertOnSubmit(user); //插入数据 06 book.SubmitChanges(); //提交更改 07 }
打开Register.aspx.cs文件,添加"提交"按钮事件处理函数,代码如下所示。
代码位置:见光盘中本章源代码的BookShopMarket/Register.aspx.cs文件。
01 protected void Button1_Click(object sender, EventArgs e) 02 { 03 bool ReName = false; 04 ReName = RepeatName(); //判断用户名是否存在 05 //如果用户名不存在与所有控件验证都通过的时候 06 if (Page.IsValid && ReName) 07 { 08 UserInfo user = new UserInfo(); //创建新用户对象 09 user.UserName = UserName.Text; //获取登录名 10 user.Name = Name.Text; //获取名称 11 user.Password = PassWord.Text; //获取密码 12 user.Email = Email.Text; //获取邮箱 13 user.Address = Address.Text; //获取地址 14 user.DateTime = DateTime.Now.Date; //获取当前日期 15 UserLogin.Add(user); //添加用户 16 Response.Redirect("Default.aspx"); //以用户登录身份跳到主页 17 } 18 else Response.Write("<script>alert('注册失败')</script>"); 19 }
第4行代码首先判断当前用户是否存在。
第8~14行代码创建一个新用户对象,并为其赋值。
第15行代码调用UserLogin类的Add方法实现添加用户的功能。
用户登录模块实现(1)
会员登录模块是会员进入会员管理系统的入口,只有登录的会员才有购物功能。由于在很多页面中都有用户登录模块和用户搜索模块,所以此处把用户登录模块和用户搜索模块做成一个用户控件。添加一个Web用户控件Login.ascx,用户搜索模块将在11.4.3节重点介绍。会员登录的设计页面如图11.10所示。
用户控件的HTML代码如下所示。这里必须特别注意的就是添加了一个注册链接,此链接会导航到前面创建的注册页面。
代码位置:见光盘中本章源代码的BookShopMarket/controls/Login.ascx文件。
01 <asp:Label ID="LbUsername" runat="server" Text="用户名:"></asp:Label> 02 <asp:TextBox ID="UserName" runat="server" Width="85px"></asp:TextBox> 03 <asp:Label ID="LbPassWord" runat="server" Text="密码:"></asp:Label> 04 <asp:TextBox ID="PassWord" runat="server" Width="85px" 05 TextMode="Password"></asp:TextBox> 06 <asp:Button ID="LoginBtn" runat="server" Text="登录" Height="27px" 07 onclick="LoginBtn_Click" Width="46px" /> 08 09 <asp:LinkButton ID="Register" runat="server" Font-Underline="False" 10 PostBackUrl="~/Register.aspx">注册</asp:LinkButton>
在初始化页面时,登录面板是可见的。当用户登录成功后,登录面板是不可见的。这时用Session["UserName"]来判断用户是否登录。Session["UserName"]在Global.asax的Session_Start中定义,后面会介绍。此处判断用户是否已登录的代码如下所示。
代码位置:见光盘中本章源代码的BookShopMarket/controls/Login.ascx.cs文件。
01 protected void Page_Load(object sender, EventArgs e) 02 { 03 if (Session["UserName"].ToString() != "") //判断用户是否已经登录 04 { 05 LoginUser(); //如果用户登录成,执行此方法 06 } 07 } 08 void LoginUser() //用户登录成功 09 { 10 PassWord.Visible = false; //密码框不可见 11 LbPassWord.Visible = false; //密码不可见 12 UserName.Visible = false; //用户名框不可见 13 //把'用户名'改为'你好,(登录成功的用户名)' 14 LbUsername.Text = "你好," + Session["UserName"].ToString(); 15 LbUsername.ForeColor = System.Drawing.Color.Blue; //把上面的文字变成蓝色 16 LbUsername.Font.Size = 18; //字体大小改为18px 17 //把宽度变为395px,用来填充文本宽度, 使布局不变,否则搜索框会向左边移动 18 LbUsername.Width = 395; 19 LoginBtn.Visible = false; //"登录"按钮不可见 20 Register.Visible = false; //"注册"按钮不可见 21 }
第3~6行代码通过Session来判断用户是否已经登录,Session类似于一个小型缓存器。
第10~20行代码设计界面的布局,设置哪些控件该显示,哪些不该显示。
用户身份验证是通过"登录"按钮的事件来实现的,需要对用户名和密码进行判断。这里用到了UserLogin类的login()方法,打开UserLogin.cs,添加代码如下所示的内容。
代码位置:见光盘中本章源代码的BookShopMarket/App_Code/UserLogin.cs文件。
01 //判断用户登录时,用户名与密码是否正确,如果正确返回true,否则返回false 02 public static bool login(string UserName, string PassWord) 03 { 04 BookManagerDataClassesDataContext book 、 05 = new BookManagerDataClassesDataContext(); //数据上下文 06 try 07 { 08 UserInfo user = book.UserInfos.Where (u => u.UserName == 09 UserName && u.Password == PassWord).First(); //是否存在数据 10 if (user !=null) 11 return true; //返回成功 12 else 13 return false; //返回失败 14 } 15 catch 16 { 17 return false; //返回失败 18 } 19 }
第4行代码是一个标准的上下文创建语句,后面会多次用到,要使用实体类,需要生成上下文。
第8~9行代码使用LINQ查询实体类中的数据。
在Login.ascx.cs中,添加"登录"事件的处理函数,代码如下所示。登录时判断用户的用户名和密码是否正确。如果正确,则调用LoginUser()方法显示登录面板。
用户登录模块实现(2)
代码位置:见光盘中本章源代码的BookShopMarket/controls/Login.ascx.cs文件。
01 protected void LoginBtn_Click(object sender, EventArgs e) 02 { 03 if (UserName.Text != "" && PassWord.Text != "") //判断用户输入是否为空 04 { 05 if (UserLogin.login(UserName.Text, PassWord.Text)) //判断用户名和密码是否正确 06 { 07 //把登录后的名字保存在Session["UserName"]中 08 Session["UserName"] = UserName.Text; 09 LoginUser(); //如果用户登录成功执行此方法 10 } 11 else Response.Write("<script>window.alert ('用户名或密码错误')</script>"); 12 } 13 else Response.Write("<script>window.alert ('用户名和密码不为空')</script>"); 14 }
第3行代码首先判断用户是否已经输入了内容,也可以在客户端使用验证控件完成这个工作。
第5行代码调用UserLogin类的login方法判断输入是否正确。
第8行代码非常关键,用户登录成功后,通过Session保存其用户名,在后面的判断中会多次使用。
此处用了Session["UserName"],如果其没有在Global.asax的Session_Start中定义,就会报错。在Global.asax的Session_Start中定义的意义是:每当用户进入网站时,系统就会为用户初始化一个Session["UserName"]对象。初始化时,把此对象的值设为空。当用户登录为会员时,此对象的值就不为空了,此时Session["UserName"]就等于登录用户的用户名。关于Global.asax的Session_Start事件可以参考下面的代码。
代码位置:见光盘中本章源代码的BookShopMarket/Global.asax文件。
01 void Session_Start(object sender, EventArgs e) 02 { 03 //在新会话启动时运行的代码 04 Session["UserName"] = ""; //初始化用户名 05 Session["BookName"] = ""; //初始化书名 06 Session["BookNum"] = "0"; //初始化购买图书的数量 07 Session["BookPrice"] = "0"; //初始化购买图书的价格 08 Session["SearchBookType"] = ""; //用于查找功能,说明图书类型 09 Session["SearchKey"] = ""; //用于查找功能,说明图书关键字 10 //管理员用户名,防止用户不输入管 理员姓名和密码,直接跳到管理页 11 Session["AdminLogin"] = ""; 12 }
关于其他的Session对象,在以后用到时再详细介绍。如果网站根目录下没有Global.asax文件,可右键单击当前项目,在"添加新项"对话框中选中"全局应用程序类"项,将此文件添加到项目中。
管理员登录模块实现
登录分为两种登录情况:普通用户登录和管理员登录。管理员相当于网站的最高级别领导,管理员登录到后台可以对用户、书籍、订单等数据进行管理。管理员登录页面是AdminLogin.aspx,该页面设计视图如图11.11所示。
管理员登录的部分HTML如下代码所示,界面设计并没有特别之处。
代码位置:见光盘中本章源代码的BookShopMarket/admin/AdminLogin.ascx文件。
01 <table border="2" class="style1" style="text-align: center; height: 247px;"> 02 <tr> 03 <td class="style2" colspan="2"> 04 管理员登录</td> 05 </tr> 06 <tr> 07 <td> 08 用户名:</td> 09 <td> 10 <asp:TextBox ID="UserName" runat="server" Width="145px"></asp:TextBox> 11 </td> 12 </tr> 13 <tr> 14 <td> 15 密码:</td> 16 <td> 17 <asp:TextBox ID="PassWord" runat=" server" TextMode="Password" 18 Width="145px"></asp:TextBox> 19 </td> 20 </tr> 21 <tr> 22 <td colspan="2"> 23 <asp:Button ID="LoginBtn" runat="server" Text="登录" Height="28px" 24 onclick="LoginBtn_Click" Width="56px" /> 25 </td> 26 </tr> 27 </table>
单击"登录"按钮时,需要对管理员的用户名和密码进行判断。如果用户名和密码正确,则进入管理页面,此处用到了一个UserLogin类的AdminLogin()方法。该主法返回的是一个bool值,如下面的代码所示。这里后台绑定了用户名和密码,而不是从数据库中读取。
代码位置:见光盘中本章源代码的BookShopMarket/App_Code/UserLogin.cs文件。
01 //判断管理员登录时,用户名与密码是否存在 02 public static bool AdminLogin(string UserName, string PassWord) 03 { 04 //如果管理员的用户名和密码是"admin",则返回true 05 if (UserName == "admin" && PassWord == "admin") 06 { 07 return true; 08 } 09 else return false; 10 }
双击"登录"按钮,完善它的事件处理函数,如下面的代码所示。
代码位置:见光盘中本章源代码的BookShopMarket/admin/AdminLogin.ascx.cs文件。
01 //用于管理员登录 02 protected void LoginBtn_Click(object sender, EventArgs e) 03 { 04 //判断管理员登录时,用户名与密码是否正确 05 if (UserLogin.AdminLogin(UserName.Text, PassWord.Text)) 06 { 07 //如果用户登录成功,给Session["AdminLogin"]传值 08 Session["AdminLogin"] = "AdminLogin"; 09 Response.Redirect("~\admin\ adminpage.aspx");//跳转到管理员主页 10 } 11 else Response.Write("<script>alert ('管理员姓名或密码错误')</script>"); 12 }
第5行代码验证管理员的用户名和密码。
第8行代码非常关键,如果管理员登录成功,则用Session保存管理员信息,这样在进入管理员专用页面时,会先判断Session中是否有值,没有就不允许进入。
注意:这里管理员的用户名和密码都是admin。
用户管理模块实现
这是管理员的功能,管理员必须登录到后台,才能操作该页面。这个页面是AdminUserInfo.aspx。管理员可以在后台对用户进行编辑和删除,该页面的设计视图如图11.12所示。
该页面主要由一个GridView控件实现,不需要在后台写代码。AdminUserInfo.aspx的 HTML代码如下所示。
代码位置:见光盘中本章源代码的BookShopMarket/admin/AdminUserInfo.ascx文件。
01 <asp:GridView ID="GridView1" runat="server" AllowPaging="True" 02 AllowSorting="True" AutoGenerateColumns="False" CellPadding="4" 03 DataKeyNames="UserName" DataSourceID="SqlDataSource1" 04 ForeColor="#333333" 05 GridLines="None" Height="18px" PageSize="8" Width="787px"> 06 <PagerSettings FirstPageText="首页" LastPageText="尾页" 07 Mode="NextPreviousFirstLast" NextPageText=" 下一页" PreviousPage Text=" 08 上一页" /> 09 <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" /> 10 <RowStyle BackColor="#EFF3FB" /> 11 <Columns> 12 <asp:CommandField ButtonType="Button" HeaderText="用户名" 18 ReadOnly="True" 19 SortExpression="UserName"> 20 <ControlStyle Width="60px" /> 21 </asp:BoundField> 22 <asp:BoundField DataField="Name" HeaderText="真实姓名" 23 SortExpression="Name"> 24 <ControlStyle Width="60px" /> 25 </asp:BoundField> 26 <asp:BoundField DataField="PassWord" HeaderText="密码" 27 SortExpression="PassWord"> 28 <ControlStyle Width="70px" /> 29 </asp:BoundField> 30 <asp:BoundField DataField="Email" HeaderText="邮箱" 31 SortExpression="Email"> 32 <ControlStyle Width="100px" /> 33 </asp:BoundField> 34 <asp:BoundField DataField="Address" HeaderText="地址" 35 SortExpression="Address"> 36 <ControlStyle Width="130px" /> 37 </asp:BoundField> 38 <asp:BoundField DataField="Datetime" HeaderText="注册时间" 39 SortExpression="Datetime"> 40 <ControlStyle Width="130px" /> 41 </asp:BoundField> 42 </Columns> 43 <PagerStyle BackColor="#2461BF" ForeColor=" White" HorizontalAlign= "Center" 44 /> 45 <SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" 46 ForeColor="#333333" /> 47 <HeaderStyle BackColor="#507CD1" Font-Bold=" True" ForeColor="White" /> 48 <EditRowStyle BackColor="#2461BF" /> 49 <AlternatingRowStyle BackColor="White" /> 50 </asp:GridView> 51 …………………………………
至此,用户登录模块就已经实现了。浏览效果如图11.13所示。输入用户名和密码,单击登录按钮,成功后如图11.14所示。注意两个图的导航栏内容不同,一个是针对管理员的导航,一个是针对普通用户的导航。
书籍类别管理
书籍信息管理由浏览图书、浏览图书详情、添加图书信息、图书信息的编辑与删除等模块组成。这些模块有的只允许管理员操作,所以编写代码时要注意条件的判断。
浏览图书模块实现
在项目中添加一个AllBook.aspx窗体,继承自母版页:MasterPage.master,浏览图书功能主要由GirdView控件来实现,因为通过其浏览,可以用尽量少的代码完成图书浏览功能。该页面的HTML代码如下所示,给出这段代码的目的是让读者了解,在绑定字段中添加了一个按钮,CommandName属性设置为info,通过其可以访问所选书的详细信息。
代码位置:见光盘中本章源代码的BookShopMarket/AllBook.aspx文件。
01 <asp:GridView ID="GridView1" runat="server" AllowPaging="True" 02 AllowSorting="True" AutoGenerateColumns=" False" CellPadding="4" 03 DataKeyNames="bookid" DataSourceID=" SqlDataSource1" ForeColor="#333333" 04 GridLines="None" Height="44px" Width="796px" PageSize="8" 05 onrowcommand="GridView1_RowCommand"> 06 <PagerSettings FirstPageText="首页" LastPageText="尾页" 07 Mode="NextPreviousFirstLast" NextPageText=" 下一页" PreviousPageText="上一页 08 " /> 09 <FooterStyle BackColor="#1C5E55" Font-Bold=" True" ForeColor="White" /> 10 <RowStyle BackColor="#E3EAEB" /> 11 <Columns> 12 <asp:BoundField DataField="bookname" HeaderText="图书名" 13 SortExpression="bookname" ApplyFormatInEditMode="True" /> 14 <asp:BoundField DataField="bookid" HeaderText="图书ID" ReadOnly= "True" 15 SortExpression="bookid" /> 16 <asp:BoundField DataField="bookprice" DataFormatString="{0:c}" 17 HeaderText="价格" SortExpression="bookprice" /> 18 <asp:BoundField DataField="bookaddress" HeaderText="出版社" 19 SortExpression="bookaddress" /> 20 <asp:BoundField DataField="bookpeople" HeaderText="作者" 21 SortExpression="bookpeople" /> 22 <asp:ButtonField ButtonType="Button" 23 CommandName="info" HeaderText="详细信息" 24 ShowHeader="True" Text="详细信息" /> 25 <asp:TemplateField HeaderText="加入购物篮"> 26 <EditItemTemplate> 27 <asp:CheckBox ID="CheckBox1" runat="server" /> 28 </EditItemTemplate> 29 <ItemTemplate> 30 31 <asp:CheckBox ID="CheckBox1" runat="server" AutoPostBack= "True" 32 oncheckedchanged="CheckBox1_CheckedChanged" /> 33 </ItemTemplate> 34 <ControlStyle Width="20px" /> 35 </asp:TemplateField> 36 </Columns> 37 …………………………………… 38 </asp:GridView>
当用户单击"详细信息"按钮后,可以浏览图书的详细信息,这是通过后台的GridView1_ RowCommand事件完成的。一定要在设计端把"详细信息"按钮的CommandName设为info。"详细信息"按钮的事件处理函数如下代码所示。
代码位置:见光盘中本章源代码的BookShopMarket/AllBook.aspx.cs文件。
01 protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e) 02 { 03 if (e.CommandName == "info") //判断用户单击的是哪个按钮 04 { 05 int index = Convert.ToInt32(e.CommandArgument); //获取用户单击按钮的行 06 //把单击按钮行的图书ID传给Session["bookname"] 07 Session["BookName"] = GridView1.Rows[index]. Cells[1].Text.ToString(); 08 Response.Redirect("~/BookInfo.aspx"); //跳转到BookInfo页面中 09 } 10 }
图书详细信息模块实现
图书详细信息模块显示图书的详细信息(如出版日期、出版社等),该模块通过BookInfo.aspx窗体来实现,页面的设计效果如图11.15所示。该页面主要由控件DataList实现。其中,DataList控件的HMTL代码如下所示。读者要关注的是DataList并不自己生成模板,而需要读者手动设计,设计的内容一定要在"ItemTemplate"模板内。
代码位置:见光盘中本章源代码的BookShopMarket/BookInfo.aspx文件。
01 <asp:DataList ID="DataList1" runat="server" DataKeyField="bookid" 02 DataSourceID="SqlDataSource1" CellPadding="4" ForeColor="#333333" 03 Width="799px" RepeatColumns="2"> 04 <FooterStyle BackColor="#1C5E55" Font-Bold="True" ForeColor= "White" 05 /> 06 <AlternatingItemStyle BackColor="White" /> 07 <ItemStyle BackColor="#E3EAEB" /> 08 <SelectedItemStyle BackColor="# C5BBAF" Font-Bold="True" 09 ForeColor="#333333" /> 10 <HeaderStyle BackColor="#1C5E55" Font-Bold="True" ForeColor= "White" 11 /> 12 <ItemTemplate> 13 <table><tr><td rowspan="6"> 14 <asp:Image ID="BookImage" runat="server" Height="243px" 15 Width="172px" /> 16 </td><td >书名</td><td> 17 <asp:Label ID="BookName" runat="server" Text='<%# Eval ("bookname") 18 %>' /> …………………
具体功能的实现比较简单,Session["BookName"]保存的是图书ID,Session["BookName"]在Global.asax的Session_Start中定义。这里的Session["BookName"]与用户登录模块的Session["UserName"]用法基本相同,此处不再详细介绍。图书的详细信息通过Session["BookName"]传递过来的值判断,然后绑定到DataList模板中,具体实现功能的代码如下所示。
代码位置:见光盘中本章源代码的BookShopMarket/BookInfo.aspx.cs文件。
01 protected void Page_Load(object sender, EventArgs e) 02 { 03 //如果用户没有选择图书,而直接跳到该页,则返回到主页 04 if (Session["BookName"].ToString() != "") 05 { 06 //改变datalist的查询方式,查询用户所需的图书信息。 07 SqlDataSource1.SelectCommand = "select * from BookInfo where BookID='" 08 + Session["BookName"].ToString() + "'"; 09 for (int i = 0; i < DataList1.Items.Count; i++) 10 { 11 //用户所需图书的图片 12 ((Image)DataList1.Items[i].FindControl ("BookImage")).ImageUrl = 13 "~\UploadImage\" + ((Label)DataList1.Items[i]. FindControl("Image Url")).Text; 14 } 15 } 16 else Response.Redirect("~/Default.aspx"); 17 }
第4行代码通过读取Session的值来判断用户的选择。
第7行代码通过设置SqlDataSource1控件的选择命令来更改查询条件。
第12~13行代码加载图书的封面图片,这非常关键,是网站中图片加载的主要方式。
【责任编辑: 云霞 TEL:(010)68476606】
图书添加模块实现
图书添加只有后台管理员可以操作,操作的页面是AdminAddBook.aspx。该页的界面设计效,果
该页面的部分HTML代码如下所示,设计页面时主要考虑上传图片这一难点,这里使用了FileUpload上传控件,读者一定要知道,此处数据库中保存的不是图片,而是图片的名称,因为图片会保存在服务器上,通过名称来获取。
代码位置:见光盘中本章源代码的BookShopMarket/admin/AdminAddBook.aspx文件。
01 <table style="text-align: left; height: 470px; font-size: large; width: 731px;" 02 border="2"><tr> <td class="style4" colspan="2" > 03 <<图书添加</td></tr> <tr> 04 <td class="style1" > 图书名*</td><td> 05 <asp:TextBox ID="BookName" runat="server" Height="22px" 06 Width="188px"></asp:TextBox> 07 <asp:RequiredFieldValidator ID=" RequiredFieldValidator1" runat="server" 08 ControlToValidate="BookName" ErrorMessage="图书名不为空 09 "></asp:RequiredFieldValidator> 10 </td></tr><tr><td class="style1" > 图书ID*</td><td> 11 <asp:TextBox ID="BookID" runat="server" Width="188px"></asp: TextBox> 12 <asp:RequiredFieldValidator ID=" RequiredFieldValidator2" runat= "server" 13 ControlToValidate="BookID" ErrorMessage="图书ID不为空 14 "></asp:RequiredFieldValidator> 15 </td> </tr> 16 ……………………………………………………… 17 <tr><td class="style1" >上传图片:</td> <td> 18 <asp:FileUpload ID="UploadImage" runat="server" Width="241px" /> 19 <asp:Label ID="Label3" runat=" server" Text="(小于2M的jpg或bmp 20 图片)" Font-Bold="False" 21 Font-Size="Medium"></asp:Label> 22 </td> </tr><tr> 23 <td class="style1" colspan="2" > 24 <asp:Button ID="AddBookBtn" runat="server" Text="确定" 25 onclick="AddBookBtn_Click" style="height: 26px" Height= "59px" 26 Width="86px" /> 27 </td></tr></table> 28 <asp:Label ID="ShowMessage" runat="server" Width="128px"></asp:Label>
双击"确定"按钮,在其事件处理函数中添加如下面的代码所示的内容。使用上传功能前,先在当前项目中创建一个名为UploadImage的文件夹,用来保存图片。这些图片一般都是图书的封面信息。
代码位置:见光盘中本章源代码的BookShopMarket/admin/AdminAddBook.aspx.cs文件。
01 protected void AddBookBtn_Click(object sender, EventArgs e) 02 { 03 string Path = Server.MapPath("~/UploadImage/"); //上传文件的路径 04 string FileName = UploadImage.PostedFile.FileName; 05 if (UploadImage.HasFile) //判断文件是否存在 06 { 07 //判断文件的大小与格式 08 if (UploadImage.PostedFile.ContentLength < 2048000 && 09 ((FileName.Substring(FileName.LastIndexOf(".") + 1). ToString().ToLower()) == "jpg" || 10 (FileName.Substring(FileName.LastIndexOf(".") + 1). ToString().ToLower()) == "bmp")) 11 { 12 UploadImage.SaveAs(Path + UploadImage.FileName); //把图片保存起来 13 } 14 else 15 { 16 ShowMessage.Text = "图片上传失败"; 17 return; 18 } 19 } 20 BookInfo bookinfo=new BookInfo{ 21 BookID=BookID.Text, 22 BookName=BookName.Text, 23 BookAddress=BookAddress.Text, 24 BookPrice=int.Parse(BookPrice.Text), 25 BookDate=DateTime.Parse(BookDate.Text), 26 BookPeople=BookPeople.Text, 27 BookSay=BookSay.Text, 28 BookPhoto=UploadImage.FileName 29 }; //创建一个图书对象 30 try 31 { 32 33 BookBookDataBase.add(bookinfo); //把上面信息插到数据库中 34 ShowMessage.Text = "上传成功"; 35 } 36 catch 37 { 38 //如果发生异常,返回到管理员主页 39 Response.Redirect("~\Admin\AdminPage.aspx"); 40 } 41 }
第7~10行代码用来判断上传文件的大小和格式,大小不能多于2MB,文件类型必须是JPG或BMP。
第20~29行代码用来创建一个新的图书对象,并且为其赋值。
第33行代码调用BookBookDataBase类的add()方法添加数据到数据库。
在把信息插入到数据库时,调用了BookBookDataBase类的add()方法,此方法在会员注册模块中已经说明,这里不再介绍,BookDataBase类add()方法的代码如下所示。
代码位置:见光盘中本章源代码的BookShopMarket/App_Code/BookBookDataBase.cs文件。
01 public static void add(string add) 02 { 03 BookManagerDataClassesDataContext book = 04 new BookManagerDataClassesDataContext(); //数据上下文 05 book.BookInfos.InsertOnSubmit(bookinfo); //插入数据 06 book.SubmitChanges(); //提交更改 07 }
图书编辑与删除模块(1)
图书编辑与删除是系统管理员的功能,管理员必须登录到后台后,才能操作该页面,该页面是AdminBookInfo.aspx。页面功能主要由一个GridView来实现,界面设计如图11.17所示。
该页面的功能全部由GridView控件方法实现,没有功能代码,部分HTML代码如下所示。
代码位置:见光盘中本章源代码的BookShopMarket/admin/AdminBookInfo.aspx文件。
01 <asp:GridView ID="GridView1" runat="server" AllowPaging="True" 02 AllowSorting="True" AutoGenerateColumns="False" CellPadding="4" 03 DataKeyNames="BookID" DataSourceID="SqlDataSource1" ForeColor="#333333" 04 GridLines="None" Height="16px" PageSize="7" Width="791px"> 05 <PagerSettings FirstPageText="首页" LastPageText="尾页" 06 Mode="NextPreviousFirstLast" NextPageText="下一页" PreviousPageText="上一页" /> 07 <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" /> 08 <RowStyle BackColor="#EFF3FB" /> 09 <Columns> 10 <asp:CommandField ButtonType="Button" HeaderText="编辑" 11 ShowDeleteButton="True" 12 ShowEditButton="True"> 13 <ControlStyle Width="50px" /> 14 </asp:CommandField> 15 <asp:BoundField DataField="BookID" HeaderText=" 图书ID" ReadOnly="True" 16 SortExpression="BookID"> 17 <ControlStyle Width="100px" /> 18 </asp:BoundField> 19 ………………………………………………………………… 20 </Columns> 21 <PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" /> 22 <SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" /> 23 <HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" /> 24 <EditRowStyle BackColor="#2461BF" /> 25 <AlternatingRowStyle BackColor="White" /> 26 </asp:GridView>
到此,图书管理模块就实现了,用户可以浏览图书、查看图书详细信息,而管理员可以实现添加图书、删除图书、编辑图书等功能。
测试上述实现的页面,单击"浏览图书"菜单,浏览效果如图11.18所示。单击网格中"详细信息"列的"详细信息"按钮,会弹出该书的详细信息页
转载于:https://my.oschina.net/bigfool007139/blog/552035