Trang chủ » Quản lý thư viện bằng Console (Phần 3)
Bài tập tổng hợp

Quản lý thư viện bằng Console (Phần 3)

Cùng nhau khám phá đằng sau thư viện này là gì nhé!
Cùng nhau khám phá đằng sau thư viện này là gì nhé!

Xin chào mọi người!

Vào năm học mình có hơi bận 1 chút xíu, 1 phần vì lịch học ở trường, 1 phần vì blog mình chỉ có mình là tác giả, nên số lượng bài up lên blog hơi hạn chế (nói cho văn chương vậy thôi chứ phần lớn thời gian là lười :v). Mấy ngày nay trời mưa bão, ngồi buồn mà chẳng muốn đụng tay vào viết, mưa lành lạnh vậy thôi chứ mấy khớp tay nhấc còn không nổi mà :v

Ở bài trước, mình cùng nhau tìm hiểu về cấu trúc file .CSV, kèm theo là viết cho cái sườn CSDL rồi, vậy nên hôm nay mình cùng nhau “xây” cái sườn thành 1 khung đăng nhập hoàn chỉnh 🙂 Có thể các bạn sẽ cảm thấy mình nói khó hiểu, nên từ phần này trở đi, mình sẽ up cả file Source để dễ dàng cho việc học tập nhé (vì sẽ có những phần code lặt vặt mà mình không thể nói hết trong 1 bài, nên mình sẽ up source kèm theo comment để các bạn có thể tiện theo dõi).

1. Cấu trúc file CSV

Không giống như những trang đăng kí thông thường, ta muốn đăng kí tài khoản thư viện thì cần phải liên hệ Admin/Mod để được đăng kí. Vậy nên mình sẽ không viết đăng kí tài khoản vào khung đăng nhập này. Ngoài ra vì phải có 1 tài khoản admin gốc nên trong file data.csv phải có ít nhất 1 hàng chứa tên tài khoản admin.

// Cấu trúc file data.csv
// Mặc dù file CSV phải bao các data con lại trong dấu quote "", và cách nhau bằng dấu phẩy
// Tuy nhiên vì mình muốn đơn giản hoá nên không sử dụng quote, cũng như thay dấu phẩy bằng dấu chấm phẩy
// <ID>;<Username>;<Password>;<Name>;<Identity Card>
m1;admin;123456;Vo Hoai Son;300300
// Nếu ta tạo 1 customer thì cấu trúc của nó sẽ như thế này
// <ID>;<Username>;<Password>;<Name>;<Identity Card>;<VIP>;<Register Date>;<List RentBook>
c1;test;123456;Hoai Son;301544;true;30/5/2014;1 2 3

Tương tự với file book.csv:

// Cấu trúc file book.csv
// <ID>;<Name>;<Price>
1;Conan;16000
2;Doraemon;16000

2. Chỉnh sửa cấu trúc class

Ở phần trước, mình cùng nhau tạo dựng 4 class là Book, Account, Customer, Moderator rồi, tuy nhiên việc mình làm là thao tác với mảng các class đó, nên mình cần sử dụng thêm 1 class cho mỗi thành viên:

class ListBook
{
public:
  vector<Book> listBook;
};

class ListModerator
{
public:
  vector<Moderator> listModerator;
}

class ListCustomer
{
public:
  vector<Customer> listCustomer;
}

Tất nhiên, ta phải khai báo những class này ở ngoài file chứa hàm main là các biến toàn cục, để khi ta cần có thể extern các biến để sử dụng. Về sau với mỗi chức năng muốn thêm vào, mình chỉ cần thêm vào các class mình đã add, ví dụ như addBook, removeBook,…

3. Kết nối CSDL

Ta thao tác với bất kì thứ gì cũng vậy, việc đầu tiên cần làm là kết nối CSDL để lấy data mà thao tác (không có data thì thao tác với cái gì đây :-/ ). Để “kết nối”, ta tạo 1 class là Database:

// Database.h
class Database
{
public:
	fstream fio;
	void getDataUser(ListCustomer& cus, ListModerator& mod);
	void getDataBook(ListBook& book);
};

// Database.cpp
#include "stdafx.h"
#include "Database.h"

