目录
- 项目描述
-
- 详细设计
-
- 涉及知识点
- JSON
-
- 正则表达式
- MySQL语句
- MySQL代码
- httplib基础
- 项目总结
- 项目代码
项目描述
功能
- 用户可以通过浏览器访问服务器获取菜品信息并进行点餐;
- 管理员可以通过浏览器访问服务器实现订单以及菜品的管理;
技术点
- 多线程、socket、http、json、mysql、stl;
框架
- 框架:简单 MVC 框架;
- M(Model):数据管理模块,管理菜品、订单信息,外界想要访问数据必须通过这个模块完成,不能直接访问;
- V(View):前端界面模块,浏览器的前端所展示的界面,用户或者管理员的操作都是通过前端界面来完成的;
- C(Controller):业务控制模块(服务器),针对前端的请求做出对应的处理;

详细设计
数据管理模块
- 数据存储:MySQL 数据库,原因:免费、可跨主机访问、线程安全;
- 数据库表的设计:菜品表、订单表;
菜品表:菜品序号、菜品名称、菜品单价、修改时间;
订单表:订单序号、订单菜品、订单状态、修改时间; - 代码设计:菜品类、订单类;
菜品类:添加、删除、修改、查看(单个 / 全部);
订单类:添加、删除、修改(菜品信息 / 菜品状态)、查看(单个 / 全部);
业务控制模块
- HTTP 服务器:基于 http 协议,使用 httplib 库搭建 http 服务器;
- 通信接口设计:借助 httplib 库编写请求与响应接口,什么样的请求对应什么样的业务处理和响应;
- 静态页面请求:HTML 页面(CSS / JS 文件,在一些现成的模板上以修改为主),然后将该页面命名为 index.html,将该页面所在目录设置为静态资源路径;
- 动态数据请求:菜品 / 订单数据增、删、改、查,通信接口采用 restful 风格接口设计,基于 HTTP 协议,使用 json 格式定义正文序列化方式,定义操作类型:新增-POST,删除-DELETE,修改-PUT,获取-GET;
| 请求方式 | 请求资源 | 响应结果 |
|---|
| Get | / 或者 index.html | 展示菜品信息界面、下单界面 |
| Post | /dish | 管理员添加菜品 |
| Delete | /dish/数字 | 删除指定数字序号的菜品 |
| Put | /dish/数字 | 修改指定数字序号的菜品 |
| Post | /order | 添加新的订单 |
前端界面模块
- 前端界面:基于简单的 html、css、vue.js 以及 ajax 实现前端界面的静态页面展示以及动态数据获取渲染功能;
- html:完成页面的布局;
- css:样式语言,对标签容器进行样式修饰,让简单的 html 页面更加好看;
- vue.js:脚本语言,让页面可以动态渲染展示;
涉及知识点
JSON
Value
- 这是 JSON 与外界进行数据转换的一个对象类,这其中重载了很多的运算符,包含了大量的类型转换函数;
string name = "zhangjinrui";
int age = 18;
vector<double> score = {88.8, 99.9, 77.7};
Json::Value val;
val["name"] = name;
val["age"] = age;
for(int i = 0; i < score.size(); i++){ val["score"].append(score[i]);
}
string name2 = val["name"].asString();
int age2 = val["age"].asInt();
double math_score = val["score"][1].asDouble();
Writer
- 实现序列化类,将 Json::Value 对象中的数据序列化成为 JSON 格式的字符串;
Json::FastWriter writer1;
string str1 = writer1.write(val);
Json::StyledWriter writer2;
string str2 = writer2.write(val);

