一、整體架構
系統的整體分爲三個部分:服務器、商家客戶端、顧客客戶端
項目效果:
- 商家通過商家客戶端可以進行訂單管理和菜品管理;
- 顧客可以通過掃描餐桌上的二維碼進入顧客客戶端進行點餐,將訂單提交到服務器上由商家在客戶端上獲取到;
編程語言/開發平臺:
- 服務器:編程語言基於C++、開發平臺基於Linux(CentOS 7.3)(阿里雲輕量應用服務器)、MySQL
- 客戶端:HTML、CSS、JavaScript
二、服務器
一、HTTP服務器
1、創建數據庫
在MySQL數據庫中創建一個名爲 Order_System 的庫,並在中添加兩張表,分別爲:
- dish_table(菜品列表):dish_id 序號、name 菜名、price 價格
- order_table(訂單列表):order_id 訂單序號、table_id 桌號、time 時間、dish_id 菜品序號、state 訂單狀態(0表示進行中,1表示已完結)
創建庫 Order_System,並使用該庫
create database if not exists order_system;
use order_system;
創建菜品列表 dish_table (展現給顧客,由商家維護)
create table if not exists dish_table(
dish_id int unsigned not null primary key auto_increment,
name varchar(50),
price int);
創建訂單列表 order_table (顧客提交,商家查看)
create table if not exists order_table(
order_id int unsigned not null primary key auto_increment,
table_id varchar(50),
time varchar(50),
dish_ids varchar(1024),
state int);
2、服務端設計 (RESTful風格)
菜品管理API設計
1、新增菜品(商家)
請求:
POST /dish
{
"name": "宮保雞丁",
"price": 1800
}
響應:
HTTP/1.1 200 OK
{
"ok": true,
"dish_id": 1,
}
2、查看所有菜品 (商家/顧客)
請求:
GET /dish
響應:
HTTP/1.1 200 OK
[
{
dish_id: 1,
name: "宮保雞丁",
price: 1800
}
]
3、刪除菜品 (商家)
請求:
DELETE /dish/:dish_id
響應:
HTTP/1.1 200 OK
{
"ok": true
}
4、修改菜品 (商家)
請求:
PUT /dish/:dish_id
{
"name": "京醬肉絲",
"price": 1900
}
響應:
HTTP/1.1 200 OK
{
"ok": true
}
訂單管理API設計
1、提交訂單(顧客)
請求:
POST /order
{
"table_id": "1",
"time": "2019-05-15 12:00",
"dish_ids": [1, 2]
}
響應:
HTTP/1.1 200 OK
{
"ok": true
}
2、 修改訂單狀態(商家)
請求:
PUT /order/:order_id
{
"state": 0,
}
響應:
HTTP/1.1 200 OK
{
"ok": true
}
3、獲取訂單 (商家)
請求:
GET /order
響應:
HTTP/1.1 200 OK
[
{
"order_id": 1,
"table_id": "1",
"time": "2019-05-15 12:00",
"dishes": [
{
"dish_id": 1,
"name": "宮保雞丁",
"price": 1800
},
{
"dish_id": 2,
"name": "京醬肉絲",
"price": 1900
}
],
"state": 0,
"consume": 3700, // 表示該訂單的價格
}
]
2、封裝 API (Cpp)
MySQL-API 官方手冊:https://dev.mysql.com/doc/
使用 JSON 作爲數據交互格式,JSON 出自 JavaScript,是一種非常方便的鍵值對數據組織格式, C++ 中可以使用 jsoncpp 這個庫來解析和構造 JSON 數據。
1、連接 / 斷開MySQL
//初始化MySQL
static MYSQL* MySQLInit(){
//創建句柄
MYSQL* mysql = mysql_init(NULL);
//建立連接
if(mysql_real_connect(mysql,"127.0.0.1","root","","order_system",3306,NULL,0) == NULL){
printf("Connect failed %s\n",mysql_error(mysql));
return NULL;
}
//設置編碼格式
mysql_set_character_set(mysql,"utf8");
return mysql
}
//斷開MySQL
static void MySQLRelease(MYSQL* mysql){
mysql_close(mysql);
}
2、菜品管理API
class DishTable{
public:
DishTable(MYSQL* mysql):
_mysql(mysql)
{}
bool Insert(const Json::Value& dish){
//拼寫MySQL語句
char sql[1024 * 4] = {0};
sprintf(sql,"insert into dish_table values(null,'%s',%d)"
,dish["name"].asCString(),dish["price"].asInt());
//執行MySQL語句
int ret = mysql_query(_mysql,sql);
if(ret != 0){
printf("Dishtable insert failed! %s\n",mysql_error(_mysql));
return false;
}
printf("Dishtable insert finished!\n");
return true;
}
bool SelectAll(Json::Value* dishes){
//拼寫MySQL語句
char sql[1024 * 4] = {0};
sprintf(sql,"select * from dish_table");
//執行MySQL
int ret = mysql_query(_mysql,sql);
if(ret != 0){
printf("Dishtable selectall failed! %s\n",mysql_error(_mysql));
return false;
}
//構造結果
MYSQL_RES* result = mysql_store_result(_mysql);
if(result == NULL{
printf("Dishtable selectall result failed! %s\n",mysql_error(_mysql));
return false;
}
//獲取行數
int rows = mysql_num_rows(result);
for(int i = 0;i < rows;++i){
Json::Value dish;
dish["dish_id"] = atoi(row[0]);
dish["name"] = row[1];
dish["price"] = atoi(row[2]);
dishes->append(dish);
}
//釋放資源!!!!!!!
mysql_free_result(result);
printf("Dishtable selectall finished!\n");
return true;
}
bool SelectOne(int32_t dish_id,Json::Value* dish){
char sql[1024 * 4] = {0};
sprintf(sql,"select * from dish_table where dish_id=%d",dish_id);
int ret = mysql_query(_mysq,sql);
if(ret != 0){
printf("Dishtable selectone failed! %s\n",mysql_error(_mysql));
return false;
}
MYSQL_RES* result = mysql_store_result(_mysql);
if(result == NULL){
printf("Dishtable selectone result failed! %s\n",mysql_error(_mysql));
}
int rows = mysql_num_rows(result);
if(rows != 1){
printf("The number of rows is not one! rows=%d\n",rows);
return false;
}
for(int i = 1;i < rows;++i){
(*dish)["dish_id"] = atio(rows[0]);
(*dish)["name"] = rows[1];
(*dish)["price"] = atoi(rows[2]);
break;
}
//釋放數據!!!!!!!!!
mysql_free_result(result);
printf("Dishtable selectone finished!\n");
return true;
}
bool Update(const Json::Value& dish){
char sql[1024 * 4] = {0};
sprintf(sql,"update dish_table set name='%s',price=%d where dish_id=%d",
dish["name"].asCString(),dish["price"].asInt(),dish["dish_id"].asInt());
int ret = mysql_query(_mysql,sql);
if(ret != 0){
printf("Dishtable update failed! %s\n",mysql_error(_mysql));
return false;
}
printf("Dishtable update finished!\n");
return true;
}
bool Delete(int dish_id){
char sql[1024 * 4] = {0};
sprintf(sql,"delete from dish_table where dish_id=%d",dish_id);
int ret = mysql_query(_mysql,sql);
if(ret != 0){
printf("Dishtable delete failed! %s\n",mysql_error(_mysql));
return false;
}
printf("Dishtable delete finished!\n");
return true;
}
private:
MYSQL* _mysql;
};
3、訂單管理API
class ordertable{
public:
ordertable(MYSQL* mysql):
_mysql(mysql)
{}
bool SelectAll(Json::Value* orders) {
char sql[1024 * 4] = {0};
sprintf(sql,"select * from order_table");
int ret = mysql_query(_mysql,sql);
if(ret != 0){
printf("Ordertable selectall failed! %s\n",mysql_error(_mysql));
return false;
}
MYSQL_RES* result = mysql_store_result(_mysql);
if(result == NULL){
printf("Ordertable selectall result failed! %s\n",mysql_error(_mysql));
return false;
}
int rows = mysql_num_rows(result);
for(int i = 0;i < rows;++i){
MYSQL_ROW row = mysql_fetch_row(result);
Json::Value order;
order["order_id"] = atoi(row[0]);
order["table_id"] = row[1];
order["time"] = row[2];
order["dish_ids_str"] = row[3];
order["state"] = atoi(row[4]);
order->append(order);
}
//釋放資源
mysql_free_result(result);
printf("Ordertable selectall finished!\n");
return true;
}
bool Insert(const Json::Value& order) {
char sql[1024 * 4] = {0};
sprintf(sql,"insert into order_table values(null,'%s','%s','%s',%d)",
order["table_id"].asCString(),order["time"].asCString(),
order["dishes"].asCString(),order["state"].asInt());
int ret = mysql_query(_mysql,sql);
if(ret != 0){
printf("Ordertable insert failed! %s\n",mysql_error(_mysql));
return false;
}
printf("Ordertable insert finished!\n");
return true;
}
bool ChangeState(const Json::Value& order) {
char sql[1024 * 4] = {0};
sprintf(sql,"update order_table set state=%d where dish_id=%d",
order["state"].asInt(),order["disd_id"].asInt());
int ret = mysql_query(_mysql,sql);
if(ret != 0){
printf("Ordertable changestate failed! %s\n",mysql_error(_mysql));
return false;
}
printf("Ordertable changestate finished!\n");
return true;
}
private:
MYSQL* _mysql;
};
3、構造HTTP請求
運用到了GitHub上面一位大佬的庫:https://github.com/ClivenZ/cpp-httplib
不得不說這個庫還是很強大的,而且大佬寫了很詳細得使用手冊,值得借鑑,主體就是這樣的:
#include <httplib.h>
int main(void)
{
using namespace httplib;
Server svr;
svr.Get("/hi", [](const Request& req, Response& res) {
res.set_content("Hello World!", "text/plain");
});
svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) {
auto numbers = req.matches[1];
res.set_content(numbers, "text/plain");
});
svr.Get("/stop", [&](const Request& req, Response& res) {
svr.stop();
});
svr.listen("localhost", 1234);
}
這裏面遇到了兩個知識點:正則表達式、lamad表達式(C++11):
正則表達式:https://www.cnblogs.com/guozht/p/7610877.html
lambda表達式:https://blog.csdn.net/fjzpdkf/article/details/50249287
三、服務端
1、幾個前端小知識
HTML:
超文本標記語言,標準通用標記語言的下一個應用。HTML不是以一種編程語言,而是一種標記語言,是製作網頁所必備的。“超文本”就是指頁面內可以包含圖片、鏈接、音樂、程序等非文字元素。
CSS:
層疊樣式表是一種用來表現HTML等文件樣式的計算機語言,說簡單一點就是用來支撐一個網頁的顏值的。
JavaScript:
JS是一種直譯式腳本語言,是一種動態類型、弱類型、基於原型的語言,在HTML中使用,用來給網頁增加動態功能。
jQuery:
jQuery是一個快速、間接的JS框架,提供一種簡便的JS設計模式,優化HTML文檔操作、時間處理、動畫設計和Ajax進行交互。
Ajax:
Ajax的本意就是異步JavaScript和XML,是指一種創建交互式網頁應用的網頁開發技術。主要是用於創建快速動態網頁的技術,特點是在無需重新加載整個網頁的情況下,就能更新部分網頁的技術。
通過在後臺與服務器進行少量的數據交換,Ajax可以使網頁實現異步更新。
Vue.js:
Vue是一套構建用戶界面的漸進式JavaScript框架,Vue可以自底向上逐層應用,Vue的核心庫只關注視圖層,方便與第三方庫或既有項目進行整合。
2、資料推薦
w3cshcool:https://www.w3school.com.cn/
Vue官方文檔:https://cn.vuejs.org/