小酒馆点餐系统实现-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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值