Reader
- 实现反序列化类,将 JSON 格式字符串转换为多个数据对象,存储在 Json::Value 对象中;
Json::Reader read;
Json::Value val2;
read.parse(str, val2);
正则表达式
R"()":去转义用途,正则表达式搭配该 C++11 新特性语法,可以去除括号中一些特殊字符的特殊含义;- 关于正则表达式这里就不过多介绍,附上一个大佬的博客,感兴趣的可以看看:最全常用正则表达式大全
():在 httplib 中,请求信息const Request& req中存在一个matches数组,当我们使用()将请求资源路径中的某些信息括起来时,该数组中就存放了这些使用括号捕捉到的信息,matches[0]存放的是整个请求,然后数组后续元素是从括号中捕捉到的信息,按顺序排列好的;
MySQL语句
MySQL代码
httplib基础
- 存在一张路由表,
map, function> route,请求与处理一一对应; - 使用
Server创建一个服务端,然后向路由表中添加请求与处理的键值对; - 服务端调用
listen接口进行监听; - 当服务端收到客户端的请求后,将该请求抛入线程池中,线程池中的线程负责与指定客户端进行通信;
- 实例化
httplib::Requert对象 req,线程按照 http 协议格式解析请求信息,将解析结果填充到 req 对象中; - 根据请求信息在路由表中查找是否有对应处理函数,如果没有则返回 404(请求资源不存在),如果有,则再实例化一个
httplib::Response对象 res,然后将 req 与 res 传入处理函数中,进行处理; - 处理结束后,将返回信息填入 res 中,然后服务端根据 res 对象组织响应,将响应结果返回给客户端;
- 注册路由函数:Get()、Post()、Put()、Delete();
- 设置静态资源默认路径接口:
Server::set_base_dir(char* path);
设置这个路径后,当前端在请求静态资源的时候,就会自动先到这个路径下查找有没有对应的静态资源文件,如果有则自动读取文件数据进行恢复;
项目总结
- 这个订单系统中,用户通过浏览器与后台服务器进行交互,实现查看菜品信息以及下单功能,管理员通过浏览器与后台服务器进行交互,实现对菜品和订单的管理功能;
- 这个项目在实现的时候采用了一个不太严谨的 mvc 框架实现,将项目实现总体分为三个模块:数据管理、业务处理、前端页面;
- 数据管理模块:基于 MySQL 数据库实现数据存储管理,并且封装数据库访问类,向外提供与业务分离的数据信息;
- 业务处理模块:基于 http 协议,使用 httplib 库搭建服务器与前端进行交互,实现菜品以及订单的数据业务处理功能;
- 前端界面模块:基于简单的 html、css、vue.js 和 ajax 实现前端的静态页面展示,以及动态数据获取渲染功能;
项目代码
create database if not exists order_sys; use order_sys; create table if not exists tb_dish( id int primary key auto_increment, name varchar(32) unique not null, price int not null, ctime datetime
); create table if not exists tb_order( id int primary key auto_increment, dishes varchar(255) comment '[1, 2]', status int comment '0-未完成,1-已完成', mtime datetime
);
#include
#include
#include
#include
#includenamespace order_sys{
#define MYSQL_SERVER "127.0.0.1"
#define MYSQL_USER "root"
#define MYSQL_PASSWD ""
#define MYSQL_DBNAME "order_sys"static MYSQL* MysqlInit(){MYSQL* mysql = NULL;mysql = mysql_init(NULL);if(mysql == NULL){std::cout << "mysql init failed!\n";return NULL;}if(mysql_real_connect(mysql, MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWD, MYSQL_DBNAME, 0, NULL, 0) == NULL){std::cout << mysql_error(mysql) << std::endl;return NULL;}if(mysql_set_character_set(mysql, "utf8") != 0){std::cout << mysql_error(mysql) << std::endl;return NULL;}if(mysql_select_db(mysql, MYSQL_DBNAME) != 0){std::cout << mysql_error(mysql) << std::endl;return NULL;}return mysql;}static void MysqlRelease(MYSQL* mysql){if(mysql != NULL){mysql_close(mysql);}}static bool MysqlQuery(MYSQL* mysql, const std::string& sql){if(mysql_query(mysql, sql.c_str()) != 0){std::cout << sql << std::endl;std::cout << mysql_error(mysql) << std::endl;return false;}return true;}class TableDish{private:MYSQL* _mysql;std::mutex _mutex;public:TableDish(){_mysql = MysqlInit();if(_mysql == NULL)exit(-1);}~TableDish(){if(_mysql != NULL){MysqlRelease(_mysql);_mysql = NULL;}}bool Insert(const Json::Value& dish){
#define DISH_INSERT "insert tb_dish values(null, '%s', %d, now());"char str_sql[4096] = {0};sprintf(str_sql, DISH_INSERT, dish["name"].asString(), dish["price"].asInt());return MysqlQuery(_mysql, str_sql);}bool Delete(int dish_id){
#define DISH_DELETE "delete from tb_dish where id = %d;"char str_sql[4096] = {0};sprintf(str_sql, DISH_DELETE, dish_id);return MysqlQuery(_mysql, str_sql);}bool Update(const Json::Value& dish){
#define DISH_UPDATE "update tb_dish set name = '%s', price = %d where id = %d;"char str_sql[4096] = {0};sprintf(str_sql, DISH_UPDATE, dish["name"].asString(), dish["price"].asInt(), dish["id"].asInt());return MysqlQuery(_mysql, str_sql);}bool SelectAll(Json::Value* dishes){
#define DISH_SELECTALL "select * from tb_dish;"_mutex.lock();if(MysqlQuery(_mysql, DISH_SELECTALL) == false){_mutex.unlock();return false;}MYSQL_RES* res = mysql_store_result(_mysql);_mutex.unlock();if(res == NULL){std::cout << "store result failed!\n";return false;}int num = mysql_num_rows(res);for(int i = 0; i < num; i++){MYSQL_ROW row = mysql_fetch_row(res);Json::Value dish;dish["id"] = std::stoi(row[0]);dish["name"] = row[1];dish["price"] = std::stoi(row[2]);dish["ctime"] = row[3];dishes->append(dish);}mysql_free_result(res);return true;}bool SelectOne(int dish_id, Json::Value* dish){
#define DISH_SELECTONE "select * from tb_dish where id = %d;"char str_sql[4096] = {0};sprintf(str_sql, DISH_SELECTONE, dish_id);_mutex.lock();if(MysqlQuery(_mysql, str_sql) == false){_mutex.unlock();return false;}MYSQL_RES* res = mysql_store_result(_mysql);_mutex.unlock();if(res == NULL){std::cout << "store result failed!\n";return false;}int num = mysql_num_rows(res);if(num != 1){std::cout << "store result failed!\n";mysql_free_result(res);return false;}MYSQL_ROW row = mysql_fetch_row(res);(*dish)["id"] = std::stoi(row[0]);(*dish)["name"] = row[1];(*dish)["price"] = std::stoi(row[2]);(*dish)["ctime"] = row[3];mysql_free_result(res);return true;}};class TableOrder{private:MYSQL* _mysql;std::mutex _mutex;public:TableOrder(){_mysql = MysqlInit();if(_mysql == NULL)exit(-1);}~TableOrder(){if(_mysql != NULL){MysqlRelease(_mysql);_mysql = NULL;}}bool Insert(const Json::Value& order){
#define ORDER_INSERT "insert tb_order values(null, '%s', 0, now());"char str_sql[4096] = {0};Json::FastWriter writer;std::string dishes = writer.write(order["dishes"]);dishes[dishes.size() - 1] = '\0';sprintf(str_sql, ORDER_INSERT, dishes.c_str());return MysqlQuery(_mysql, str_sql);}bool Delete(int order_id){
#define ORDER_DELETE "delete from tb_order where id = %d;"char str_sql[4096] = {0};sprintf(str_sql, ORDER_DELETE, order_id);return MysqlQuery(_mysql, str_sql);}bool Update(const Json::Value& order){
#define ORDER_UPDATE "update tb_order set dishes = '%s', status = %d where id = %d;"char str_sql[4096] = {0};Json::FastWriter writer;std::string dishes = writer.write(order["dishes"]);dishes[dishes.size() - 1] = '\0';sprintf(str_sql, ORDER_UPDATE, dishes.c_str(), order["status"].asInt(), order["id"].asInt());return MysqlQuery(_mysql, str_sql);}bool SelectAll(Json::Value* orders){
#define ORDER_SELECTALL "select * from tb_order;"_mutex.lock();if(MysqlQuery(_mysql, ORDER_SELECTALL) == false){_mutex.unlock();return false;}MYSQL_RES* res = mysql_store_result(_mysql);_mutex.unlock();if(res == NULL){std::cout << mysql_error(_mysql) << std::endl;return false;}int num = mysql_num_rows(res);for(int i = 0; i < num; i++){MYSQL_ROW row = mysql_fetch_row(res);Json::Value order, dishes;Json::Reader reader;order["id"] = std::stoi(row[0]);reader.parse(row[1], dishes);order["dishes"] = dishes;order["status"] = std::stoi(row[2]);order["mtime"] = row[3];orders->append(order);}mysql_free_result(res);return true;}bool SelectOne(int order_id, Json::Value* order){
#define ORDER_SELECTONE "select * from tb_order where id = %d;"char str_sql[4096] = {0};sprintf(str_sql, ORDER_SELECTONE, order_id);_mutex.lock();if(MysqlQuery(_mysql, str_sql) == false){_mutex.unlock();return false;}MYSQL_RES* res = mysql_store_result(_mysql);_mutex.unlock();if(res == NULL){std::cout << mysql_error(_mysql) << std::endl;return false;}int num = mysql_num_rows(res);if(num != 1){std::cout << "store result failed!\n";mysql_free_result(res);return false;}Json::Reader reader;Json::Value dish;MYSQL_ROW row = mysql_fetch_row(res);(*order)["id"] = std::stoi(row[0]);reader.parse(row[1], dish);(*order)["name"] = dish;(*order)["price"] = std::stoi(row[2]);(*order)["ctime"] = row[3];mysql_free_result(res);return true;}};
}
#include"db.hpp"
#include"httplib.h"
using namespace httplib;
#define WWWROOT "./wwwroot"
order_sys::TableDish* dishptr = NULL;
order_sys::TableOrder* orderptr = NULL;
void DishInsert(const Request& req, Response& rsp){Json::Value dish;Json::Reader reader;bool ret = reader.parse(req.body, dish);if(ret == false){rsp.status = 400;Json::Value reason;Json::FastWriter writer;reason["result"] = false;reason["reason"] = "dish info parse failed!";rsp.body = writer.write(reason);rsp.set_header("Content-Type", "application/json");std::cout << "dish insert parse failed!\n";return;}ret = dishptr->Insert(dish);if(ret == false){ rsp.status = 500;Json::Value reason;Json::FastWriter writer;reason["result"] = false;reason["reason"] = "mysql insert failed!";rsp.body = writer.write(reason);rsp.set_header("Content-Type", "application/json");std::cout << "mysql dish insert failed!\n";return;}rsp.status = 200;return;
}
void DishDelete(const Request& req, Response& rsp){int dish_id = std::stoi(req.matches[1]);bool ret = dishptr->Delete(dish_id);if(ret == false){std::cout << "mysql dish delete failed!\n";rsp.status = 500;return;}return;
}
void DishUpdate(const Request& req, Response& rsp){int dish_id = std::stoi(req.matches[1]);Json::Value dish;Json::Reader reader;bool ret = reader.parse(req.body, dish);if(ret == false){rsp.status = 400;std::cout << "dish update parse failed!\n";return;}dish["id"] = dish_id;ret = dishptr->Update(dish);if(ret == false){rsp.status = 500;std::cout << "mysql dish update failed!\n";return;}return;
}
void DishGetAll(const Request& req, Response& rsp){Json::Value dishes;bool ret = dishptr->SelectAll(&dishes);if(ret == false){rsp.status = 500;std::cout << "mysql dish selectall failed!\n";return;}Json::FastWriter writer;rsp.body = writer.write(dishes);return;
}
void DishGetOne(const Request& req, Response& rsp){int dish_id = std::stoi(req.matches[1]);Json::Value dish;bool ret = dishptr->SelectOne(dish_id, &dish);if(ret == false){rsp.status = 500;std::cout << "mysql dish selectone failed!\n";return;}Json::FastWriter writer;rsp.body = writer.write(dish);return;
}
void OrderInsert(const Request& req, Response& rsp){Json::Value order;Json::Reader reader;bool ret = reader.parse(req.body, order);if(ret == false){rsp.status = 400;Json::Value reason;Json::FastWriter writer;reason["result"] = false;reason["reason"] = "order info parse failed!";rsp.body = writer.write(reason);rsp.set_header("Content-Type", "application/json");std::cout << "order insert parse failed!\n";return;}ret = orderptr->Insert(order);if(ret == false){ rsp.status = 500;Json::Value reason;Json::FastWriter writer;reason["result"] = false;reason["reason"] = "mysql insert failed!";rsp.body = writer.write(reason);rsp.set_header("Content-Type", "application/json");std::cout << "mysql order insert failed!\n";return;}rsp.status = 200;return;
}
void OrderDelete(const Request& req, Response& rsp){int order_id = std::stoi(req.matches[1]);bool ret = orderptr->Delete(order_id);if(ret == false){std::cout << "mysql order delete failed!\n";rsp.status = 500;return;}return;
}
void OrderUpdate(const Request& req, Response& rsp){int order_id = std::stoi(req.matches[1]);Json::Value order;Json::Reader reader;bool ret = reader.parse(req.body, order);if(ret == false){rsp.status = 400;std::cout << "order update parse failed!\n";return;}order["id"] = order_id;ret = orderptr->Update(order);if(ret == false){rsp.status = 500;std::cout << "mysql order update failed!\n";return;}return;
}
void OrderGetAll(const Request& req, Response& rsp){Json::Value orders;bool ret = orderptr->SelectAll(&orders);if(ret == false){rsp.status = 500;std::cout << "mysql order selectall failed!\n";return;}Json::FastWriter writer;rsp.body = writer.write(orders);return;
}
void OrderGetOne(const Request& req, Response& rsp){int order_id = std::stoi(req.matches[1]);Json::Value order;bool ret = orderptr->SelectOne(order_id, &order);if(ret == false){rsp.status = 500;std::cout << "mysql order selectone failed!\n";return;}Json::FastWriter writer;rsp.body = writer.write(order);return;
}int main(){dishptr = new order_sys::TableDish();orderptr = new order_sys::TableOrder();Server server;server.set_base_dir(WWWROOT);server.Post("/dish", DishInsert);server.Delete(R"(/dish/(\d+))", DishDelete); server.Put(R"(/dish/(\d+))", DishUpdate);server.Get("/dish", DishGetAll);server.Get(R"(/dish/(\d+))", DishGetOne);server.Post("/order", OrderInsert);server.Delete(R"(/order/(\d+))", OrderDelete); server.Put(R"(/order/(\d+))", OrderUpdate);server.Get("/order", OrderGetAll);server.Get(R"(/order/(\d+))", OrderGetOne);server.listen("0.0.0.0", 9000);return 0;
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!