void Database::getDataUser(ListCustomer& cus, ListModerator& mod)
{
	this->fio.open("data.csv");
	Customer currCus;
	Moderator currMod;
	string id, username, password, name, icard, date, listBook, boolean;
	while (!this->fio.eof())
	{
		getline(this->fio, id, ';');
		if (id[0] == 'm')
		{
			currMod.setID(id);
			getline(this->fio, username, ';');
			currMod.setUsername(username);
			getline(this->fio, password, ';');
			currMod.setPassword(password);
			getline(this->fio, name, ';');
			currMod.setName(name);
			getline(this->fio, icard);
			currMod.setIdentityCard(icard);
			mod.listModerator.push_back(currMod);
		}
		else if (id[0] == 'c')
		{
			currCus.setID(id);
			getline(this->fio, username, ';');
			currCus.setUsername(username);
			getline(this->fio, password, ';');
			currCus.setPassword(password);
			getline(this->fio, name, ';');
			currCus.setName(name);
			getline(this->fio, icard, ';');
			currCus.setIdentityCard(icard);
			getline(this->fio, boolean, ';');
			currCus.setVIP((boolean == "true") ? true : false);
			getline(this->fio, date, ';');
			currCus.convertStringToDate(date); // Hàm này sẽ chuyển đổi chuỗi thành kiểu Date
			getline(this->fio, listBook);
			stringstream ss(listBook);
			int temp;
			while (ss >> temp)
			{
				Rent currRent;
				currRent.id = temp;
				currCus.addRentBook(currRent);
			}
			cus.listCustomer.push_back(currCus);
		}
	}
	this->fio.close();
}

void Database::getDataBook(ListBook& book)
{
	this->fio.open("book.csv");
	string id, name, price;
	Book currBook;
	while (!this->fio.eof())
	{
		if (getline(this->fio, id, ';') && getline(this->fio, name, ';') && getline(this->fio, price))
		{
			currBook.setID(stoi(id));
			currBook.setName(name);
			currBook.setPrice(stoi(price));
			book.listBook.push_back(currBook);
		}
	}
	this->fio.close();
}

4. Xây dựng giao diện đăng nhập

Dù biết rằng mình đang viết trên Console, nhưng “làm màu” tí cũng đâu có chết ai nhỉ :v? Chí ít thì mỗi thư viện đều có 1 giao diện đăng nhập, và thư viện của chúng ta cũng có 1 giao diện đăng nhập hoàn toàn đặc biệt (chí ít là không đụng hàng, vì có ai làm giống mình đâu :v)

Ta tạo 1 class tên là View, class này đảm nhiệm vai trò là quản lý các “giao diện”, giống như giao diện đăng nhập, giao diện customer, giao diện moderator,…

// View.h
class View
{
public:
  // Mình trả về string là id đăng nhập nếu thành công, là rỗng nếu không thành công
  string Login();
}

// View.cpp
#include "stdafx.h"
#include "View.h"

extern ListCustomer cus;
extern ListModerator mod;
extern ListBook book;
extern Database db;


std::string View::Login()
{
        // Kiểm tra nếu hợp lệ thì out khỏi vòng lặp
        while (true)
	{
		system("cls");
		string username, password;
		cout << "### DANG NHAP ###" << endl << endl;
		cout << "Tai khoan: ";
		getline(cin, username);
		cout << "Mat khau: ";
		getline(cin, password);
                // Quét tất cả các Account trong data, nếu phù hợp thì return id của Account đó
		for (int i = 0; i < cus.listCustomer.size(); i++)
		{
			if (cus.listCustomer[i].getUsername() == username && cus.listCustomer[i].getPassword() == password) return cus.listCustomer[i].getID();
		}
		for (int i = 0; i < mod.listModerator.size(); i++)
		{
			if (mod.listModerator[i].getUsername() == username && mod.listModerator[i].getPassword() == password) return mod.listModerator[i].getID();
		}
		cout << "Tai khoan khong hop le, vui long kiem tra lai!" << endl;
		system("pause");
	}
}

Ở mục này có 1 phần là biến extern, đây là 1 biến khá đặc biệt, nó là tham chiếu của 1 biến toàn cục cùng tên, được định nghĩa bên ngoài. Mình có nói ở trên là đặt các biến ListCustomer, ListModerator, Book,… thành biến toàn cục. Nếu các bạn có học về PHP, thì đây “giống giống” như các global variable $_POST, $_GET. Khai báo biến extern để mình có thể truyền biến qua các file khác nhau để dễ dàng sử dụng.

Đến đây, các bạn có thể build và chạy thử, nhập vào tên tài khoản và mật khẩu, nếu nó out thẳng ra ngoài có nghĩa là các bạn đã đăng nhập thành công rồi đấy 🙂

Các bạn có thể download file tại đây, sau đó add vào Project của bạn và chạy thử để xem kết quả nhé!

Trên đây là Phần 3 – Quản lý thư viện bằng Console, cảm ơn các bạn đã chú ý theo dõi. Hẹn gặp lại ở Phần 4!

Tags

About the author

Võ Hoài Sơn

Tính tình bất định
Chọc vào là bịnh
Rất yêu lập trình
Luôn code hết mình
Mình hiện đang là sinh viên của trường ĐH Khoa học tự nhiên TPHCM. Bản thân rất thích code, kiêm luôn cả mần thơ nên thường hơi hâm hâm dở dở. Ngoài ra chém gió, chém chuối, chém trái cây các kiểu cũng là sở trường của mình. Rất mong được làm quen với các bạn :D

Add Comment