文章教程

第29章B2C网上购物系统实战

8/31/2020 9:10:17 PM 人评论 次浏览

第29章 B2C网上购物系统实战

本章视频教学录像:23分钟

以练促学,通过实际项目开发,巩固加深对.Net的掌握。本章通过开发一个完整的B2C网上购物系统,以掌握Web系统开发的流程。

本章要点(已掌握的在方框中打钩)

□ 开发背景

□ 需求及功能分析

□ 系统功能实现

□ 系统运行

□ 开发过程常见问题及解决

29.1 开发背景

本节视频教学录像:2分钟

我们已经系统地学习了.Net程序设计的基本概念、方法和一般的应用技巧,但是编程的目的是应用,而不是死记硬背,不会灵活使用,知识永远也无法转化成能力。本章通过建立一个较为完整的B2C网上购物系统,让大家全面地掌握.Net的基本知识,并熟练掌握Web网站系统开发的基本流程。

结合本系统,一个Web网站的开发流程通常需要经历以下几个步骤。

⑴知道为什么做,也就是编写程序的目的是什么。我们要开发的是具有网上购物功能的一个系统。

⑵要做哪些事情,做这些事情需要达到什么程度。网上购物,通常就是要完成顾客注册、商品录入与展示、购物车、订单查询与处理等功能。

⑶数据库的设计,这是建立在对项目需求明确、功能清晰基础上的,因为数据库的设计是项目的基石,必须牢固。本系统的数据库是用来存储信息数据的,鉴于本系统的重点不是数据库,故实现的方法略微简单。

⑷编写代码。在达到目的的前提下,兼顾代码的运行效率,也就是体现出代码的功能化、模块化等。

⑸运行系统,查漏补缺,总结经验和教训。

29.2 需求及功能分析

本节视频教学录像:6分钟

所谓磨刀不误砍柴工,在接到项目任务时,不能盲目地进行开发。在开发之前,要对项目的开发背景、客户的需求以及项目的可行性等进行分析,然后再根据分析的结果做出合理的项目规划,使项目能够按部就班地进行,不至于出现顾此失彼的情况。

提示

在实际应用中,需求不是非常明确的,需要与客户长期接洽才能达成共识。

29.2.1 需求分析

通常,网上购物系统的功能可以很复杂很强大,也可以很简单很明了,但是最主要的需求是必须满足的,比如顾客的注册,商品的查询、维护、销售,订单的查询与处理等。经过这样一个调查分析的过程,我们设计的B2C网上购物系统的需求才能明确。

下面,把B2C网上购物系统的主要需求一一列举出来。

⑴设计数据库,用来存储顾客、商品、购物车、订单等各种信息,这样顾客、商品、购物信息才不至于程序结束导致据丢失,并且能对各种数据信息进行有效管理,方便查询与存储操作。本次.NET系统的开发,将采用SQL Server作为数据库。

⑵顾客的注册。

⑶顾客、管理人员的登录。

⑷商品呈现,实现顾客对商品的浏览与查找。

⑸购物车,实现顾客可以方便地多次购物。

⑹商品管理,实现对商品信息的录入与管理功能。

⑺销售订单管理,实现对顾客的订单进行查询和处理。

这就是我们设计的系统的基本需求,在需求定义阶段,设计人员和需方人员应协调沟通,确认需求且彼此理解无误,形成书面文档,就可以进行下一步的工作了。

下面对系统进行功能分析。

29.2.2 总体功能设计

总体功能模块设计,是在需求的基础上,对系统的架构做一个总体的规划。开发一个项目,特别是复杂的项目,总体设计方案是由大家集思广益,多次商讨之后决定的。我们这样做,也是按照程序设计的指导思想进行的,即由上至下、逐步细化。

可以把本系统分为以下几大模块:人员信息管理、商品呈现、购物车、商品管理、订单管理。如图所示。

figure_0614_0973

为了充分发挥.NET的特性,我们建立一个购物明细类OrderItem 和订单信息类OrderInfo,为购物信息的传递实现提供方便。类声明如下。

01 //购物明细项目类

02 public class OrderItem

03 {

04 public string ID; //商品编号

05 public float Price; //商品价格

06 public int Num; //商品数量

07 public float SumPrice; //小计

08 public OrderItem()

09  {

10  }

11 }

12 //订单信息类

13 public class OrderInfo

