小酒馆点餐系统实现-C++项目详细过程

项目介绍

1、项目描述

使用户可以通过浏览器访问服务器获取菜品信息并进行点餐;以及可以使管理员通过浏览访问服务器实现订单以及菜品的管理。

2、市场调研

减少人力资源开销,便利点餐环节。

3、技术调研

用到以下技术:
线程,socket,http,json,mysql,STL

项目设计

1、概要设计

  • 框架设计MVC框架
    model(数据管理模块):–管理数据(菜品,订单),外界想要访问数据必须通过这个模块完成,不能直接访问。
    view(视图界面模块):–浏览器前端界面,用户或者管理员的操作都是通过前端界面完成。
    controller(业务控制模块):–搭建服务器针对前端的请求进行对应业务处理
  • 项目流程图
    在这里插入图片描述

2、详细设计

① 数据管理模块:

菜单数据管理和订单数据管理通过MySQL数据库进行数据管理,首先来介绍数据库表的设计:
数据库表包括以下两个表:
菜品信息表:菜品ID,菜品名称,菜品单价,修改时间
订单信息表:订单ID,订单菜品,订单状态,修改时间
1、 MYSQL基本操作
(1)首先在Linux系统下完成对mariadb的配置,我使用的基于Ubuntu的Linux系统,对于mariadb配置的过程见该文mariadb配置
(2)配置完成之后就进行对数据表的设计,进入项目文件,创建一个db.sql文件,用于执行创建数据库和数据库表的操作,并对表中内容进行指定。

//创建数据库
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,
prece 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
);
//测试插入信息
insert tb_dish values(null, "百威", 2800, now()),
(null, "科罗娜", 1800, now());
insert tb_order values(null, "[1,2]", 0, now()),
(null, "[2]", 0, now());

(3)编写完成db.sql后,在当前终端执行mysql -uroot -p > db.sql操作,将其连上数据库并执行db.sql里面的语句命令,此时进入mysql数据库查看内容。
在这里插入图片描述
如上:成功创建order_sys数据库,并在order_sys数据库内创建两个表单。
在这里插入图片描述
在这里插入图片描述

如上查看两个表单的信息。
2、数据管理
数据库操作时,在业务模块中我们并不直接操作数据库,是通过数据管理模块来进行操作,在数据管理模块实现所有数据库的操作,向外提供接口功能即可;
(1)菜单数据管理模块:添加菜品,删除菜品,修改菜品,获取菜品(所有,单个)

class DishesTable{
	public:
		bool Insert(单个菜品信息);//向数据库中添加菜品信息
		bool SelectOne(int dish_id,单个菜品信息);//通过菜单ID查询单个菜品信息,通过第二个参数返回
		bool SelectAll(多个菜品信息的返回);//从数据库中查询所有菜品信息,通过参数返回
		bool Update(单个菜品信息);//修改数据库中的菜品信息
		bool Delete(int dish_id);//删除指定菜品
	private:
		MYSQL* _mysql;
}

(2)订单数据管理模块:添加订单删除订单,修改订单(菜品,状态),获取订单(所有,指定id)

class OrdersTable{
	public:
		bool Insert(单个订单信息);//向数据库中添加订单信息
		bool SelectOne(int order_id,单个订单信息);//通过订单ID查询单个订单信息,通过第二个参数返回
		bool SelectAll(多个订单信息的返回);//从数据库中查询所有订单信息,通过参数返回
		bool Update(单个订单信息);//修改数据库中的订单信息
		bool Delete(int order_id);//删除指定订单
	private:
		MYSQL* _mysql;
}

② 业务控制模块:

业务处理主要包括:接收客户端请求,进行处理满足用户需求
1>接收客户端请求数据,并解析数据;
2>根据解析得到的请求方法和路径,进行业务处理,
3>组织http响应数据,发送给客户端;

  • 搭建服务器:HTTP服务器(这里采用httplib库搭建)
  • 通信接口设计:什么样的请求对应什么样的业务处理和响应 ①静态页面请求:html页面(以及依赖的css/js文件) ②动态数据请求:菜品数据,订单数据
    通信接口采用restful风格接口设计:基于http协议,适应xml或者json格式定义正文序列化方式。定义操作类型:新增-POST;删除-DELETE;修改-PUT;获取-GET
    这里使用Restful风格的通信数据格式即正文采用json串组织数据,json串是轻量级的数据交换格式。json数据库的组织和解析也通过第三方库jsoncpp实现以此来节省时间成本,具体定义以及操作见该文jsoncpp基本应用认识

