一、整体架构
系统的整体分为三个部分:服务器、商家客户端、顾客客户端
项目效果:
- 商家通过商家客户端可以进行订单管理和菜品管理;
- 顾客可以通过扫描餐桌上的二维码进入顾客客户端进行点餐,将订单提交到服务器上由商家在客户端上获取到;
编程语言/开发平台:
- 服务器:编程语言基于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/