14 {

15 public string OrderNo;  //订单编号

16 public DateTime OrderTime; //下单时间

17 public float TotalPrice; //订单总金额

18 public string BuyerName; //购货人姓名

19 public string BuyerPhone; //联系人电话

20 public string BuyerEmail; //Email地址

21 public string ReceiverName; //收货人姓名

22 public string ReceiverPhone; //联系人电话

23 public string ReceiverAddress; //收货人地址

24 public string ReceiverPostalcode; //邮政编码

25 public string State; //订单状态

注意

在这里声明类对象,目的是为了程序在传值的时候简单一些,表达方便,不一定都要把信息封装成类。

29.2.3 各功能模块设计

下面依次介绍人员信息管理、商品呈现、购物车、商品管理和订单管理5大模块的实现。

1. 人员信息管理

人员信息管理是用来实现B2C网上购物系统的顾客在线注册、顾客信息管理和管理员信息管理等3个功能。

人员信息管理模块的流程如图所示。

figure_0615_0974

2. 商品呈现模块

商品呈现模块的功能是将系统中的商品在网站首页显示出来,提供多种供用户查询自己所需商品的方法。

流程如图所示。

figure_0616_0975

提示

我们对按各种条件检索出来的商品,如种类、价格区间或名称,在展示商品信息时,可以将商品的图片信息显示出来,这样会给顾客呈现非常直观的效果。

3. 购物车模块

网上购物车模块实现顾客的购物过程,提供类似于超市中小购物车的功能,用来搜集顾客选中的商品,一块结账。并实现比商场的传统购物车更方便的功能:顾客可以多次购物,购物车会记录下每次顾客选中的商品,下次登录时可以继续购物,多次一块结账,而不需要像逛超市一样,每次要重新推一个空的购物车重新选购。

网上购物车模块流程如图所示。

figure_0616_0976

4. 商品管理模块

商品管理模块的功能是录入要销售的商品信息,如名称、种类、价格、图片等信息,然后对录入的商品进行修改、删除等维护操作。

商品管理模块流程如图所示。

figure_0616_0977

5. 订单管理模块

订单管理模块的功能是查询客户订单,核对订单信息,对订单进行处理。

订单管理模块流程如图所示。

figure_0617_0978

29.3 系统功能实现

本节视频教学录像:7分钟

本节从以下几个方面详细讲解B2C网上购物系统是如何实现的,分为系统目录框架、顾客注册功能、人员信息管理、商品呈现、购物车、商品管理、订单管理等。

29.3.1 系统目录框架的搭建

本小节介绍系统目录框架的搭建。B2C系统和一般的Web网站略有不同,其权限管理和逻辑流程较一般网站更为复杂。系统框架的搭建也有别于网站的开发。下面具体介绍本系统搭建的流程。

1. 创建项目

系统搭建的第1步是创建一个站点。打开Visual Studio 2008,选择文件→新建→网站,在弹出的新建网站窗口中选择代码文件的存放路径和开发语言,系统将在选定的文件路径下写入Web开发所需的文件,并生成一个默认的Web网页“Default.aspx”,这样系统项目就建好了。

以后需要添加页面时,只需要在解决方案面板中,在网站需要添加页面的目录单击右键,在弹出的快捷菜单中选择【添加新项】菜单项,然后在弹出的【新建文件】对话框中选择需要添加的文件类型和文件即可。

2. 附加数据库

⑴在SQL Server 2008中,右击【对象资源管理器】中的【数据库】,在弹出的快捷菜单中选择【附加】菜单项。

figure_0618_0979

⑵单击【添加】按钮,添加“随书光盘ch29\db_EShop.mdf”数据库文件。

figure_0618_0980

⑶修改Web.config文件的<connectionStrings>标签对为以下代码。

01 <connectionStrings>

02 <add name="db_EShopConnectionString" connectionString="Data Source=,\sqlexpress;InitialCatalog=DB_ESHOP;User ID=sa;Password=123"/>

03 < /connectionStrings>

提示

“Data Source=.\sqlexpress”表示数据库在本地计算机中,开发完成后,可将该地址改为数据库的具体地址。“User ID”和“Password”可改为自己计算机中SQL Server 2008的登录账户名和密码。

3. 页面框架

接下来的工作就是决定系统页面的框架和页面的风格。系统采用如图所示的框架,依次为页头、菜单、导航、主功能区、页脚。因为除了登录和重设密码外,所有的页面布局基本一致,所以我们可采用模板页以保证系统具有统一的风格,从而提高代码的重用度。

figure_0618_0981

模板页是在项目里选择【添加新项】,在弹出窗口中选择【添加母版页】,然后再进行排版布局。

29.3.2 顾客注册功能的实现

在Web项目上右击,选择【添加新项】,选择新建一个Web窗体,即可创建一个Web网页,我们把这个页面的文件命名为“AddUser”,用来实现注册用户的功能。可以看到,对于一个Web窗体, Visual Studio .Net 实际上创建了两个文件,一个是aspx前台页面文件,负责页面布局与控件的声明;一个是.cs后台程序文件,用来实现逻辑处理。在后面其他页面创建时也都采用这种方法。

顾客注册包括顾客的基本信息录入,以及确认提交,在前台页面提供了注册信息的输入,及非空等验证,单击【提交】按钮后,服务器端将会对提交的注册信息进行逻辑处理,合法信息将会保存到数据库中。后台程序单击【提交】按钮的代码如下(代码29-1.txt)。

01 protected void btnSubmit_Click(object sender,EventArgs e)

02 {

03 stringsql=@"insertinto[USER](ID,NAME,PASSWORD,PHONECODE,EMAILS,ADVANCEPAYMENT,ROLE) values (@ID,@NAME,@PASSWORD,@PHONECODE,@EMAILS,@ADVANCEPAYMENT,@ROLE)";

04 SqlParameter[]parameters= newSqlParameter[7];

05

06 SqlParameter id= new SqlParameter("@ID",SqlDbType.Char);

07 DateTime tempTime=DateTime.Now;

08   id.Value= tempTime.ToString("yyyyMMddhhmmss");

09 parameters[0]= id;

10 SqlParameter name= new SqlParameter("@NAME",SqlDbType.VarChar);

11 name.Value= this.txtUserName.Text.Trim();

12 parameters[1]= name;

13

14 SqlParameter password= new SqlParameter("@PASSWORD",SqlDbType.VarChar);

15 password.Value= this.txtPassword.Text.Trim();

16 parameters[2]=password;

17

18 SqlParameter phoneCode= new SqlParameter("@PHONECODE",SqlDbType.VarChar);

19 phoneCode.Value= this.txtPhone.Text.Trim();

20 parameters[3]=phoneCode;

21

22 SqlParameter email= new SqlParameter("@EMAILS",SqlDbType.VarChar);

23 email.Value= this.txtEmail.Text.Trim();

24 parameters[4]= email;

25

26 SqlParameter adven= new SqlParameter("@ADVANCEPAYMENT",SqlDbType.Float);

27 adven.Value= 0;

28 parameters[5]= adven;

29

30 SqlParameter role= new SqlParameter("@ROLE",SqlDbType.Bit);

31  role.Value= false;

32 parameters[6]= role;

33  try

34  {

35    int result=dbHelper.ExecuteNonQuery(sql,parameters);

36    if (result== 1)

37   {

38  Response.Write("<script type='text/javascript'> alert('添加成功 ');< /script>");

39

40   }

41  else

42    throw new Exception();

43  }

44 catch

45  {

46  Response.Write("<script type='text/javascript'> alert('用户名已存在,请修改用户名! ');< /script>");

47  }

48

49 }

此处代码中调用了公共类DataBaseHelper,其代码如下(代码29-2.txt)。

01 using System;

02 using System.Data;

03 using System.Data.SqlClient;

04 using System.Configuration;

05 public class DataBaseHelper

06 {

07  //声明数据连接对象和数据访问对象

08 private SqlConnection connection;

09 private SqlCommand command;

10 private SqlDataAdapter adapter;

11 public DataBaseHelper()

12 {

13   this.connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Database ConnectionString"].ConnectionString); //取得连接字符处 ;

14   this.command= new SqlCommand();

15   this.command.Connection= this.connection;

16   this.adapter= new SqlDataAdapter(command);

17 }

18

19 public int ExecuteNonQuery(string sql)

20  {

21  return this.ExecuteNonQuery(sql, new SqlParameter[0]);

22  }

23

24 public int ExecuteNonQuery(string sql,SqlParameter[]param)

25  {

26   this.command.CommandText= sql;

27   this.command.Parameters.Clear();

28   for (int i= 0; i<param.Length; i++)

29  {

30     if(param[i] != null)

31     this.command.Parameters.Add(param[i]);

32  }

33    int result= 0;

34   try

35  {

36    this.connection.Open();

37   result= this.command.ExecuteNonQuery();

38  }

39  catch (Exception ex)

40  {

41    throw ex;

42  }

43  finally

44  {

45    this.connection.Close();

46  }

47  return result ;

48  }

49

50 public DataTable Select(string sql,SqlParameter[]param)

51  {

52   this.command.CommandText= sql;

53   this.command.Parameters.Clear();

54   for (int i= 0; i<param.Length; i++)

55  {

56     if(param[i] != null)

57     this.command.Parameters.Add(param[i]);

58  }

59 DataTable dtData= new DataTable();

60   //连接数据库取得数据 ,出现异常则向上级抛出;

61   try

62  {

63    this.adapter.Fill(dtData);

64  }

65 catch (Exception ex)

66  {

67    throw ex;

68  }

69  return dtData;

70  }

71

72 public DataTable Select(String sql)

73  {

74  return this.Select(sql, new SqlParameter[0]);

75  }

76

77 public static SqlParameter[]AddParameter(SqlParameter[]paramArray,SqlParameter param)

78  {

79 Array.Resize<SqlParameter>(refparamArray,paramArray.Length+ 1);

80 paramArray[paramArray.Length - 1]=param;

81  return paramArray;

82  }

83 }

以后各页面调用的DataBaseHelper类皆为此类,后面不再赘述。

29.3.3 人员信息的维护

对录入的顾客信息,管理人员可进行删除等操作,以将无效用户从系统中清除,所以只需在人员列表中将要删除的用户名称取出,然后提交数据库进行删除即可。操作较为简单,我们重点学习一下GridView的扩展用法,注意绑定列BoundField与命令列CommandField的使用。下面建立UserManage页面,如图所示。

figure_0622_0982

前台页面使用了GridView列出用户,通过提交行删除事件,后台程序可对选中的行进行删除操作。后台.cs代码如下(代码29-3.txt)。

01 protected void Page_Load(object sender,EventArgs e)

02 {

03   if (!IsPostBack)

04  {

05 gvMemberBind();

06  }

07 }

08 public void gvMemberBind()

09 {

10 DataTable dt = new DataBaseHelper().Select("select * from [user] where role='0' order byname");

11 gvUser.DataSource=dt;

12 gvUser.DataBind();

13

14 }

15 protected void gvUser_PageIndexChanging(object sender,GridViewPageEventArgs e)

16 {

17 gvUser.PageIndex= e.NewPageIndex;

18 gvMemberBind();

19 }

20 protected void gvUser_RowDeleting(object sender,GridViewDeleteEventArgs e)

21 {

22 string name=gvUser.DataKeys[e.RowIndex].Value.ToString();

23 string sql="delete from [user]where name='"+name+"' ";

24   int i= new DataBaseHelper().ExecuteNonQuery(sql);

25   if (i== 1)

26  {

27 gvMemberBind();

28  }

29 }

29.3.4 商品呈现功能实现

我们采用DataList控件将查询得到的商品信息以直观的形式展示给顾客,这样可以方便商品图片的布局显示。大家要重点学习一下DataList与GridView有什么不同,在绑定数据时,DataList控件有什么灵活性。下面建立商品展示Default.aspx页面,如图所示。

figure_0623_0983

在前面的布局中我们设置了检索条件,下面展示商品信息,以满足顾客的购物需求,后台代码主要是根据传入的检索条件,进行商品的查询、数据的绑定,在这里大家可以看一下,是如何与DataList控件进行数据绑定的。后台代码如下(代码29-4.txt)。

01 private void query()

02 {

03

04 string sql="select top 20 * from Goods where 1=1 ";

05   if (!IsPostBack)

06  {

07    if (Request["Class"] != null&&Request["Class"].ToString().Trim().Length> 0)

08   {

09  sql+= "and class like'%"+Server.HtmlDecode(Request["Class"].ToString().Trim())+ "%' ";

10   }

11  }

12 else if (ddlKind.SelectedIndex> 0)

13  {

14  sql+= " and class like'%='"+ddlKind.SelectedValue.Trim()+ "%' ";

15  }

16   if(txtName.Text.Trim().Length>0)

17  {

18  sql+= " and name like '%"+ txtName.Text.Trim()+ "%' ";

19  }

20   if (txtPriceMin.Text.Trim().Length> 0)

21  {

22  sql+= " and price>="+ txtPriceMin.Text.Trim();

23  }

24   if (txtPriceMax.Text.Trim().Length> 0)

25  {

26  sql+= " and price<="+ txtPriceMax.Text.Trim();

27  }

28 sql+= " order by class,name ";

29 DataTable dt= new DataBaseHelper().Select(sql);

30 dlResult.DataSource=dt;

31 dlResult.DataBind();

32 }

29.3.5 购物车功能实现

本模块将检索到的要采购的商品,通过单击【购买】按钮,实现将此商品信息收集在本人的购物车中。前台页面即为商品呈现页面,只是在呈现每个商品的信息时,加载了购买事件。在事件被激发时,后台程序通过绑定信息,分析是购买的哪个商品,将此人的购买信息存到数据库的购物车表中,并以购物车的形式展现给顾客。实现代码如下(代码29-5.txt)。

01  //当购买商品时,获取商品信息

02 public OrderItem GetSubGoodsInformation(DataListCommandEventArgs e,DataList DLName)

03 {

04  //获取购物车中的信息

05 OrderItem Goods= new OrderItem();

06 Goods.ID=DLName.DataKeys[e.Item.ItemIndex].ToString();

07 string GoodsInfo= e.CommandArgument.ToString();

08 Goods.Price= float.Parse(GoodsInfo);

09  return (Goods);

10 }

11 public void AddShopCartItem(DataListCommandEventArgs e,DataList DLName)

12 {

13   if (Session["USERNAME"] != null)

14  {

15 OrderItem Goods= null;

16 Goods=GetSubGoodsInformation(e,DLName);

17    if (Goods== null)

18   {

19   //显示错误信息

20  Response.Write("<script>alert('没有可用的数据 ');location='index.aspx';< /script>");

21   return;

22   }

23  else

24   {

25    //取得当前购物车有无此已购商品

26   string sql ="select * from ShopCart where GoodsID=@GoodsID and UserName=@ UserName";

27  SqlParameter[]parameters={ newSqlParameter("@GoodsID",SqlDbType.Char, 14),

28  new SqlParameter("@UserName",SqlDb Type.Char, 50)};

29  parameters[0].Value=Goods.ID;

30  parameters[1].Value=Session["USERNAME"].ToString().Trim();

31     int i=new DataBaseHelper().Select(sql,parameters).Rows.Count;

32     if(i>0 )

33   {

34   sql=@"updateShopCart

35    set Num=(Num+1),

36 SumPrice=(SumPrice+@Price)

37   where GoodsID=@GoodsID and UserName=@UserName";

38   }

39  else

40   {

41   sql=@"Insert into ShopCart(GoodsID,Num,SumPrice,UserName)

42    values(@GoodsID,1,@Price,@UserName)";

43

44   }

45  SqlParameter[]parameters1={ new SqlParameter("@GoodsID",SqlDbType.Char, 14),

46  new SqlParameter("@Price",SqlDbType.Float, 8),

47  new SqlParameter("@UserName",SqlDbType.Char, 50)};

48

49  parameters1[0].Value=Goods.ID;

50  parameters1[1].Value=Goods.Price;

51  parameters1[2].Value=Session["USERNAME"].ToString().Trim();

52

53    //执行

54     int s= new DataBaseHelper().ExecuteNonQuery(sql,parameters1);

55     if (s> 0)

56   {

57  GlobleClass.PopInfo(this.Page, "恭喜您,添加成功! ");

58   }

59  else

60   {

61  GlobleClass.PopInfo(this.Page, "操作不成功! ");

62   }

63   }

64  }

65 else

66  {

67 GlobleClass.PopInfo(this.Page, "请先登录,谢谢! ");

68  }

69 }

需要注意的是,在添加购物信息时,一定要注意判断用户是否已登录,如果未登录要给以提醒登录,因为只有登录了,才知道商品是卖给哪位用户。购物结束,我们要能查看购物车的采购信息,并进行结账。为此在主页建立“我的购物车”链接,建立购物车页面,新建一个窗口文件“UserDetail. aspx”。前台模板内设计如图所示。

figure_0626_0984

后台读取绑定购物车的商品信息,并进行“结账”,即提交订单的操作。后台文件UserDetail.aspx. cs代码如下(代码29-6.txt)。

01 //<summary>

02 ///显示购物车中的信息

03 ///< /summary>

04 private void LoadShopCar()

05 {

06 string sql=@"select GoodsID,Name,Price,Num,SumPrice,UserName

07    from ShopCart S, Goods G where S.GoodsID=G.ID and UserName='" +Session["USERNAME"].ToString().Trim()+ "' ";

08 DataTable dt= new DataBaseHelper().Select(sql);

09 gvShopCart.DataSource=dt;

10 gvShopCart.DataBind();

11 }

12 ///<summary>

13 ///显示购物车中的商品合计金额

14 ///< /summary>

15 private void TotalDs()

16 {

17 string sql= "select Sum(SumPrice) from ShopCart "+

18     "where UserName='"+Session["USERNAME"].ToString().Trim()+ "' ";

19 DataTabledt= new DataBaseHelper().Select(sql);

20   if (dt.Rows.Count> 0)

21  {

22    lblTotal .Text=GlobleClass.VarStr(dt.Rows[0][0].ToString(), 2);

23  }

24 }

25 protected void gvShopCart_PageIndexChanging(object sender,GridViewPageEventArgs e)

26 {

27 gvShopCart.PageIndex= e.NewPageIndex;

28 LoadShopCar();

29 }

30 protected void gvShopCart_RowDeleting(object sender,GridViewDeleteEventArgs e)

31 {

32 string goodsID=gvShopCart.DataKeys[e.RowIndex]["GoodsID"].ToString();

33 string userName=gvShopCart.DataKeys[e.RowIndex]["UserName"].ToString();

34 string sql=@"delete from ShopCart

35  where UserName='"+userName+"' and GoodsID='"+goodsID+"' ";

36   int i= new DataBaseHelper().ExecuteNonQuery(sql);

37 LoadShopCar();

38 TotalDs();

39 }

40 protected void gvShopCart_RowCancelingEdit(object sender,GridViewCancelEditEventArgs e)

41 {

42 gvShopCart.EditIndex= -1;

43 LoadShopCar();

44 TotalDs();

45 }

46 protected void gvShopCart_RowUpdating(object sender,GridViewUpdateEventArgs e)

47 {

48 string goodsID=gvShopCart.DataKeys[e.RowIndex]["GoodsID"].ToString();

49 string userName=gvShopCart.DataKeys[e.RowIndex]["UserName"].ToString();

50 string num= ((TextBox)(gvShopCart.Rows[e.RowIndex].Cells[2].Controls[0])).Text.ToString();

51   if (GlobleClass.IsNumber(num)== true)

52  {

53  string sql=@"update ShopCart set Num="+ num+ ", "+

54      "SumPrice=("+ num+ "*(Select Price from Goods "+

55      "where ID='"+goodsID+ "')) "+

56     "where UserName='"+ userName+ "' and GoodsID='"+goodsID+ "'";

57    if (new DataBaseHelper().ExecuteNonQuery(sql)== 1)

58   {

59  gvShopCart.EditIndex= -1;

60  LoadShopCar();

61  TotalDs();

62   }

63  }

64 else

65  {

66 GlobleClass.PopInfo(this.Page, "请输入正确的物品数量! ");

67  }

68 }

69

70 protected void gvShopCart_RowEditing(object sender,GridViewEditEventArgs e)

71 {

72 gvShopCart.EditIndex= e.NewEditIndex;

73 LoadShopCar();

74 TotalDs();

75 }

<    >

76 protected void btnReckoning_Click(object sender,EventArgs e)

77 {

78 Response.Redirect("CheckOut.aspx?Total="+lblTotal.Text.Trim());

79 }

单击“结账”按钮的事件btnReckoning_Click,将会把购物信息以及收件人的地址电话等信息传到后台,生成订单,由卖家对订单进行发货等处理。

29.3.6 商品信息管理功能实现

商品信息管理将实现新商品的录入,并支持商品图片的上传,以及对系统内已有商品的修改和删除。通过本小节用户应学会简单的添加上传附件的功能,将文件图片上传到服务器并加以保存。要对商品进行管理,有必要做一个商品的查询功能,以方便查找要修改或删除的商品,为此新建Product窗口,在这里实现对已有商品的查询显示功能,如图所示。

figure_0629_0985

后台代码将按照前台设置的检索条件,进行数据库信息的查询,并将结果绑定到GridView控件上显示,同时进行商品的删除操作。后台代码如下(代码29-7.txt)。

01 ///<summary>

02 ///绑定商品的信息

03 ///< /summary>

04 public void gvBind()

05 {

06 string sql= "select * from Good swhere 1=1 ";

07   if (ddlKind.SelectedIndex> 0)

08  {

09  sql+= " and class='"+ddlKind.SelectedValue.Trim()+ "' ";

10  }

11   if (txtName.Text.Trim().Length> 0)

12  {

13  sql+= " and Name like '%"+ txtName.Text.Trim()+ "%' ";

14  }

15 sql+= " order by class,name ";

16 DataTable dt= new DataBaseHelper().Select(sql);

17

18 gvGoodsInfo.DataSource=dt;

19 gvGoodsInfo.DataBind();

20 }

21

22 protected void gvGoodsInfo_PageIndexChanging(object sender,GridViewPageEventArgs e)

23 {

24 gvGoodsInfo.PageIndex= e.NewPageIndex;

25 gvBind();

26 }

27

28 protected void gvGoodsInfo_RowDeleting(object sender,GridViewDeleteEventArgs e)

29 {

30 string ID=gvGoodsInfo.DataKeys[e.RowIndex].Value.ToString();

31 string sql= "delete fromgoodswhere id='"+ ID+ "' ";

32   int i= newDataBaseHelper().ExecuteNonQuery(sql);

33 gvBind();

34 }

35 protected void btnSearch_Click(object sender,EventArgs e)

36 {

37 gvBind();

38 }

39 protected void gvGoodsInfo_RowDataBound(object sender,GridViewRowEventArgs e)

40 {

41   if (e.Row.RowIndex>-1)

42  {

43  string id=gvGoodsInfo.DataKeys[e.Row.RowIndex]["ID"].ToString();

44  string myUrl= "EditProduct.aspx?ID="+ id;

45    ((HyperLink)e.Row.FindControl("hlDetail")).NavigateUrl = "javascript:OpenWindow('" +myUrl+ "')";

46

47  }

48 }

对于要修改或者新增加的商品,鉴于信息较多,大家要在这一小节中学会简单地添加附件功能。我们专门建立了一个商品信息窗口进行维护,商品信息维护窗口EditProduct如图所示。

figure_0630_0986

值得注意的是,为了增加代码的可重用性,我们在此将新增商品和修改已有商品做在了一个页面中,那么在保存商品信息时,就一定要区别,方法是通过判断窗口有无传入商品的ID信息,来作为是保存修改还是新增商品,为此一定要做好页面传入参数的判断。本页面用了一个HiddenField控件hdID来保存传入商品的ID,HiddenField控件常用来保存存储页面不可见的信息。后台代码如下(代码29-8.txt)。

01 protected void Page_Load(object sender,EventArgs e)

02 {

03 GlobleClass.ExecBeforPageLoad(this.Page);

04   if (!IsPostBack)

05  {

06    if (Request["ID"] != null&&Request["ID"].ToString().Trim().Length> 0)

07   {

08  hdID.Value=Request["ID"].ToString().Trim();

09  GetGoodsInfo(hdID.Value);

10   }

11  }

12 }

13 ///<summary>

14 ///获取指定商品的信息,并将其显示在界面上

15 ///< /summary>

16 public void GetGoodsInfo(string id)

17 {

18 string sql= "SELECT * FROM GOODSWHERE ID='"+id+"' ";

19 DataTable dt= new DataBaseHelper().Select(sql);

20   if (dt.Rows.Count> 0)

21  {

22   txtName.Text=dt.Rows[0]["NAME"].ToString();

23 ddlKind.SelectedValue=dt.Rows[0]["CLASS"].ToString();

24   txtUnit.Text=dt.Rows[0]["UNIT"].ToString();

25   txtPrice.Text=GlobleClass.VarStr(dt.Rows[0]["Price"].ToString(), 2);

26  hdImageUrl.Value=dt.Rows[0]["ImageUrl"].ToString();

27   ImageMapPhoto.ImageUrl=dt.Rows[0]["ImageUrl"].ToString();

28   txtShortDesc.Text=dt.Rows[0]["Introduce"].ToString();

29  }

30 }

31 protected void btnUpdate_Click(object sender,EventArgs e)

32 {

33   if (txtName.Text== "" || txtUnit.Text== "" || txtPrice.Text== "" ||ddlKind.SelectedIndex==0)

34  {

35 GlobleClass.PopInfo(this.Page, "请输入必要的信息! ");

36  }

37 else if (GlobleClass.IsNumber(txtPrice.Text.Trim())== false)

38  {

39 GlobleClass.PopInfo("<script>alert('请输入正确价格(格式:1.00)! ");

40  }

41 else

42  {

43  string sql= "";

44    if (hdID.Value.Trim().Length> 0)

45   {

46  sql=@"update Goods

47    set Class=@Class,

48   Name=@Name,

49        Introduce=@Introduce,

50   Unit=@Unit,

51        ImageUrl=@ImageUrl,

52    Price=@Price

53   where ID=@ID";

54   }

55  else

56   {

57  sql=@"insert Goods

58      (Class,Name,Introduce,Unit,ImageUrl,Price,ID)

59   values(@Class,@Name,@Introduce,@Unit,@ImageUrl,@Price,@ID)";

60   }

61 SqlParameter[]Parameters= newSqlParameter[7];

62 SqlParameter ClassID= new SqlParameter("@Class",SqlDbType.VarChar, 50);

63 ClassID.Value=ddlKind.SelectedValue;

64 Parameters[0]=ClassID;

65 SqlParameter name= new SqlParameter("@Name",SqlDbType.VarChar, 50);

66  name.Value= txtName.Text.Trim();

67 Parameters[1]= name;

68 SqlParameter GoodsIntroduce= new SqlParameter("@Introduce",SqlDbType.NText, 16);

69 GoodsIntroduce.Value= txtShortDesc.Text.Trim();

70 Parameters[2]=GoodsIntroduce;

71 SqlParameter GoodsUnit= new SqlParameter("@Unit",SqlDbType.VarChar, 10);

72 GoodsUnit.Value= txtUnit.Text.Trim();

73 Parameters[3]=GoodsUnit;

74 SqlParameter GoodsUrl= new SqlParameter("@ImageUrl",SqlDbType.VarChar, 50);

75 GoodsUrl.Value= hdImageUrl.Value.Trim();

76 Parameters[4]=GoodsUrl;

77 SqlParameter MarketPrice= new SqlParameter("@Price",SqlDbType.Float, 8);

78 MarketPrice.Value= txtPrice.Text.Trim();

79 Parameters[5]=MarketPrice;

80 SqlParameter ID= new SqlParameter("@ID",SqlDbType.BigInt, 8);

81    if (hdID.Value.Trim().Length> 0)

82   {

83    ID.Value= hdID.Value;

84   }

85  else

86   {

87    ID.Value=System.DateTime.Now.ToString("yyyyMMddHHmm");

88   }

89 Parameters[6]= ID;

90   //执行

91    int i= new DataBaseHelper().ExecuteNonQuery(sql,Parameters);

92    if (i== 1)

93   {

94  GlobleClass.PopInfo(this.Page, "操作成功! ");

95   }

96  }

97 }

98 protected void UploadImage_OnClick(object sender,EventArgs e)

99 {

100  try

101  {

102    if (imageUpload.PostedFile.FileName== "")

103   {

104  GlobleClass.PopInfo(this.Page, "要上传的文件不允许为空! ");

105   return;

106   }

107  else

108   {

109  string filePath= imageUpload.PostedFile.FileName;

110  string filename= filePath.Substring(filePath.LastIndexOf("\\")+ 1);

111  string fileSn=System.DateTime.Now.ToString("yyyyMMddHHmmssfff");

112   string serverpath = Server.MapPath(@"~\Images\Goods\") + fileSn + filename.Substring(filename.LastIndexOf("."));

113   string relativepath =@"~\Images\Goods\" + fileSn + filename.Substring(filename.LastIndexOf("."));

119     imageUpload.PostedFile.SaveAs(serverpath);

115  hdImageUrl.Value= relativepath;

116    ImageMapPhoto.ImageUrl= relativepath;

117   }

118  }

119 catch (Exception error)

120  {

121 GlobleClass.PopInfo(this.Page,"处理发生错误!原因:"+ error.ToString());

122  }

123 }

124 protected void btnNew_Click(object sender,EventArgs e)

125 {

126 hdID.Value= "";

127  txtName.Text= "";

128  txtUnit.Text= "";

129  txtPrice.Text= "";

120  txtShortDesc.Text= "";

121 hdImageUrl.Value= "";

122 }

29.3.7 订单信息管理功能实现

订单信息管理,将实现对客户提交到系统内的已有订单进行查询和处理的功能,我们在本小节还要学习简单的票据打印功能。

程序要人性化设计,查询订单要符合实际业务需要,这就要提供按客户查询和按订单信息查询等多种检索条件,以方便查找需要处理的订单。为此新建了一个OrderList窗口,在这里实现对已有订单的查询,显示各个订单当前处理状态,如图所示。

figure_0634_0987

在这里我们仍然使用了GridView作为数据显示的控件,对于规整的二维表格式数据,GridView确实是一个很好的控件。下面看一下后台代码,是如何查询订单数据,并绑定到GridView控件显示的。很简单,代码如下(代码29-9.txt)。

01 //绑定总金额

02 public string GetVarTP(string strTotalPrice)

03 {

04  return GlobleClass.VarStr(strTotalPrice, 2);

05 }

06 ///<summary>

07 ///获取符合条件的订单信息

08 ///< /summary>

09 public void pageBind()

10 {

11 string sql= "select * from [Order]where 1=1 ";

12

13   if (txtKeyword.Text.Trim().Length> 0)

14  {

15    if (ddlKeyType.SelectedIndex== 0)

16   {

17  sql+= " and ORDERID='"+ txtKeyword.Text.Trim()+ "' ";

18   }

19  else if (ddlKeyType.SelectedIndex== 1)

20   {

21  sql+= " andUserName='"+ txtKeyword.Text.Trim()+ "' ";

22   }

23  }

24   if (ddlState.SelectedIndex> 0)

25  {

26  sql+= " and state='"+ddlState.SelectedValue.Trim()+ "' ";

27  }

28 sql+= " order by orderdate desc ";

29 DataTable dt= new DataBaseHelper().Select(sql);

30

31 gvOrderList.DataSource=dt;

32 gvOrderList.DataBind();

33 }

34

35 protected void gvOrderList_PageIndexChanging(object sender,GridViewPageEventArgs e)

36 {

37 gvOrderList.PageIndex= e.NewPageIndex;

38 pageBind();

39 }

40 protected void btnSearch_Click(object sender,EventArgs e)

41 {

42 pageBind();

43 }

44 protected void gvOrderList_RowDeleting(object sender,GridViewDeleteEventArgs e)

45 {

46 string orderID=gvOrderList.DataKeys[e.RowIndex].Value.ToString();

47 string sql= "delete * from [Order]where ORDERID='"+ txtKeyword.Text.Trim()+ "' ";

48   int i= new DataBaseHelper().ExecuteNonQuery(sql);

49 pageBind();

50

51 }

到这一步,我们通过检索找到了要处理的订单,如何处理呢?首先要能看到订单的详细信息,比如订单里都订购了哪些商品,数量和价格是多少。为此新建一个订单明细窗口OrderModify,在这个窗口中将显示上一步检索到的订单的详细信息,并能够对订单进行处理,即修改订单的执行状态,如图所示。

figure_0636_0988

前台页面为了打印时页面美观,进行了平铺式的布局,通过调用Windows的打印程序,实现了本小节要学习的打印功能,页面后台代码如下(代码29-10.txt)。

01 public OrderInfo order= new OrderInfo();

02 protected void Page_Load(object sender,EventArgs e)

03 {

04   if (!IsPostBack)

05  {

06  order=GetOrderInformation();

07 OrderItemBind();

08  }

09 }

10

11 private void OrderItemBind()

12 {

13 string sql=@"select GoodsID,Name,Price,Num,SumPrice,UserName

14     from OrderItem S,GoodsG

15  where S.GoodsID=G.ID and s.orderid='"+Request["OrderID"].ToString().Trim()+"' ";

16 DataTable dt= new DataBaseHelper().Select(sql);

17  rptOrderItems.DataSource=dt;

18  rptOrderItems.DataBind();

19 }

20 ///<summary>

21 ///获取指定订单信息

22 ///< /summary>

23 ///<returns>返回OrderInfo类的实例对像< /returns>

24 public OrderInfo GetOrderInformation()

25 {

26 OrderInfo order= new OrderInfo();

27  //获取订单基本信息

28 DataTable dt = new DataBaseHelper().Select( "select * from [Order]where ORDERID='" +Request["OrderID"].ToString().Trim()+ "' ");

29   if(dt.Rows.Count>0)

30  {

31 DataRow dr=dt.Rows[0];

32  order.OrderNo=dr["ORDERID"].ToString();

33  order.OrderTime=Convert.ToDateTime(dr["orderdate"].ToString());

34  order.TotalPrice= float.Parse(dr["TotalPrice"].ToString());

35  order.ReceiverName=dr["ReceiverName"].ToString();

36  order.ReceiverPhone=dr["ReceiverPhone"].ToString();

37  order.ReceiverPostalcode=dr["ReceiverPostCode"].ToString();

38  order.ReceiverAddress=dr["ReceiverAddress"].ToString();

39  order.State=dr["State"].ToString();

40    lblState.Text=dr["State"].ToString();

41   //ddlState.SelectedValue=dr["State"].ToString();

42  }

43  //获取订单购买人信息

44 DataTable dtBuyer= new DataBaseHelper().Select("select [User].* from [Order] INNER JOIN "+

45   "[USER] ON [Order].UserName = [USER].Name where [Order].ORDERID='" +Request["OrderID"].ToString().Trim()+ "' ");

46   if (dt.Rows.Count> 0)

47  {

48 DataRow drBuyer=dtBuyer.Rows[0];

49  order.BuyerEmail=drBuyer["Emails"].ToString();

50  order.BuyerName=drBuyer["Name"].ToString();

51  order.BuyerPhone=drBuyer["Phonecode"].ToString();

52  }

53  return (order);

54 }

55

56 protected void btnSave_Click(object sender,EventArgs e)

57 {

58   if(ddlState.SelectedIndex>0)

59  {

60  string sql = "update [order] set state='" + ddlState.SelectedValue.Trim() + "' where OrderID='"+Request["OrderID"].ToString().Trim()+ "' ";

61    int i= new DataBaseHelper().ExecuteNonQuery(sql);

62    if (i== 1)

63   {

64 GlobleClass.PopInfo(this.Page, "修改成功,订单状态变更为:"+ddlState.SelectedValue.Trim());

65  order=GetOrderInformation();

66   }

67  }

68 }

在本次窗口代码中,大家有没有发现在绑定显示数据时有什么不同?除了直接将后台变量的值直接输出到前台显示,更关键的是不是多了一个对象order ?这就是我们在项目开发初期介绍的OrderInfo类的对象实例。在这个页面我们对它进行了初始化,赋值和前台输出绑定,希望大家仔细研究,对将某些事物的基本信息封装的好处多加体会。

到本节为止,我们已经将B2C网上购物系统从顾客注册与登录、商品呈现、购物车、商品管理,一直到订单管理等最基本的流程实现了。在项目实现的过程中,用到了最常用的Web服务器控件的用法,相信大家对GridView显示二维表数据、在DataList里定义Tale表灵活展示数据、图片附件上传至服务器、简单打印订单等功能都有了一定的了解,更重要的是对.Net进行Web系统开发的流程有了一个完整的认识。

29.4 系统运行

本节视频教学录像:6分钟

系统设计开发完成后,现在就将商品展示页Default页设为起始页,来看看系统的运行效果。按【F5】键调试运行,会在浏览器中打开系统的默认页面,本系统默认为登录页面。

29.4.1 普通用户登录

⑴在左侧登录窗口中单击【注册】按钮,填写注册信息(如用户名为123456,密码为123456),完成后单击【提交】按钮,提示“添加成功”。

figure_0638_0989

⑵使用注册的信息登录,即可登录网站,可以购买本站中的商品。

⑶单击商品的【详细】链接可查看到商品明细信息。

figure_0638_0990

⑷单击商品的【购买】链接,即可提示“恭喜你,添加成功!”,购买完成,单击【我的购物车】,即可查看所购买的商品,并且可以结账,结账后会生成订单,购物车内的物品自动清空。

figure_0638_0991
figure_0638_0992

29.4.2 管理员登录

⑴使用管理员的用户名“admin”、密码“000”登录本站,系统会自动转到网站管理的界面。

⑵在管理界面中,管理员可以实现订单管理、商品管理以及人员管理等。

figure_0639_0993
figure_0639_0994

29.5 开发过程中的常见问题及解决方式

本节视频教学录像:2分钟

本章主要通过一个不太复杂的综合范例——B2C网上购物系统的开发,具体讲解了如果开发一个.NET Web网站,包括开发的流程和一些开发技巧。

如果你是初次开发这样的综合性程序,在开发过程中,你肯定会遇到这样或者那样的问题,不要急于求成,要按照软件设计的原理一步步完成。

⑴明确系统的需求,做到有的放矢。

⑵讨论、思考系统的总体框架,在此基础上完成各部门功能模块的框架。

⑶建立合理高效的数据库,尽可能做到满足现有功能,还能进行下一步扩展的需求。

⑷编写代码,运行调试,逐渐完善。

⑸总结开发过程当中遇到的问题和解决的方法,为以后的编程提供宝贵的经验。

注意

更改数据库地址、名称或SQL Server 2008的登录名和密码后,对Web.config文件的<connectionStrings>标签对中的连接字符串,需改成新数据库的地址名称及账号和密码。

教程类别