1、httplib如何搭建HTTP服务器,以及httplib搭建服务器之后对于请求的处理流程
httplib工作流程:
httplib::Server map<pair<string,string>, function> route—请求与处理的路由表:当服务器收到一个客户端连接,则将新建连接抛入线程池,线程池中的线程负责与指定客户端进行通信(http通信)

  1. 接收请求数据,按照http请求协议格式进行解析(请求方法,资源路径,查询字符串,头部字段,正文…) 实例化httplib::Request对象,将解析的信息填入其中;
  2. 根据请求信息,在route路由表中查找针对这个请求有没有对应的处理函数: (1)如果没有则直接返回404–请求的资源不存在; (2)如果有,则使用对应函数指针执行这个处理函数(程序员自定义的处理函数),①传入请求信息;②实例化一个httplib::Response对象,传入函数,在处理函数内部,用户实现针对请求的业务处理,在业务处理完毕后填充Response对象。
    3.线程中执行完处理函数之后,得到了一个填充完毕的Response对象,根据其中的数据(响应状态码,正文数据,头部字段)组织http响应协议格式的数据,回复给客户端。
    4.等待还有没有请求需要处理(没有则关闭套接字g)

httplib::Request{
method:请求方法
path:资源路径
version:协议版本
body:正文
headers:头部信息的键值对
params:url中查询字符串信息的键值对
}

httplib::Response{
status:响应状态码
headers:头部信息键值对
body:响应正文
}

在httplib中有一个Server类,主要是针对各个请求方法来处理相应的路由信息,含有的内容如下:

httplib::Server{
Get(资源路径,回调函数);
Put(资源路径,回调函数);
Post(资源路径,回调函数); srv.Post(/dish,InsertDish)
Delete(资源路径,回调函数);
listen(绑定的IP地址,端口);—搭建TCP服务器
}

因此搭建HTTP服务器就是在main函数中实现以下:

main()
{
httplib::Server server;
server.Get(…);//添加路由信息
server.listen(ip,port);//开始TCP服务器
return 0;
}

2、实现对菜品数据管理通信接口
(1)菜品信息的上传通信接口设计
http请求信息构建,然后发起请求,服务器进行相应,如图(Restful风格):
在这里插入图片描述
(2)获取所有菜品信息
如图:
在这里插入图片描述
(3)获取单个菜品信息
在这里插入图片描述
(4)更新菜品信息,如图:
在这里插入图片描述
(5)删除菜品信息
在这里插入图片描述订单数据管理通信接口与菜单信息类似

③ 前端界面模块:

html的编写渲染 实现:html+css+js(vue.js)
首先使用html编写出一个静态页面, 然后通过css进行样式渲染,最后通过vue.js实现数据的动态渲染。

3、代码实现

实现数据管理模块

mysql是一个客户端/服务端模式的数据库,如图:
在这里插入图片描述
mysql在代码中进行操作的目的就是自己搭建一个mysql客户端完成我们想要的操作

mysql代码操作:
初始化操作
1.初始化操作句柄
2.通过句柄链接mysql服务器
3.设置客户端字符集(utf8)
4.选择使用的数据库
数据操作
5.执行语句:
增删改:执行语句–执行语句成功即可
查询:执行语句-将查询结果获取到本地;获取结果中数据条数、列数;遍历结果集获取每一条数据的每一列;获取本地结果集
6.关闭句柄释放资源
7.获取接口执行失败原因

mysql的相关操作具体介绍在该链接mysql接口认识
关于jsoncpp的使用在该链接jsoncpp介绍
了解上述两个内容后,实现工程db.hpp,实现mysql的初始化(包含初始化句柄,建立数据库连接,设置字符编码集)、mysql的销毁、mysql的执行语句以及实现对菜单信息的增删改查和订单信息的增删改查,代码如下:

