1.1. Mục đích
Xây dựng website “Đấu giá trực tuyến” đáp ứng nhu cầu cần có một trang đấu giá trực tuyến hoạt động hiệu quả, ổn định với hình thức đấu giá mới lạ và thú vị. 1.2. Yêu cầu - Hệ thống hoạt động nhanh, ổn định. - Đáp ứng phục vụ số lượng người dùng lớn. II. Phân tích chức năng 2.1. Các chức năng chính 2.1.1. BackEnd
Phần BackEnd sẽ quản trị toàn bộ website Đấu giá trực tuyến. Nó bao gồm các nghiệp vụ sau:
- Quản lý sản phẩm: Bao gồm việc thêm mới, sửa, xóa sản phẩm sẽ tham gia đấu giá.
uc ProductMgmt ProductMgmt (from Login) Login AddProduct EditProduct DelProduct DisplayProduct
(from Use Case Model)
Validate Auction Manager (from Actors) SearchProduct «extend» «include» «extend» «include» «extend» «include» «extend» «include» «include»
- Quản lý đấu giá: Bao gồm việc tạo mới, cập nhật một phiên đấu giá.
uc AutionsMgmt AutionsMgmt AddAutions EditAutions DeleteAutions DisplayAutions
Auction Manager Site
(from Actors) (from Login) Login «include» «include» «extend» «extend» «extend»
- Quản lý người dùng: Bao gồm việc thêm mới, cập nhật, phân quyền cho user.
uc AccountMgmtByAdmin Admin (from Actors) (from Login) Login AccountMgmt DeleteAccount DeleteAccountRole InsertAccount InsertAccountRole SelectAccountByName SelectAccountRole UpdateAccount UpdateAccountRole
(from Use Case Model)
Validate DisplayAccount «extend» «include» «include» «extend» «include» «include» «extend» «include» «extend» «include» «extend» «include» «extend» «include» «extend» «include» «extend» «extend»
- Báo cáo, thống kê 2.1.2. FrontEnd
Phần FrontEnd sẽ tương tác trực tiếp với người dùng, thực hiện các chức năng:
uc Auctions User (from Actors) Auctions (from Login) Login BidAgent BidSingle DisplayProductInterest DisplayWiner DisplayHistory DislayAccountConsulting DisplayProductAuctionEndSoon DisplayCategory «include» «extend» «include» «extend» «extend» «include» «include» «include» «include» «include» «include»
uc Product User (from Actors) DisplayProductDetail DisplayHistory ProductDetail BidSingle BidAgent (from Login) Login BuyProduct SendToFriend AddToProductInterest «extend» «extend» «include» «include» «include» «extend» «extend» «include» «extend» «include» «extend» - Xử lý sự kiện đặt bid.
uc Account User (from Actors) AccountMgmt (from Login) Login DisplayProfiles EditProfiles DisplayHistory «extend» «extend» «extend» «include» 2.2. Biểu đồ chức năng 2.3. Các tác nhân trong hệ thống
Ứng với mỗi User đăng nhập, hệ thống chỉ cho phép nhìn thấy các chức năng tương ứng với quyền trên hệ thống.
2.3.1. Admin
Đây là tài khoản quản trị hệ thống.Tài khoản quản trị (Admin) có quyền quản lý tất cả các tài khoản Quản lý AuctionShop (AuctionShopManage), quyền cấu hình hệ thống,quản lý sản phẩm,quản lý đấu giá, quản lý người dùng..
2.3.2. AuctionsManager
Đây là tài khoản có chức năng quản lý sản phẩm và quản lý đấu giá. 2.3.3. AuctionManagerSite
Đây là tài khoản có chức năng quản lý sản phẩm và quản lý đấu giá, tương tự như AuctionsManager, nhưng ở mức cao hơn. Nghĩa là khi AuctionsManager đưa lên một sản phẩm, thì để sản phẩm đó được đưa ra đấu giá, cần qua sự xét duyện của một tài khoản AuctionsManagerSite. 2.2.4. User
Đây là tài khoản người chơi trong hệ thống. Để trở thành người chơi, người dùng cần đăng ký các thông tin cá nhân trên website. Tài khoản User không có quyền đối với BackEnd mà chỉ được quyền tham gia đấu giá sản phẩm trên FrontEnd.
III. Luồng dữ liệu
3.1. BackEnd
3.1.1. Quản lý Account
sd SelectAccountByName AccountManager AccountDataContext Account AccountInfo WriteLog() SelectAccountByName() :List<Account> SelectAccount() :List<Account> AccountInfo()
Thêm mới Account
sd InsertAccount
AccountManager AccountDataContext
Account Admin
(from Actors)
Auction Manager Site
(from Actors)
Add new account() Add new account()
Validate() AddAccount() :boolean
AddAccount() :int
WriteLog()
sd UpdateAccount AccountManager AccountDataContext Account Validate() UpdateAccount() :boolean UpdateAccount() :int WriteLog() Xóa một Account sd DeleteAccount AccountManager AccountDataContext Account Admin (from Actors)
Auction Manager Site
(from Actors) Delete account() DeleteAccount() DeleteAccount() :int WriteLog() Message() Message()
3.1.2. Quản lý sản phẩm
Lấy thông tin sản phẩm
sd DisplayProduct Auction Manager (from Actors) Products ProductManager ProductDataContext Display product() SelectProductByStatusLangID(int, smallint) :Product SelectProductByStatusLangID(int, smallint) :Product Display() Thêm mới sản phẩm
sd AddProduct
Auction Manager
(from Actors)
Products
ProductManager ProductDataContext
Auction Manager Site
(from Actors)
Add new product()
Add new product()
Validate()
AddProduct(int, int, string, string, string, int, int, int, string, string, datetime, string)
AddProduct(int, int, string, string, string, int, int, int, string, string, datetime, string)
WriteLog() Add new product language()
Add product by language()
Validate()
AddProductByLanguage(int, int, string, string) :int
AddProductByLanguage(int, int, string, string) :int WriteLog() Display() Message() Message() Cập nhật thông tin sản phẩm
sd EditProduct Auction Manager (from Actors) Products ProductManager ProductDataContext Edit product() Validate()
UpdateProduct(int, string, string, string, int, int, int, string, string, string, smallint)
UpdateProduct(int, string, string, string, int, int, int, string, string, string)
WriteLog() Display() Message()
sd DelProduct Auction Manager (from Actors) Products ProductManager ProductDataContext Select produc delete() Validate() DeleteProduct(int) DeleteProduct(int) WriteLog() Display() Message() Aprove một sản phẩm
3.1.3. Quản lý đấu giá
Lấy thông tin phiên đấu giá Thêm mới một phiên đấu giá
Cập nhật thông tin một phiên đấu giá Xóa phiên đấu giá
3.2. FrontEnd
3.2.1. Account
sd DisplayHistory User (from Actors) AccountManager AccountDataContext Account Display history() SelectHistory() :List<History>
Select history() :List<History>
Display()
Hiển thị thông tin cá nhân
sd DisplayProfiles User (from Actors) Account AccountManager AccountDataContext Display profile() SelectAccountInfo() SelectAccountInfo() Display()
sd EditProfiles User (from Actors) AccountManager AccountDataContext Account Edit profile() Update profile() Validate() UpdateProfile() WriteLog() *Message() 3.2.2. Auctions
Hiển thị danh sách các phiên đấu giá theo chuyên muc, theo phiên đấu giá hot, sắp kết thúc, sắp bắt đầu...
sd DisplayCategory User (from Actors) Category CategoryManager CategoryDataContext Display category() SelectCategory() SelectCategory()
sd DisplayProductAuctionHot User (from Actors) AuctionManager (from BLL) AuctionDataContext (from ENT) Auction Display product auction hot()
SelectProductAuctionHot()
SelectProductAuctionHot()
Hiển thị thông tin chi tiết một phiên đâu giá
sd DisplayHistory
User
(from Actors)
Consulting
ConsultingManager ConsultingDataContext
Display history consulting()
SelectConsulting()
SelectConsulting()
3.2.3. Product
sd DisplayProductDetail
User
(from Actors)
Product
ProductManager ProductDataContext
Display product detail()
SelectProductInfo() SelectProductInfo() Mua sản phẩm VI. Thiết kế CSDL Danh sách các bảng chính: 4.1. Cấu hình hệ thống 4.1.1. Bảng Menu 4.1.2. Bảng Role 4.2. Account
4.2.1. Bảng Account
4.2.2. Bảng AccountRole
4.3. Auctions
4.3.2. Bảng AuctionsAccount
4.4. Product
CHƯƠNG 4
CÀI ĐẶT CHƯƠNG TRÌNH
I. Các công nghệ ứng dụng
Chương trình sử dụng các công nghệ sau:
- Công nghệ ASP.net, sử dụng kết hợp các ngôn ngữ HTML, C#, CSS và JavaScript.
- Xây dựng CSDL dùng ngôn ngữ SQL Server 2005. - Xây dựng theo mô hình 3 lớp.
- Kết nối CSDL dùng công nghệ LINQ. - Sử dung jQuery.
- Công nghệ hiển thị ảnh DeepZoom.
II. Các vấn đề cần giải quyết
Việc cài đặt chương trình đặt ra các vấn đề cần giải quyết như sau:
Làm sao để request trang liên tục?
Hệ thống chạy theo thời gian thực nên thông tin luôn thay đổi theo thời gian. Và mỗi lần người chơi đặt bid các thông tin lại bị thay đổi. Vì vậy cần request trang liên tục để cập nhật thông tin.
Việc request trang liên tục dẫn đến các request lên server là rất lớn. Điều này làm cho hệ thống bị chậm, hoặc chạy không ổn định và có thể dẫn đến bị chết hệ thống. Với việc xử lý đa luồng, mỗi công việc sẽ thực hiện trên một thread riêng, làm cho hệ thống được tăng tốc và ổn định.
View ảnh sản phẩm
Đây là website thương mại điện tử, phục vụ nhu cầu mua bán sản phẩm trực tuyến, nên việc view ảnh sản phẩm cho người dùng là rất quan trọng. Cần chọn một hình thức view ảnh mang lại nhiều tiện lợi nhất cho người dùng. Trong website này, sẽ sử dụng công nghệ View ảnh DeepZoom.
Thanh toán trực tuyến
Trong thương mại điện tử, thanh toán trực tuyến là khâu cuối cùng khi người bán và người mua đã thống nhất giá cả và sản phẩm. Có thể sử dụng nhiều hình thức thanh toán trực tuyến bằng cách sử dụng các dịch vụ của các ngân hàng và các trang web thương mại.
III. Mô hình 3 lớp
Trong phát triển ứng dụng, để dễ quản lý các thành phần của hệ thống, cũng như không bị ảnh hưởng bởi các thay đổi, người ta hay nhóm các thành phần có cùng chức năng lại với nhau và phân chia trách nhiệm cho từng nhóm để công việc không bị chồng chéo và ảnh hưởng lẫn nhau. Trong phát triển phần mềm, người ta cũng áp dụng cách phân chia chức năng này, với việc dùng các thuật ngữ như kiến trúc đa tầng/nhiều lớp, mà mỗi lớp sẽ thực hiện một chức năng nào đó, trong đó mô hình 3 lớp là phổ
biến nhất. 3 lớp bao gồm Presentation, Business Logic, và Data Access. Các lớp này sẽ giao tiếp với nhau thông qua các dịch vụ (services) mà mỗi lớp cung cấp để tạo nên ứng dụng, lớp này cũng không cần biết bên trong lớp kia làm gì mà chỉ cần biết lớp kia cung cấp dịch vụ gì cho mình và sử dụng nó mà thôi.
3.1. Presentation Layer
Lớp này làm nhiệm vụ giao tiếp với người dùng cuối để thu thập dữ liệu và hiển thị kết quả/dữ liệu thông qua các thành phần trong giao diện người sử dụng. Lớp này sẽ sử dụng các dịch vụ do lớp Business Logic cung cấp. Trong.NET thì có thể dùng Windows Forms, ASP.NET hay Mobile Forms để hiện thực lớp này.
Trong lớp này có 2 thành phần chính là User Interface Components và User Interface Process Components.
UI Components là những phần tử chịu trách nhiệm thu thập và hiển thị thông tin cho người dùng cuối. Trong ASP.NET thì những thành phần này có thể là các TextBox, các Button, DataGrid…
UI Process Components: là thành phần chịu trách nhiệm quản lý các qui trình chuyển đổi giữa các UI Components. Ví dụ chịu trách nhiệm quản lý các màn hình nhập dữ liệu trong một loạt các thao tác định trước như các bước trong một Wizard…
Lưu ý : lớp này không nên sử dụng trực tiếp các dịch vụ của lớp Data Access mà nên sử dụng thông qua các dịch vụ của lớp Business Logic vì khi sử dụng trực tiếp như vậy, ta có thể bỏ qua các ràng buộc, các logic nghiệp vụ mà ứng dụng cần phải có
3.2. Business Logic Layer
Lớp này thực hiện các nghiệp vụ chính của hệ thống, sử dụng các dịch vụ do lớp Data Access cung cấp, và cung cấp các dịch vụ cho lớp Presentation. Lớp này cũng có thể sử dụng các dịch vụ của các nhà cung cấp thứ 3 (3rd parties) để thực hiện công việc của mình (ví dụ như sử dụng dịch vụ của các cổng thanh tóan trực tuyến như VeriSign, Paypal…).
Trong lớp này có các thành phần chính là Business Components, Business Entities và Service Interface.
Service Interface là giao diện lập trình mà lớp này cung cấp cho lớp Presentation sử dụng. Lớp Presentation chỉ cần biết các dịch vụ thông qua giao diện này mà không cần phải quan tâm đến bên trong lớp này được hiện thực như thế nào.
Business Entities là những thực thể mô tả những đối tượng thông tin mà hệ thống xử lý. Các business entities này cũng được dùng để trao đổi thông tin giữa lớp Presentation và lớp Data Access.
Business Components là những thành phần chính thực hiện các dịch vụ mà Service Interface cung cấp, chịu trách nhiệm kiểm tra các ràng buộc logic (constraints), các qui tắc nghiệp vụ (business rules), sử dụng các dịch vụ bên ngoài khác để thực hiện các yêu cầu của ứng dụng.
3.3. Data Access Layer
Lớp này thực hiện các nghiệp vụ liên quan đến lưu trữ và truy xuất dữ liệu của ứng dụng. Thường lớp này sẽ sử dụng các dịch vụ của các hệ quản trị cơ sở dữ liệu như SQL Server, Oracle,… để thực hiện nhiệm vụ
của mình. Trong lớp này có các thành phần chính là Data Access Logic, Data Sources, Servive Agents).
Data Access Logic components (DALC) là thành phần chính chịu trách nhiệm lưu trữ vào và truy xuất dữ liệu từ các nguồn dữ liệu – Data Sources như RDMBS, XML, File systems…. Trong.NET Các DALC này thường được hiện thực bằng cách sử dụng thư viện ADO.NET để giao tiếp với các hệ cơ sở dữ liệu hoặc sử dụng các O/R Mapping Frameworks để thực hiện việc ánh xạ các đối tượng trong bộ nhớ thành dữ liệu lưu trữ trong CSDL.
VI. Sử dụng jQuery để thực hiện request trang liên tục
Sử dụng hàm “UpdateAuctions” đặt trong tệp.js. Hàm này sẽ thực hiện nhiệm vị request trang liên tục:
function UpdateAuctions(param) { $.ajax({
type: "POST",
url: "/GetData.aspx?param=" + param,
contentType: "application/json; charset=utf-8", dataType: "json",
success: function(response) { if (response != null) {
for (var i = 0; i < response.length; i++) { var TotalSecond = response[i].t; if (TotalSecond <= -2) {
// window.location.reload(true); }
var TotalSecondOld = '#TotalSecond_' + response[i].id; if (TotalSecond <= 3600) {
var TotalSecondOldValue = $(TotalSecondOld).attr("innerHTML"); if (TotalSecondOldValue != '' && TotalSecondOldValue > 3600) { //window.location.reload(true);
} }
var TimeRemain = 'div#TimeRemain_' + response[i].id; var isProductNew = $(TimeRemain).attr("innerHTML"); if (isProductNew == null) {
//window.location.reload(true); }
var PriceNow = 'div#PriceNow_' + response[i].id; var Bidder = 'div#Bidder_' + response[i].id;
var MyBidder = 'div#MyBidder_' + response[i].id; var PriceNowOld = $(PriceNow).attr("innerHTML"); if(PriceNowOld != null)
{
PriceNowOld = jQuery.trim(PriceNowOld.replace(" VNĐ", "")); var PriceNowNew = response[i].p;
$(TimeRemain).attr("innerHTML", CaculatorTime(TotalSecond)); $(PriceNow).attr("innerHTML", response[i].p + " VNĐ");
$(Bidder).attr("innerHTML", '<p>1. <a href="/blog/' + response[i].b[0] + '/index.htm">' + response[i].b[0] + '</a></p><p>2. <a href="/blog/' + response[i].b[1] + '/index.htm">' + response[i].b[1] + '</a></p><p>3. <a href="/blog/' + response[i].b[2] + '/index.htm">' + response[i].b[2] + '</a></p>');
$(MyBidder).attr("innerHTML", 'Người đặt: <span
class="namewinner"><a href="#">' + response[i].b[0] + '</a></span>'); if (PriceNowNew != PriceNowOld) { SetBackground(TimeRemain); } } } $("#ctl00_ucAccount_lblBidNumber").attr("innerHTML", response[0].ttb.toString()); } }, failure: function(msg) { alert(msg); } });
Hàm trên sẽ liên tục được gọi sau một khoảng thời gian nhất định. Ta sẽ dùng một hàm như sau để liên tục gọi đến nó.
setInterval("UpdateAuctions('" + param + "')", 1000); }
Ở các trang FrontEnd, bất kì trang nào có nhúng danh sách các sản phẩm đấu giá, ta đều sẽ phải gọi đến hàm “GetAuctionsInfo” ở trên. Hàm náy se được gọi trong thẻ <script>. Ví dụ trong trang chủ, ta sẽ viết như sau:
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="Server"> <script type="text/javascript"> $(document).ready(function() { GetAuctionsInfo('<%=param %>'); }); </script> </asp:Content>
Trong đó, tham số “param” sẽ chưa thông tin về danh sách thông tin chi tiết của các phiên đấu giá.
V. Xử lý đa luồng
5.1. Cở sở lý thuyết
Sử dụng lớp BackGroundWorker để xử lý đa luồng.
5.1.1. Tạo một BackGroundWorker
Tạo một đối tượng backgroundWorker như sau:
// Xác đinh các thuộc tính đề Backgrond cho phép hủy bỏ và báo cáo các tiến trình
bw.WorkerSupportCancellation=true; bw.WorkerProcessReport=true;
5.1.2. Tạo một Event handle cho một BackGroundWorker
DoWorker event handle là nơi chạy hệ thống trên nền Thread. Bất kì một thay đổi nào của hệ thống nền thông qua đối số của DoWorkerEventArgs, đối tượng đó sẽ được thông qua handle.
Để thông báo tiến trình quay trở lại gọi đến hàm Reportprocess và thông qua nó hoàn thành một giá trị từ 0-100. ReportProcess gây nên một sự kiện ProcessChanged mà ta có thể xử lý riêng biệt. Trong trường hợp báo cáo tiến trình WorkerReportProcess của BackgroundWorker không được đặt là True mà bạn gọi ReportProcess, mọt ngoại lệ sẽ xảy ra.
Để xác định xem có một yêu cầu nào đó đang chờ thực thi yêu cầu hủy bỏ BackGround ngầm, thì kiểm tra thuộc tính CancellationPending của backgroundWorker. Nếu thuộc tính đó trả về là True thì thuộc tính CancelAsync sẽ được gọi. Đối tượng BackgroundWorker được hủy bỏ và hệ thống sẽ dừng lại.
Để chuyển dữ liệu quay trở lại quá trình xử lý, thiết lập thuộc tính cho DoWorkEventAgrs của đối tượng được thông qua với sự kiện handle. Giá trị này có thể được đọc khi mà RunWorkerCompeleted sự kiện được gây ra khi kết thúc hệ thống.
Private void bw_DoWork (object sender, DoWorkEventArgs e) {
BackgroundWorker work = sender as BackgroundWorker For(i=0;i<=10;i++) { If(work.CancellationPending==true) { e.Cancel=True; break; } else { Thread.Sleep(500); Worker.ReportProcess((i*10)); } } }
5.1.3. Tạo một Event handle cho sự kiên ProcessChanged
Trong sự kiện ProcessChanged, thêm mã xử lý tiến trình như cập nhật giao diện người dùng. Để xác định bao nhiêu tỉ lệ phần trăm được hoàn thành kiểm tra thuộc tính ProcessPecentage thông qua sự kiện ProcesChangedEventArgs
Private void bw_ProcessChanged(object sender, ProcessChangedEventArgs e) {
}
5.1.4. Tạo một sự kiện cho RunWorkerCompeleted
Sự kiện RunWorkerCompeleted được gây ra khi tiến trình BackgroundWork được hoàn thành. Tùy thuộc việc tiến trình BackgroundWorker đưa ra trang thái như hoàn thành, lỗi, hủy mà update giao diện người dùng phù hợp.
Để xác định một lỗi xảy ra, kiểm tra các lỗi từ RunWorkerCompeletedEventArgs thông qua sự kiện.Nếu một lỗi xảy ra, thuộc tính này sẽ bao gồm các thông tin về trường hợp ngoại lệ.
Nếu hệ thống hoạt động không cho phép hủy bỏ nhưng ta muốn kiểm tra xem các hoạt động của hệ thống đã được hủy bỏ hay không sự kiện được thông qua RunWorkerCompeletedEventArgs. Nếu là true, sự kiện CancellAsync đã được gọi.
Private void bw_RunWorkerCompleted(object sender,
RunWorkerCompleted EventArgs e) { If(e.Cancelled==true) { This.tbProcess.Text=”Cancel”; }
Else if(!(e.Error==null)) {
This.tbProcess.Text= e.Error.ToString(); }
}
5.1.5. Bổ sung sự kiện vào BackGroundWorker
Ví dụ sau đây cho phép làm thế nào để bổ sung thêm sự kiện vào DoWork, ProcessChanged và các sự kiện RunCompletedEventArgs.
Bw.DoWork += new DoWorkEventHandle(bw_DoWork);
Bw.ProcessChanged += ProcessChangedEventHandle(bw_DoWork);
Bw.RunWorkCompleted += RunWorkCompletedEventHandle(bw_DoWork);
5.1.6. Chạy một BackgroundWorker
Để chạy một BackgroundWorker, gọi hàm: