Ngày nay, việc mua hàng qua website đã trở nên quen thuộc với nhiều người và nó mang lại một thị trường mở cho các nhà kinh doanh. Để khách hàng có thể mua hàng qua website của mình, thì họ cần phải xây dựng một website thương mại điện tử. Với vai trò là một lập trình viên, bạn thường xuyên gặp phải bài toán giỏ hàng trong những dự án ấy. Đây là một trong những nghiệp vụ quan trọng bậc nhất với những website thương mại điện tử.
Để hiểu về giỏ hàng thì chúng ta hãy tưởng tượng chúng ta đang đi siêu thị nhé. Việc đầu tiên khi bạn vào siêu thị là bạn làm gì? Tôi chắc rằng bạn sẽ cần tới một chiếc xe đẩy để chở hàng, hay một cái giỏ để đựng hàng, tôi xin tạm gọi hai thứ đó là “giỏ hàng”. Công việc tiếp theo là lựa chọn sản phẩm để mua, bạn có thể nhặt sản phẩm định mua, đưa vào giỏ hàng, mua bao nhiêu sản phẩm thì bạn nhặt bấy nhiêu. Sau khi nhặt một hồi, bạn có thể thay đổi ý định, bỏ bớt một số sản phẩm, hoặc giảm hoặc tăng số lượng sản phẩm mình mua trong giỏ hàng. Những sản phẩm trong giỏ hàng là những sản phẩm bạn chọn để mua, và nó chỉ có tính chất lưu trữ tạm thời trước khi thanh toán. Tức là, khi bạn thanh toán xong giỏ hàng lại trở về trạng thái rỗng.
Câu chuyện về giỏ hàng trong website thương mại điện tử, nó cũng giống như chiếc xe đẩy chở hàng trong siêu thị. Tức là, bạn phải làm sao cho người dùng lựa chọn được sản phẩm, đưa vào giỏ hàng, thay đổi số lượng sản phẩm, xóa sản phẩm trong giỏ hàng. Và bạn nhớ rằng giỏ hàng chỉ là nơi lưu trữ tạm thời các sản phẩm mà bạn cần mua trước khi thanh toán.
Tôi thấy có khá nhiều bạn sinh viên đau đầu với bài toán kinh điển này. Để giúp các bạn bớt đau đầu, tôi sẽ hướng dẫn các bạn những thao tác cơ bản để xây dựng được giỏ hàng trong ASP.NET.
Để tạo ra được giỏ hàng, chúng ta cần có 3 class cơ bản là ShoppingCart, CartItem, Product được mô tả như class diagram ở dưới đây.
Bước 1: Tạo Class ShoppingCart
Chúng ta cần một nơi để lưu trữ trữ các mục (item) trong giỏ hàng cũng như cung cấp chức năng để thao tác với những phần tử đó. Chúng ta sẽ tạo ra một class để làm được việc này. Class này sẽ quản lý việc lưu trữ session (phiên làm việc).
Đầu tiên, chúng ta phải tạo ra thư mục App_Code. Để làm được việc này, vào menu “Website”, sau đó chọn “Add ASP.NET Folder”, rồi chọn “App_Code”. Đây chính là nơi chúng ta đặt toàn bộ class do mình viết ra. Từ bất kỳ trang web nào cũng có thể truy cập tới code trong App_Code (chúng ta không cần phải tham chiếu tới nó bằng cách sử dụng những lệnh kiểu như “include” hay bất cứ cái gì). Sau đó, chúng ta có thể thêm class vào thư mục này bằng cách kích chuột phải vào folder rồi chọn “Add New Item”.
Mẹo nhanh: Regions (Khu vực) trong ASP.NET thực sự là một điều tuyệt vời để tổ chức và nhóm code lại với nhau. Điều tốt đẹp nhất về chúng là bạn có thể mở và đóng các khu vực để thu gọn số lượng mã mà bạn đang tìm kiếm hoặc nhanh chóng tìm thấy theo cách của bạn xung quanh một tập tin.
Đây là code của ShoppingCart
[sourcecode language=”csharp”]
using System.Collections.Generic;
using System.Web;
/**
* The ShoppingCart class
*
* Holds the items that are in the cart and provides methods for their manipulation
*/
public class ShoppingCart {
#region Properties
public List Items { get; private set; }
#endregion
#region Singleton Implementation
// Readonly properties can only be set in initialization or in a constructor
public static readonly ShoppingCart Instance;
// The static constructor is called as soon as the class is loaded into memory
static ShoppingCart() {
// If the cart is not in the session, create one and put it there
// Otherwise, get it from the session
if (HttpContext.Current.Session["ASPNETShoppingCart"] == null) {
Instance = new ShoppingCart();
Instance.Items = new List();
HttpContext.Current.Session["ASPNETShoppingCart"] = Instance;
} else {
Instance = (ShoppingCart)HttpContext.Current.Session["ASPNETShoppingCart"];
}
}
// A protected constructor ensures that an object can’t be created from outside
protected ShoppingCart() { }
#endregion
#region Item Modification Methods
/**
* AddItem() – Adds an item to the shopping
*/
public void AddItem(int productId) {
// Create a new item to add to the cart
CartItem newItem = new CartItem(productId);
// If this item already exists in our list of items, increase the quantity
// Otherwise, add the new item to the list
if (Items.Contains(newItem)) {
foreach (CartItem item in Items) {
if (item.Equals(newItem)) {
item.Quantity++;
return;
}
}
} else {
newItem.Quantity = 1;
Items.Add(newItem);
}
}
/**
* SetItemQuantity() – Changes the quantity of an item in the cart
*/
public void SetItemQuantity(int productId, int quantity) {
// If we are setting the quantity to 0, remove the item entirely
if (quantity == 0) {
RemoveItem(productId);
return;
}
// Find the item and update the quantity
CartItem updatedItem = new CartItem(productId);
foreach (CartItem item in Items) {
if (item.Equals(updatedItem)) {
item.Quantity = quantity;
return;
}
}
}
/**
* RemoveItem() – Removes an item from the shopping cart
*/
public void RemoveItem(int productId) {
CartItem removedItem = new CartItem(productId);
Items.Remove(removedItem);
}
#endregion
#region Reporting Methods
/**
* GetSubTotal() – returns the total price of all of the items
* before tax, shipping, etc.
*/
public decimal GetSubTotal() {
decimal subTotal = 0;
foreach (CartItem item in Items)
subTotal += item.TotalPrice;
return subTotal;
}
#endregion
}
[/sourcecode]
Bước 2: Tạo class CartItem và Product
Bên cạnh việc tạo ra một nơi để lưu trữ các phần tử, chúng ta cũng cần tạo ra nơi để lưu trữ thông tin về mỗi mục (item). Chúng ta sẽ tạo ra class CartItem để làm việc này. Chúng ta cũng sẽ tạo ra một class Product đơn giản, nó sẽ chứa thông tin cơ bản về sản phẩm chúng ta đang bán.
Đây là CartItem class
[sourcecode language=”csharp”]
using System;
/**
* The CartItem Class
*
* Basically a structure for holding item data
*/
public class CartItem : IEquatable<CartItem> {
#region Properties
// A place to store the quantity in the cart
// This property has an implicit getter and setter.
public int Quantity { get; set; }
private int _productId;
public int ProductId {
get { return _productId; }
set {
// To ensure that the Prod object will be re-created
_product = null;
_productId = value;
}
}
private Product _product = null;
public Product Prod {
get {
// Lazy initialization – the object won’t be created until it is needed
if (_product == null) {
_product = new Product(ProductId);
}
return _product;
}
}
public string Description {
get { return Prod.Description; }
}
public decimal UnitPrice {
get { return Prod.Price; }
}
public decimal TotalPrice {
get { return UnitPrice * Quantity; }
}
#endregion
// CartItem constructor just needs a productId
public CartItem(int productId) {
this.ProductId = productId;
}
/**
* Equals() – Needed to implement the IEquatable interface
* Tests whether or not this item is equal to the parameter
* This method is called by the Contains() method in the List class
* We used this Contains() method in the ShoppingCart AddItem() method
*/
public bool Equals(CartItem item) {
return item.ProductId == this.ProductId;
}
}
[/sourcecode]
Đây là Product class
[sourcecode language=”csharp”]
/**
* The Product class
*
* This is just to simulate some way of accessing data about our products
*/
public class Product
{
public int Id { get; set; }
public decimal Price { get; set; }
public string Description { get; set; }
public Product(int id)
{
this.Id = id;
switch (id) {
case 1:
this.Price = 19.95m;
this.Description = "Shoes";
break;
case 2:
this.Price = 9.95m;
this.Description = "Shirt";
break;
case 3:
this.Price = 14.95m;
this.Description = "Pants";
break;
}
}
}
[/sourcecode]
Một “property” (thuộc tính) là một biến trong một class mà nó kèm theo setter, getter hoặc cả hai. Trong class Product chúng ta khai báo các thuộc tính của sản phẩm thông qua các property: Id, Price, Description. Ngoài ra, class Product còn khởi tạo một vài sản phẩm (3 sản phẩm) để chúng ta dễ dàng kiểm tra phần giỏ hàng.
Bước 3: Thêm vào giỏ hàng
Sau khi code rất nhiều, giờ là lúc chúng ta làm cái gì đó thật trực quan. Chúng ta sẽ tạo ra một page đơn giản để thêm các mục vào trong giỏ hàng. Tất cả, chúng ta có một vài mục cùng với link “Add to Cart” . Nào chúng ta hãy cùng code trang Default.aspx.
Đây phần design của trang Default.aspx
[sourcecode language=”html”]
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>My Store</title>
<link href="Styles/StyleSheet.css" rel="stylesheet" type="text/css" />
</head>
<body>
<form id="form1" runat="server">
<div class="container">
<h1>My Store</h1>
<div class="products">
<div>Shoes – <asp:LinkButton runat="server" ID="btnAddShirt" OnClick="btnAddShoes_Click">Add To Cart</asp:LinkButton></div>
<div>Shirt – <asp:LinkButton runat="server" ID="btnAddShorts" OnClick="btnAddShirt_Click">Add To Cart</asp:LinkButton></div>
<div>Pants – <asp:LinkButton runat="server" ID="btnAddShoes" OnClick="btnAddPants_Click">Add To Cart</asp:LinkButton></div>
</div>
<a href="ViewCart.aspx">View Cart</a>
</div>
</form>
</body>
</html>
[/sourcecode]
Còn đây là phần code behind để xử lý các sự kiện Default.aspx.cs
[sourcecode language=”csharp”]
using System;
public partial class _Default : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e) {
}
protected void btnAddShoes_Click(object sender, EventArgs e) {
// Add product 1 to the shopping cart
ShoppingCart.Instance.AddItem(1);
// Redirect the user to view their shopping cart
Response.Redirect("ViewCart.aspx");
}
protected void btnAddShirt_Click(object sender, EventArgs e) {
ShoppingCart.Instance.AddItem(2);
Response.Redirect("ViewCart.aspx");
}
protected void btnAddPants_Click(object sender, EventArgs e) {
ShoppingCart.Instance.AddItem(3);
Response.Redirect("ViewCart.aspx");
}
}
[/sourcecode]
Bước 4: Hiển thị giỏ hàng
Tất cả những gì chúng ta làm ở trên chỉ là để chuẩn bị cho shopping cart! Giờ chúng ta hãy nhìn trang ViewCart.aspx.
Đây là code của trang ViewCart.aspx. Về cơ bản chúng ta sẽ sử dụng GridView để hiển thị thông tin trong giỏ hàng. Cột Description trong GridView chúng ta sẽ sử dụng BoundFiled. Còn cột Quantity chứa số lượng sản phẩm sẽ mua, ta cần sử dụng TemplateFiled, để có thể đưa TextBox và link Remove luôn vào đó. Để hiển thị thông tin như Price, Description …. trên GridView chúng ta cần dùng tới <%# Eval("PropertyName") %>.
Chi tiết code của ViewCart.aspx ở đây
[sourcecode language=”html”]
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="ViewCart.aspx.cs" Inherits="ViewCart" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Shopping Cart</title>
<link href="Styles/StyleSheet.css" rel="stylesheet" type="text/css" />
</head>
<body>
<form id="form1" runat="server">
<div class="container">
<h1>Shopping Cart</h1>
<a href="Default.aspx">< Back to Products</a>
<br /><br />
<asp:GridView runat="server" ID="gvShoppingCart" AutoGenerateColumns="false" EmptyDataText="There is nothing in your shopping cart." GridLines="None" Width="100%" CellPadding="5" ShowFooter="true" DataKeyNames="ProductId" OnRowDataBound="gvShoppingCart_RowDataBound" OnRowCommand="gvShoppingCart_RowCommand">
<HeaderStyle HorizontalAlign="Left" BackColor="#3D7169" ForeColor="#FFFFFF" />
<FooterStyle HorizontalAlign="Right" BackColor="#6C6B66" ForeColor="#FFFFFF" />
<AlternatingRowStyle BackColor="#F8F8F8" />
<Columns>
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="Quantity">
<ItemTemplate>
<asp:TextBox runat="server" ID="txtQuantity" Columns="5" Text='<%# Eval("Quantity") %>’></asp:TextBox><br />
<asp:LinkButton runat="server" ID="btnRemove" Text="Remove" CommandName="Remove" CommandArgument='<%# Eval("ProductId") %>’ style="font-size:12px;"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="UnitPrice" HeaderText="Price" ItemStyle-HorizontalAlign="Right" HeaderStyle-HorizontalAlign="Right" DataFormatString="{0:C}" />
<asp:BoundField DataField="TotalPrice" HeaderText="Total" ItemStyle-HorizontalAlign="Right" HeaderStyle-HorizontalAlign="Right" DataFormatString="{0:C}" />
</Columns>
</asp:GridView>
<br />
<asp:Button runat="server" ID="btnUpdateCart" Text="Update Cart" OnClick="btnUpdateCart_Click" />
</div>
</form>
</body>
</html>
[/sourcecode]
Kết quả
Bây giờ, chúng ta đã có một shopping cart khá là đẹp mắt !
Bài này mới chỉ dừng lại ở việc hướng dẫn bạn xây dựng giỏ hàng bằng ASP.NET sử dụng C#, nhưng từ đây bạn hoàn toàn có thể thể triển khai cách làm này với các ngôn ngữ khác. Chúc bạn thành công với những website thương mại điện tử của mình !
Download SourceCode Demo
Bài viết có tham khảo thông tin của net.tutspluts.com
Đặng Kim Thi
Download SourceCode Demo bị lỗi rồi thầy ah..
Done rùi em nhé 🙂
Em hơi thắc mắc về cái IEquatable ! cố có thể giải thích giúp em được không ạ ? IEquatable là j ạ ? và khi nào thì dùng nó ? Em xin cảm ơn !
Nó dùng để so sánh đối tượng bạn ạ. Liên quan tới đoạn code sau
45 /**
46 * Equals() – Needed to implement the IEquatable interface
47 * Tests whether or not this item is equal to the parameter
48 * This method is called by the Contains() method in the List class
49 * We used this Contains() method in the ShoppingCart AddItem() method
50 */
51 public bool Equals(CartItem item) {
52 return item.ProductId == this.ProductId;
53 }
Tham khảo thêm: http://broadcast.oreilly.com/2010/09/understanding-c-equality-iequa.html
Cái dòng Total ở dưới footer làm sao vậy thầy?
Mình không hiểu ý bạn tinhoc31
Dòng đó để hiển thị tổng tiền (Total) của giỏ hàng./
thầy ơi nó ko hiểu cái List trong ShoppingCart là cái gì thầy ạ
Bạn trình bày rõ hơn được không?
Nó ở đây là cái gì hả bạn?
vay co tao class listview không,
demo ma ko co file nguon solution (.sln) thì chạy = nt à
Đây là website mà bạn hiền, bạn vào File –> Open –> Web site rồi chọn đến folder.
Hoặc nhấn tổ hợp phím Shift + Alt + O
Anh nên giải thích trong mã nguồn bằng tiếng việt cho dễ hiểu cảm ơn anh về bài viết.
ok Cuong. Thanks bạn 🙂
// Readonly properties can only be set in initialization or in a constructor
public static readonly ShoppingCart Instance;
// The static constructor is called as soon as the class is loaded into memory
Nếu khai báo biến là public thì dữ liệu sẽ dùng chung cho tất cả các user truy cập vào trang .
em thắc mắc là làm thế nào để mỗi khi add 1 new CartItem vào cái gridView thì lại có cái nút remove+field quantity, và làm thế nào cái nút remove nó biết nó sẽ xóa cái Item nào???
em hiểu hết bài này rồi, cám ơn thầy!
neu dua du lieu tu co so du lieu SQL len thi lam sao vay ? . mong giup ho em cai em co 1 co so du lieu do len datalist, co nut mua hang khi click vao thi no k + vao ben gio hang mong giup e voi.
2 khách hàng khác nhau , có giỏ hàng giống nhau. Người này add cái gì người kia có cái đó.. Lỗi ?
khách hàng khác đăng nhập thì phải xóa session của khách hàng trước đi chứ!
tớ được biết thì session được lưu trên bộ nhớ của server và k được truyền cho client mỗi 1 client đăng nhập sẽ có 1 session với id riêng. Vì thế sẽ không có chuyện đó xảy ra…
Thân!
bạn nói không sai, đúng là session được lưu trên bộ nhớ server, rõ ràng là giỏ hàng này được lưu trên session đúng không? giả sử tên session lưu giỏ hàng này là :”ShoppingCard”
và bạn đang test bài này trên cùng một máy+ một server + một trình duyệt , khi bạn Logout để cho khách hàng khác đăng nhập mà bạn không cho cái Session[“ShoppingCard”] = null;
thì xin thưa là cả ngàn khách hàng nó vẫn có cái giỏ hàng giống nhau mà thôi.
Giỏ hàng này lỗi trầm trọng
bạn gặp lỗi gì vậy bạn? mình thấy giỏ hàng code kiểu này là quá ok, mình chạy cũng ok.
Ừm có 1 lỗi nho nhỏ xinh xinh là (số âm) :))) bạn nào dùng nhớ bắt cái thằng số âm k lại hối hận..
minh co cau hoi nay mong ban tra loi giup: Neu cac gio hang thuong mai dien tu?
Thầy ơi, nếu như client1 lên đặt 1 món, và client2 lên đặt 2 món thì nó sẽ bị lỗi là sẽ có 3 món trong giỏ hàng luôn, nó không biết user nào và nó chỉ gom hết vô chung 1 giỏ hàng, dù trong giỏ hàng đó người thì 1 món người thì 2 món, vậy fix sao đây thầy