/*
*db.hpp
*数据管理模块
*基于mysql封装数据对象操作类
* 1、菜品信息表的操作类
* 2、订单信息表的操作类
* 注意事项:菜品信息/订单信息的通信格式--采用json进行数据传输
*/
#include<iostream>
#include<string>
#include<mysql/mysql.h>
#include<jsoncpp/json/json.h>
#include<mutex>

namespace 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_init(句柄地址);
        MYSQL *mysql = NULL;
        mysql = mysql_init(NULL);
        if(mysql == NULL)
        {   
            std::cout << "mysql init failed!\n";
            return NULL;
        }   
        //连接服务器
        //mysql_real_connect(句柄,服务器IP,用户名,密码,数据库名称,端口,套接字文件,客户端>
        if(mysql_real_connect(mysql, MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWD, MYSQL_DBNAME, 0, NU
        {   
            std::cout << mysql_error(mysql) << std::endl;
            return NULL;
        }   
        //设置字符集
        //mysql_set_character_set(句柄,字符集名称);
        if(mysql_set_character_set(mysql, "utf8mb4") != 0)
        {
            std::cout << mysql_error(mysql) << std::endl;
            return NULL;
        }
        //选择数据库(连接服务器时已经默认选择数据库了)
        //mysql_select_db(句柄,数据库名称);
        //mysql_select_db(mysql, MYSQL_DBNAME);
        return mysql;
    }
    static void MysqlRelease(MYSQL *mysql)
    {
        if(mysql != NULL)
        {
            mysql_close(mysql);
        }
    }
    static bool MysqlQuery(MYSQL *mysql, const std::string &sql)
    {
        //mysql_query(句柄,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:
            //mysql初始化
            TableDish()
            {
                _mysql = MysqlInit();
                if(_mysql == NULL)
                {
                    exit(-1);
                }
            }
            ~TableDish()
            {
                MysqlRelease(_mysql);
                _mysql = NULL;
            }
            bool Insert(const Json::Value &dish)
            {
                //组织sql语句
                #define DISH_INSERT "insert tb_dish values(null, '%s', %d, now());"
                char str_sql[4096] = {0};
                sprintf(str_sql, DISH_INSERT, dish["name"].asCString(), dish["price"].asInt());
                if(MysqlQuery(_mysql, str_sql) == false)
                {
                    return false;
                }
                return true;
            }
            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;"
                std::string priceStr = dish["price"].asString();
                int price = std::stoi(priceStr);
                char str_sql[4096] = {0};
                sprintf(str_sql, DISH_UPDATE,
                            dish["name"].asCString(), price,
                        dish["id"].asInt());
                return MysqlQuery(_mysql, str_sql);
            }
            bool SelectAll(Json::Value *dishes)
            {
                #define DISH_SELECTALL "select * from tb_dish;"
                _mutex.lock();
                bool ret = MysqlQuery(_mysql, DISH_SELECTALL);
                if(ret = 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();
                bool ret = MysqlQuery(_mysql, DISH_SELECTONE);
                if(ret = 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 << "result error\n";
                    mysql_free_result(res);
                    return false;
                }
                MYSQL_ROW row = mysql_fetch_row(res);
                (*dish)["id"] = dish_id;
                (*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:
            //mysql初始化
            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 = 
                char str_sql[4096] = {0};
                Json::FastWriter writer;
                std::string dishes = writer.write(order["dishes"]);
                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();
                bool ret = MysqlQuery(_mysql, ORDER_SELECTALL);
                if(ret == 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;
                    order["id"] = std::stoi(row[0]);
                    Json::Reader reader;
                    Json::Value dishes;
                    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();
                bool ret = MysqlQuery(_mysql, str_sql);
                if(ret == false)
                {
                    _mutex.unlock();
                    return false;
                }
                MYSQL_RES *res = mysql_store_result(_mysql);
                _mutex.unlock();
                if(res == NULL)
                {
                    std::cout << "store failed!\n";
                    return false;
                }
                int num = mysql_num_rows(res);
                if(num != 1)
                {
                    std::cout << "one result error\n";
                    mysql_free_result(res);
                    return false;
                }
                MYSQL_ROW row = mysql_fetch_row(res);
                (*order)["id"] = order_id;
                Json::Reader reader;
                Json::Value dishes;
                reader.parse(row[1], dishes);
                (*order)["dishes"] = dishes;
                (*order)["status"] = std::stoi(row[2]);
                (*order)["mtime"] = row[3];
                mysql_free_result(res);
                return true;
            }
    };
}

首先初始化数据库,也就是进行句柄初始化、连接数据库,设置字符编码集等操作,然后实现销毁句柄的函数,然后实现执行语句的函数,之后就是实现菜单信息的增删改查和订单信息的增删改查。
此时可以在test.cpp中进行局部测试,代码如下:

#include "db.hpp"

int main()
{
	dish_test();
    order_test();
}
void dish_test()
{
    order_sys::TableDish dish;
    /*
    Json::Value val;
    val["id"] = 3;
    val["name"] = "烧茄子";
    val["price"] = 1300;

    //dish.Insert(val);
    //dish.Update(val);
    //dish.Delete(3);
    */
    Json::Value val;
    Json::StyledWriter writer;
    //dish.SelectAll(&val);
    dish.SelectOne(2, &val);
    std::cout << writer.write(val) <<std::endl;
}

void order_test()
{
    order_sys::TableOrder order;
    /*
    Json::Value val;
    val["id"] = 7;
    val["dishes"].append(2);
    val["dishes"].append(1);
    //order.Insert(val);
    val["status"] = 1;
    //order.Update(val);
    order.Delete(7);
    */
    Json::Value val;
    Json::StyledWriter writer;
    order.SelectAll(&val);
    std::cout << writer.write(val) << std::endl;
}

实现业务控制模块

1、搭建HTTP服务器(采用httplib来实现,httplib的流程前面已经介绍过,即:(1)实例化Server对象,(2)添加请求方法/资源路径对应回调接口信息—告诉Server对象对于什么请求使用哪个回调接口进行业务处理,(3)回调用户业务接口会传入请求信息(根据请求进行业务处理),需要用户填充的响应信息(组织HTTP响应),(4)回调接口调用完毕,httplib获取到填充完毕的http响应信息,然后根据http协议格式组织响应数据)
2、根据HTTP的请求进行业务逻辑处理(菜品信息和订单信息的增删改查)
3、组织HTTP响应返回给客户端
我们先将httplib.h导入到工程中(在github上有很多开源文件,直接克隆过来即可)
例如实现代码:

#include "httplib.h"
#include <iostream>

void HelloWorld(const httplib::Request &req,httplib::Response &rsp)
{
	std::cout<<"method:"<<req.method<<std::endl;
	std::cout<<"path:"<<req.path<<std::endl;
	std::cout<<"body:"<<req.body<<std::endl;
	rsp.status=200;//响应状态码
	rsp.body="<html><body><h1>HelloWorld</h1></body></html>";
	rsp.set_header("Content-Type","text/html");

	//std::string body="<html><body><h1>HelloWorld<</h1></body></html>";
	//rsp.set_content(body,body.size(),"text/html");
	return ;
}
int main()
{
	int a = 100;
	httplib::Server server;//实例化Server对象
	//server.Get(请求的资源路径,回调函数地址);
	//针对指定资源的GET请求,采用指定的回调函数---添加请求路由信息
	//server.Put(请求的资源路径,回调函数地址)
	//这些接口主要作用是添加了一张路由表---什么请求对应什么处理函数
	//请求来了就会从路由表中查看,有没有这个请求的处理函数,没有就返回404,有就进行相应请求
	server.Get("/helloworld",HelloWorld);
	server.Get("/hi",[&](const httplib::Request &req,httplib::Response &rsp){
			std::cout<<"a:"<<a<<std::endl;
			std::string body="<html><body><h1>Hi</h1></body></html>";
			rsp.set_content(body.c_str(),body.size(),"text/html");
			});

	server.listen("0.0.0.0",9000);//搭建http服务器
	return 0;
}

通过浏览器访问:
服务器IP:端口号/HelloWorld
服务器IP:端口号/HI
使用函数调用的方式来实现一个简单的http服务器,即在浏览器界面会显示HelloWorld,也可以使用lambda表达式来实现,会在浏览器上显示Hi。
上述这就是使用httplib来实现http服务器

接下来正式编写业务逻辑模块代码
我们主要是要实现收到请求向数据库执行相应操作(增删改查),从而响应到客户端,首先是对菜单信息的请求:
(1)插入菜品:获取菜品信息正文—json字符串,将json字符串解析成为json::Value对象,通过json::Value信息向数据库中插入菜品信息。
(2)删除菜品:获取菜品ID—id=req.matches[1],通过菜品id从数据库中删除一个菜品信息。
(3)更新菜品:获取菜品信息正文—json字符串,将json字符串解析成为json::Value对象,通过json::Value信息向数据库中更新菜品信息。
(4)查询菜品:(若是查询单个菜品,要先获取菜品id)从数据库中获取到菜品信息,存放到json::Value对象中,将json::Value对象序列化成为json字符串—json::FastWriter.write(json::Value),将序列化的字符串放到http响应正文中(通过set_content),响应给客户端。
接着是对订单信息的请求(与菜单信息相似):
(1)插入订单:获取订单信息正文,将json字符串解析成为json::Value对象,通过json::Value信息向数据库中插入订单信息。
(2)删除订单:获取订单id—id=req.matches[1],通过订单id从数据库中删除一个订单信息。
(3)更新订单:获取订单信息正文—json字符串,将json字符串解析为json::Value对象,通过json::Value信息向数据库中更新菜品信息。
(4)查询订单:(若是查询单个订单,要先获取订单id)从数据库中获取到菜品信息,存放到json::Value对象中,将json::Value对象序列化为json字符串—json::FastWriter.write(json::Value),将序列化的字符串放到http响应正文中(通过set_content),响应给客户端。
以下为业务逻辑模块main.cpp代码:

#include "db.hpp"
#include "httplib.h"


#define WWWROOT "./wwwroot"
using namespace httplib;

order_sys::TableDish *tb_dish = NULL;
order_sys::TableOrder *tb_order = NULL;
void DishInsert(const Request &req, Response &rsp)
{
    //1.业务处理
    //①.解析正文(json反序列化),得到菜品信息
    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 << "insert- dish parse error\n";
        return ;
    }   
    //②.将菜品信息插入数据库
    ret = tb_dish->Insert(dish);
    if(ret == false)
    {
        Json::Value reason;
        Json::FastWriter writer;
        reason["result"] = false;
        reason["reason"] = "mysql insert failed!";
        rsp.status = 500;
        rsp.body = writer.write(reason);
        rsp.set_header("Content-Type", "application/json");
        std::cout << "mysql insert dish error\n";
        return ;
    }
    //2.设置响应信息:响应状态码mttplib默认设置200
    //rsp.status = 200;
    return ;
}
void DishDelete(const Request &req, Response &rsp)
{
    //1.获取要删除的菜品id  /dish/id
    int dish_id = std::stoi(req.matches[1]);
    //2.数据库删除操作
    bool ret = tb_dish->Delete(dish_id);
    if(ret == false)
    {
        rsp.status = 500;
        std::cout << "mysql delete dish error\n";
        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 << "update- parse dish info failed\n";
        return ;
    }
    dish["id"] = dish_id;
    ret = tb_dish->Update(dish);
    if(ret == false)
    {
        rsp.status = 500;
        std::cout << "mysql update dish error\n";
        return ;
    }
    return ;
}
void DishGetAll(const Request &req, Response &rsp)
{
    Json::Value dishes;
    bool ret = tb_dish->SelectAll(&dishes);
    if(ret == false)
    {
        rsp.status = 500;
        std::cout << "selectall- mysql select dish error\n";
        return ;
    }
    Json::FastWriter writer;
    rsp.body = writer.write(dishes);
    rsp.set_header("Content-Type", "application/json");
    return ;
}
void DishGetOne(const Request &req, Response &rsp)
{
    int dish_id = std::stoi(req.matches[1]);
    Json::Value dish;
    bool ret = tb_dish->SelectOne(dish_id, &dish);
    if(ret == false)
    {
        rsp.status = 500;
        std::cout << "selecone- mysql select dish error\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;
        std::cout << "insert- parse order info failed\n";
        return ;
    }
    ret = tb_order->Insert(order);
    if(ret == false)
    {
        rsp.status = 500;
        std::cout << "insert- mysql insert order error\n";
        return ;
    }
    return ;
}
void OrderDelete(const Request &req, Response &rsp)
{
    int order_id = std::stoi(req.matches[1]);
    bool ret = tb_order->Delete(order_id);
    if(ret == false)
    {
        rsp.status = 500;
        std::cout << "delete- mysql delete order error\n";
        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 << "update- parse order info failed\n";
        return ;
    }
    order["id"] = order_id;
    ret = tb_order->Update(order);
    if(ret == false)
    {
        rsp.status = 500;
        std::cout << "update- mysql update order error\n";
        return ;
    }
    return ;
}
void OrderGetAll(const Request &req, Response &rsp)
{
    Json::Value orders;
    bool ret = tb_order->SelectAll(&orders);
    if(ret == false)
    {
        rsp.status = 500;
        std::cout << "selectAll- mysql get order error\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 = tb_order->SelectOne(order_id, &order);
    if(ret == false)
    {
        rsp.status = 500;
        std::cout << "selectOne- mysql getone order error\n";
        return ;
    }
    Json::FastWriter writer;
    rsp.body = writer.write(order);
    return ;
}
int main()
{
    tb_dish = new order_sys::TableDish();
    tb_order = new order_sys::TableOrder();
    Server server;
    //server.set_base_dir(静态资源默认根路径)
	//设置静态资源根目录之后,如果浏览器请求的是根目录下的静态资源,httplib就会自动的将资源数据读取出来返回给浏览器
    server.set_base_dir(WWWROOT);//设置前端页面相对的根目录
    server.Post("/dish", DishInsert);
    //正则表达式:(\d+)表示匹配一个数字字符一次或多次
    //正则表达式:()表示捕捉匹配括号中规则的文本
    //R"()"表示括号中的字符串去除特殊字符的特殊含义
    server.Delete(R"(/dish/(\d+))", DishDelete);
    server.Put(R"(/dish/(\d+))", DishUpdate);
    server.Get(R"(/dish/(\d+))", DishGetOne);
    server.Get(R"(/dish)", DishGetAll);

    server.Post("/order", OrderInsert);
    server.Delete(R"(/order/(\d+))", OrderDelete);
    server.Put(R"(/order/(\d+))", OrderUpdate);
    server.Get(R"(/order/(\d+))", OrderGetOne);
    server.Get(R"(/order)", OrderGetAll);

    server.listen("0.0.0.0", 9000);
    return 0;
}

执行命令g++ -std=c++11 main.cpp -o main -L/usr/lib/x86_64-linux-gnu -lmysqlclient -ljsoncpp -lpthread
也可以定义makefile文件执行make命令

//makefile
LFLAG =-L/usr/lib/x86_64-linux-gnu -lmysqlclient -ljsoncpp -lpthread
main:main.cpp db.hpp
       g++ -std=c++11 $^ -o $@ $(LFLAG)

生成main后执行,此时可以通过局部测试工具PostMan对各个操作进行测试

实现前端界面模块

在视图模块,也就是前端页面,主要实现菜品信息的浏览以及下单操作,如图为最终界面:
菜单界面:
在这里插入图片描述
管理界面:
在这里插入图片描述

前端主要是使用html/css/js/vue.js/jquery等来进行实现,
前端代码过于冗杂,这里只放了重点代码内容:
index.html如下:

<!--index.html-->

  <!-- Menu Area (Start) -->
  <section class="menu" id="menu-gallery">

    <div class="heading">
        <h2><span>Menu</span></h2>
    </div>

    <div class="content">
        <div class="box-container">
          <div class="menu-gallery active" id="Starters">
            <div class="menu-item" id="myorder">
              <img src="static/picture/11.jpg" alt="">
              <div class="content">
                <div class="intro">
                  <h3>ysy的小酒馆</h3>
                  <div class="price">菜单</div>
                </div>
                <div class="text" id="myorder">
                    <table class="table" style="width:100%;">
                        <thead>
                            <tr class="tou">
                                <th>名称</th>
                                <th>单价</th>
                                <th>操作</th>
                            </tr>
                        </thead>
                        <tfoot>
                            <tr>
                                <th colspan="3" style="text-align:right">
                                    <button type="button" class="btn btn-primary" v-on:click="insert_order()">下单</button>
                                    总价:{{get_total()}}
                                </th>
                            </tr>
                        </tfoot>
                        <tbody>
                            <tr v-for="dish in dishes" style="text-align:center">
                                <td>{{dish.name}}</td>
                                <td>{{dish.price/100}}</td>
                                <td>
                                    <div class="form-check">
                                        <label class="form-check-label">
                                            <input class="form-check-input" type="checkbox" v-model="dish.selected" />选中下单
                                        </label>
                                    </div>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>
              </div>
            </div>
          </div>
        </div>

      </div>
  </section>
  
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
	<script>
        var myorder = new Vue({
            el: '#myorder',
            data: {
                dishes: []
            },
            methods: {
                get_total:function()
                {
                    var total = 0;
                    for(i=0; i<this.dishes.length; i++)
                    {
                        if(this.dishes[i].selected)
                        {
                              total += (this.dishes[i].price / 100);
                        }
                    }
                    return total;
                },
                insert_order:function()
                {
                    var order = 
                        {
                            dishes:[]
                        }
                    for(i=0; i<this.dishes.length; i++)
                    {
                        if (this.dishes[i].selected)
                        {
                            order.dishes.push(this.dishes[i].id);
                        }
                    }
                    //ajax-其实就是一个http客户端
                    $.ajax({
                        url: "/order",
                        type: "post",
                        data: JSON.stringify(order),
                        success:function()
                        {
                            alert("下单成功");
                        }
                    })
                },
                get_alldishes:function()
                {
                    $.ajax({
                        url: "/dish",
                        type: "get",
                        context:this,
                        success:function(res, status, xhr)
                        {
                            this.dishes = res;
                        }
                    })
                }
            }
        })
        myorder.get_alldishes();
    </script>

admin.html如下

  <!-- admin.html -->
  <!-- Menu Area (Start) -->
  <section class="menu" id="menu-gallery">

    <div class="heading">
        <h2><span>Menu</span></h2>
    </div>

    <div class="content">
        <div class="box-container">
          <div class="menu-gallery active" id="Starters">
            <div class="menu-item" id="myorder">
              <img src="static/picture/11.jpg" alt="">
              <div class="content">
                <div class="intro">
                  <h3>ysy的小酒馆</h3>
                  <div class="price">
                      <button type="button" class="btn btn-primary" v-on:click="insert_show()">新增</button>
                  </div>
                </div>
                <div class="text" id="myorder">
                    <table class="table" style="width:100%;">
                        <thead>
                            <tr class="tou">
                                <th>名称</th>
                                <th>单价</th>
                                <th>操作</th>
                            </tr>
                        </thead>
                        <tfoot v-show="show_flag==true">
                            <tr>
                                <th>
                                    <input type="text" v-model="dish.name"/>
                                </th>
                                <th>
                                    <input type="text" v-model="dish.price"/>
                                  </th>
                                <th style="text-align:right">
                                    <button type="button" class="btn btn-primary" v-on:click="insert_dish()">提交</button>
                                </th>
                            </tr>
                        </tfoot>
                        <tbody>
                            <tr v-for="dish in dishes" style="text-align:center">
                                <td>
                                    <span  v-show="update_flag==false">{{dish.name}}</span>
                                    <span><input type="text" v-show="update_flag==true" v-model="dish.name" /></span>
                                </td>
                                <td >
                                    <span v-show="update_flag==false">{{dish.price/100}}</span>
                                    <span><input type="text" v-show="update_flag==true" v-model="dish.price" /></span>
                                </td>
                                
                                <td>
                                    <button type="button" class="btn btn-primary" v-show="update_flag==false" v-on:click="update_dishes">修改</button>
                                    <button type="button" class="btn btn-primary" v-show="update_flag==true" v-on:click="update_dish(dish.id)">提交</button>
                                    <button type="button" class="btn btn-primary" v-on:click="delete_dish(dish.id)">删除</button>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>
              </div>
            </div>
          </div>
        </div>

      </div>
  </section>
  
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
	<script>
        var myorder = new Vue({
            el: '#myorder',
            data: {
                dishes: [],
                update_flag: false,
                show_flag: false,
                dish: {
                    name: "",
                    price:0
                }
            },
            methods: {
                get_total:function()
                {
                    var total = 0;
                    for(i=0; i<this.dishes.length; i++)
                    {
                        if(this.dishes[i].selected)
                        {
                            total += (this.dishes[i].price / 100);
                        }
                    }
                    return total;
                },
                insert_order:function()
                {
                    var order = 
                        {
                            dishes:[]
                        }
                    for(i=0; i<this.dishes.length; i++)
                    {
                        if (this.dishes[i].selected)
                        {
                            order.dishes.push(this.dishes[i].id);
                        }
                    }
                    //ajax-其实就是一个http客户端
                    $.ajax({
                        url: "/order",
                        type: "post",
                        data: JSON.stringify(order),
                        success:function()
                        {
                            alert("下单成功");
                        }
                    })
                },
                get_alldishes:function()
                {
                    $.ajax({
                        url: "/dish",
                        type: "get",
                        context:this,
                        success:function(res, status, xhr)
                        {
                            this.dishes = res;
                        }
                    })
                },
                //增
                insert_show:function()
                {
                    this.show_flag = true;
                },
                insert_dish:function()
                {
                    this.dish.price *= 100;
                    $.ajax({
                        url: "/dish",
                        type: "post",
                        data: JSON.stringify(this.dish),
                        context:this,
                        success: function (res, status, xhr) {
                            this.get_alldishes();
                            this.show_flag = false;
                        }
                    })
                },
                //删
                delete_dish:function(dish_id)
                {
                    $.ajax({
                        url: "/dish/" + dish_id,
                        type: "delete",
                        data: JSON.stringify(this.dish),
                        context: this,
                        success: function (res, status, xhr) {
                            alert("删除成功");
                            this.get_alldishes();
                            this.show_flag = false;
                        }
                    })
                },
                //改
                update_dishes: function () {
                    this.update_flag = true;
                },
                update_dish:function(dish_id)
                {
                    //this.dish.price *= 100;
                    
                    for (i = 0; i < this.dishes.length; i++) {
                        if (this.dishes[i].id==dish_id) {
                            console.log("开始提交菜品更新,菜品ID:", dish_id);
                            console.log("待提交的菜品信息:", this.dishes[i]);
                            $.ajax({
                                url: "/dish/" + dish_id,
                                type: "put",
                                data: JSON.stringify(this.dishes[i]),
                                context: this,
                                success: function (res, status, xhr) {
                                    alert("修改成功");
                                    this.get_alldishes();
                                    this.update_flag = false;
                                },
                                error: function (xhr, status, error) {
                                    console.error("AJAX 请求失败:", error);
                                    alert("修改失败,请稍后重试");
                                }
                            })
                        }
                    }
                }
            }
        })
        myorder.get_alldishes();
    </script>

为了可以让前端界面与后台建立连接,只需要为main.cpp的main函数中添加server.set_base_dir("./wwwroot);代码(wwwroot是前端工程文件名),具体实现在业务处理模块中:这里仅截出前端界面链接代码:

    Server server;
    //server.set_base_dir(静态资源默认根路径)
	//设置静态资源根目录之后,如果浏览器请求的是根目录下的静态资源,httplib就会自动的将资源数据读取出来返回给浏览器
    server.set_base_dir(WWWROOT);//设置前端页面相对的根目录
  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值