基于C++的视频点播系统


项目描述

一个用户可以通过浏览器上传视频,且对自己上传的视频进行管理,而其他用户可以通过浏览器观看视频。


概要设计

采用不太严谨的MVC框架。此项目分模块进行设计——数据管理模块:对数据进行统一管理,外界只能通过此模块访问;用户界面/前端界面模块:实现用户交互,提供前端界面;业务处理模块:接收前端请求进行处理完成用户的需求。
在这里插入图片描述


技术调研

socket、http、tcp、json、mysql、前端三剑客(html、css、js)


详细设计

数据管理模块

1.数据存储

采用MySQL数据库——免费,采用c/s架构,可以远程访问以及有统一接口,安全便于扩展。

数据库表的设计
视频信息表:视频id、视频名称、视频描述、上传时间、视频文件路径、封面图路径。

create database if not exists vod_system;
use vod_system;

create table if not exists tb_video(
    id int primary key auto_increment,
    name varchar(32),
    vdesc text,
    video_url varchar(255),
    image_url varchar(255),
    ctime datetime);
insert tb_video values(null,"飞机大战","这是一部烂片",
"/video/plane.mp4","/image/plane.jpg",now());

2.封装实现数据库访问类

该类提供视频信息的增删改查(所有视频/单个视频);
数据库表的访问类的实现

1.了解mysql的c语言库接口

1.定义mysql句柄
2.初始化mysql句柄
3.连接mysql服务器
4.设置客户端字符编码集
5.切换选择数据库
6.执行语句(库,表,数据操作—sql语句的执行)增,删,改–只要语句执行成功,就表示完成了查-需要执行语句成功后对数据进行操作
①.将查询结果保存到本地
②.获取保存的结果集中的数据条数和列数3.遍历逐条取出结果集中的每一条数据4.释放结果集
7.关闭句柄,释放资源
8.获取某个接口执行失败原因的接口

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <mysql/mysql.h>

int main()
{
    MYSQL *mysql = NULL;//定义,ysql句柄
    mysql = mysql_init(NULL);//初始化mysql句柄
    if(mysql == NULL)
    {
        printf("mysql init error!\n");
        return -1;
    }
    //连接服务器mysql_real_connect(句柄,服务器IP,用户名,密码,库名称,
    //端口,套接字文件,客户端标志)
    if(mysql_real_connect(mysql,"127.0.0.1","root","ljl12138",
                "vod_system",0,NULL,0)==NULL)
    {
        printf("connect mysql failed:%s\n", mysql_error(mysql));
        return -1;
    }
    //设置客户端字符集
    int ret;
    ret = mysql_set_character_set(mysql,"utf8");
    if(ret != 0)
    {
        printf("set character failed:%s\n",mysql_error(mysql));
        return -1;
    }
    //选择数据库 mysql_select_db(mysql,"vod_system");
    //char * insert = "insert tb_video values(null,'变形金刚','婆媳战争',
    //'video/popo.mp4', '/image/xifu.jpg',now())";
    //执行语句 mysql_query(句柄,语句)
    //char *update = "update tb_video set vdesc = '大型家庭疯整篇' where id=2;";
    //char *delete = "delete from tb_video where id=2;";
    char *select = "select * from tb_video;";
    ret = mysql_query(mysql,select);
    if(ret != 0)
    {
        printf("query sql failed:%s\n", mysql_error(mysql));
        return -1;
    }
    //保存结果集到本地
    MYSQL_RES *res = mysql_store_result(mysql);
    if(res == NULL)
    {
        printf("store result failed:%s\n",mysql_error(mysql));
        return -1;
    }
    //获取结果集条数和列数
    int row_num = mysql_num_rows(res);
    int col_num = mysql_num_fields(res);
    int i = 0;
    for(i = 0;i<row_num;++i)
    {
        //逐条遍历获取结果集mysql_fetch_row(结果集)
        MYSQL_ROW row = mysql_fetch_row(res);
        int j = 0;
        for(j = 0; j<col_num; ++j)
        {
            printf("%s\t",row[j]);
        }
        printf("\n");

    }
    //释放结果集
    mysql_free_result(res);
    mysql_close(mysql);
    return 0;
}

jsoncpp的基本使用:

实现json格式的序列化与反序列化功能

json数据类型:对象 {} ,字符串,整数,布尔,数组[]。

{“学生”:1001,“姓名”:“张三”,“年龄”:18,“婚否”:false,“成绩”:[88,77,66]},

Json::Value 中间数据对象;
val[“学号”] = 1001;

Json::Writer 序列化对象,将Json::Value中的各个数据序列化为字符串;
Json::Writer 是基类一般使用它的子类:StyledWrite/FastWriter,后者为整行形式,会去掉空行,空格;前者为会添加换行,空格之类的。
接口:
std::string StyledWriter::write(val),将val按照json序列化格式序列化为字符串将其返回。

Json::Reader 反序列化对象,将一个json格式字符转换为Json::Value;
Reader::parse(const std::string &str,Json::Value &val)
将str进行反序列化,将其反序列化之后的结果放入val中,通过val形式获取值。

在安装使用json时需要先进行gcc的升级:gcc升级及jsoncpp安装

3.数据管理模块代码

因为表中字段有多个,所以使用json序列化将多个字段整合成一个参数传递起来会方便很多。


//数据管理模块
#include <iostream>
#include <mysql/mysql.h>
#include <jsoncpp/json/json.h>
#include <mutex>

namespace vod_system
{
#define MYSQL_HOST "127.0.0.1"
#define MYSQL_USER "root"
#define MYSQL_PASS "ljl12138"
#define MYSQL_NAME "vod_system"


    static MYSQL *MysqlInit()//初始化接口
    {
        MYSQL *mysql = mysql_init(NULL);//句柄初始化
        if(mysql == NULL)
        {
            std::cout<<"mysql init failed!\n";
            return NULL;
        }
        if(mysql_real_connect(mysql,MYSQL_HOST,MYSQL_USER,
                    MYSQL_PASS,MYSQL_NAME,0,NULL,0)==NULL)//连接服务器
        {
            std::cout<<mysql_error(mysql)<<std::endl;
            mysql_close(mysql);
            return NULL;
        }
        if(mysql_set_character_set(mysql,"utf8")!=0)
        {//设置字符集
            std::cout<<mysql_error(mysql)<<std::endl;
            mysql_close(mysql);
            return NULL;
        }
        return mysql;

    }
    static void MysqlRelease(MYSQL *mysql)//数据库释放接口
    {
        if(mysql != NULL)
        {
            mysql_close(mysql);
        }
        return;
    }
    static bool  MysqlQuery(MYSQL *mysql, const std::string sql)//执行语句操作接口
    {//执行接口封装
        int ret = mysql_query(mysql,sql.c_str());
        if(ret != 0)//执行失败
        {
         std::cout<<sql<<std::endl;//要执行的语句
         std::cout<<mysql_error(mysql)<<std::endl;
         return false;
        }
        return true;
    }
    /
    //数据库访问类
    class TableVod
    {
        private:
            MYSQL *_mysql;
            std::mutex _mutex;
        public:
            TableVod()//数据库句柄初始化连接服务器
            {
                _mysql = MysqlInit();
                if(_mysql == NULL)
                {
                    exit(0);
                }
            }
            ~TableVod()//数据库句柄销毁
            {
                MysqlRelease(_mysql);
            }

	    //增
            bool Insert(const Json::Value &video)
            {
               const char* name = video["name"].asCString();
               const char* vdesc = video["vdesc"].asCString();
               const char *video_url = video["video_url"].asCString();
               const char* image_url = video["image_url"].asCString();
                char sql[8192] = {0};
#define VIDEO_INSERT "insert tb_video values(null,'%s','%s','%s','%s',now());"
                sprintf(sql,VIDEO_INSERT, name,vdesc,video_url,image_url);
                return MysqlQuery(_mysql,sql);
            }

	    //删
            bool Delete(int video_id)
            {
#define VIDEO_DELETE "delete from tb_video where id=%d;"
                char sql[8192] = {0};
                sprintf(sql,VIDEO_DELETE,video_id);
                return MysqlQuery(_mysql,sql);
            }

	    //改
            bool Update(int video_id,const Json::Value &video)
            {
#define VIDEO_UPDATE "update tb_video set name='%s',vdesc='%s' where id=%d;"
                char sql[8192] = {0};
                sprintf(sql,VIDEO_UPDATE,video["name"].asCString(),
                        video["vdesc"].asCString(),
                        video_id);
                return MysqlQuery(_mysql,sql);
            }

	    //查
            bool GetAll(Json::Value *video)
            {
#define VIDEO_GETALL "select * from tb_video;"
                _mutex.lock();
                bool ret = MysqlQuery(_mysql,VIDEO_GETALL);//查询结果集
                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 val;
                    val["id"] = std::stoi(row[0]);
                    val["name"] = row[1];
                    val["vdesc"] = row[2];
                    val["video_url"] = row[3];
                    val["image_url"] = row[4];
                    val["ctime"] = row[5];
                    video->append(val);//添加数组元素,每一条都是一个数组元素
                }
                mysql_free_result(res);//释放结果集
                return true;
            }
            bool GetOne(int video_id,Json::Value *video)
            {
#define VIDEO_GETONE "select * from tb_video where id=%d;"
                char sql_str[4096] = {0};
                sprintf(sql_str,VIDEO_GETONE,video_id);
                _mutex.lock();
                bool ret = MysqlQuery(_mysql,sql_str);
                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_row = mysql_num_rows(res);
                if(num_row != 1)
                {
                    std::cout<<"getone result error\n";
                    mysql_free_result(res);
                    return false;
                }
                MYSQL_ROW row = mysql_fetch_row(res);//从结果集获取一条结果
                (*video)["id"] = video_id;
                (*video)["name"] = row[1];
                (*video)["vdesc"] = row[2];
                (*video)["video_url"] = row[3];
                (*video)["image_url"] = row[4];
                (*video)["ctime"] = row[5];
                mysql_free_result(res);
                return true;
            }
    };
}


前端界面模块

实现前端界面能够与用户进行交互

1.完成前端html界面的编写

html+css+js
html:标签化语言,实现浏览器对于最粗糙的界面的渲染;
css:层叠样式语言,实现对html进行样式美化;
js:javascript脚本语言,实现让界面动态渲染,本次我们使用vue.js进行前端页面的渲染,在使用vue.js前需要本地安装或者远程请求服务。

本次项目的界面并非从零开始编写,在网上找的模板中做些修改即可,在把前端界面初步完成之后,需要使用ajax进行交互

ajax
就像是http客户端,相当于当前界面分离的一个客户端与服务器进行数据交互,说白了ajax的作用就是,从后台获取到数据。在本次项目中,我们使用jquery ajax,使用前和vue.js一样需要本地安装或者远程请求服务。

前端界面:
负责展示当前服务器上的所有视频

单个视频播放界面:
视频播放界面需要指定到底要播哪个视频,所以需要回调函数,会用到字符串替换boost库,使用库前先安装。yum -y install boost boost_system


业务处理模块

接收前端请求进行业务处理最终响应

1.http服务器的搭建:

实现与前端的网络通信——接受客户端请求,使用httplib库完成http服务器的搭建。why不独立实现http,使用库项目难度降低,提高开发速度,用库比自己实现更为稳定。httplib可以帮助我们用更剪短的代码来搭建http服务器,用户只需要根据什么样的服务去做相应的处理就ok,从而不需要放心思至服务器的搭建而是更关注具体的业务。

httplib库
组成:
Server类:
服务端类;
用于搭建服务器,实现网络通信,解析http请求,组织http响应;
Server类中就一张map表。当我们实现一个服务端时,就会在里面填充信息,请求与处理函数的映射表。

Request结构体:
将http请求数据解析后就能得到这个类的对象,包含了一次http请求中的所有信息;

Response类:
响应信息类,通常其中的数据需要用户自己添加。
在这里插入图片描述

#include "httplib.h"

using namespace httplib;

void helloworld(const Request &req, Response &rsp)
{
    rsp.body = "<html><body><h1>Hello</h1></body></html>";
    rsp.status = 200;
    rsp.set_header("Content-Type", "text/html");
}
int main()
{
    httplib::Server srv;//实例化服务端对象
    srv.set_base_dir("./wwwroot");
    srv.Get("/hello",helloworld);
    srv.listen("0.0.0.0",9000);
    return 0;
}

在这里插入图片描述
正则表达式:
用来检索和替换符合文本规则的文本

2.请求与响应的网络通信接口设计

1.静态页面请求(首页,播放)

①GET/index.html HTTP/1.1(首页)
响应:
HTTP/1.1 200 OK
…(正文index.html文件数据)

②GET/video.html?id=1
响应:
HTTP/1.1 200 OK
…(正文video.html文件数据)

2.动态数据请求

视频数据信息的增删改查
多个视频对象的序列化设计——采用restful风格网络接口设计
1. 基于http,正文数据使用xml或者json格式进行序列化,我们采用json格式序列化;json是一种轻量化的数据交换格式,采用完全独立于编程语言的文本格式来存储和表示数据。
Json数值对象:数组、数字、字符串;
eg:表示多个学生信息[{name:“zhangsan”,age:18,score:[77,88,99],marry:false},{name:“zhangsan”,age:18,score:[77,88,99],marry:false}]

2. restful风格里面定义了四种操作类型:新增(POST)、获取(GET)、修改(PUT)、删除(DELETE)。

①新增视频信息:
请求:
POST /video HTTP/1.1
头部…
正文{name:“变形金刚”…}
响应:
<1>HTTP/1.1 200 OK
头部…
无正文
<2>HTTP/1.1 500 SEVER ERROR

{result:false,reason:“mysql err”}
(不适宜json格式,因为视频数据大,存在风险,使用http默认的文件上传操作html操作)
原生的文件上传,正文中分为多个表单数据域,每个域表示的是不同的提交的表单项(视频文件数据,封面图片数据,视频名称,视频描述)收到请求进行解析。
1.将视频文件数据,以及图片数据存储到对应文件中;
2.将视频路径,图片路径,视频名称,描述存储到数据库。

上传的视频文件重名如何处理?

当前做法:直接覆盖式写入
预想做法:每个用户上传的文件名都以一种独一无二的形式命名(时间戳+用户名+某种算法)。

上传的文件冗余重复(名字不同,数据实际相同)

当前做法:不作处理;
预想做法:计算每个文件的md5值存放到视频信息数据库中,每个上传的视频文件都要计算md5,然后到数据库中查找有没有相同md5的文件,如果有,则直接将url路径拿过来就行,不用存放冗余文件数据。

MD5: 是一种信息摘要算法,常用于文件数据的唯一标识,针对一个文件的数据进行大量用算得到一个md5值;文件内容一有差别得到的MD5值大不相同。Linux中MD5sum命令就是计算文件的MD5值。

②删除视频信息:
请求:
DELETE /video?id=1 HTTP/1.1

无正文
响应:
HTTP/1.1 200 OK

正确响应则无正文

③修改视频信息:
请求
PUT /video/1(或者/video?id=1) HTTP/1.1

{name:"", desc:"", …}
响应:
HTTP/1.1 200 OK

④获取视频信息:
获取所有:
请求:
GET /video HTTP/1.1

无正文
响应:
HTTP/1.1 200 OK

[{视频1信息},{视频2信息}…]

获取单个视频信息:
请求:
GET /video/1 HTTP/1.1

响应:
HTTP/1.1 200 OK

{视频信息}

http协议实现
http服务器:实质是tcp服务器,上层使用http协议约定数据格式。

协议格式:
首行:
①请求行:请求方法(GET/HEAD/POST/PUT…),URL(统一资源定位符http://user:pass@ip:port/path?key=val#ch),协议版本(0.9/1.0/1.1/2.0)
②协议行:协议版本,响应状态码,状态码描述;1××协议切换/2××正确处理/3××重定向/4××客户端错误/5××服务端错误

头部:
键值对组成的头部字段
Content-Type:正文类型
Content-Length:正文长度,解决http拈包问题
Connection:控制长短连接
Location:重定向新链接
Cookie、Set-Cookie:维护http通信状态–保存在客户端持续传输维护状态
session:保存在服务端,通过cookie传递sessionid,包含客户端隐私信息和状态信息

空行:
\r\n:间隔头部与正文,标识头部结束位置

正文:
提交响应的数据

在基本完成模块搭建之后,使用postman模拟客户端对服务端进行请求来交互。

#include <iostream>
#include <mysql/mysql.h>
#include <jsoncpp/json/json.h>
#include <mutex>
#include <fstream>

//数据管理模块

namespace vod_system
{
#define MYSQL_HOST "127.0.0.1"
#define MYSQL_USER "root"
#define MYSQL_PASS "ljl12138"
#define MYSQL_NAME "vod_system"


    static MYSQL *MysqlInit()//初始化接口
    {
        MYSQL *mysql = mysql_init(NULL);//句柄初始化
        if(mysql == NULL)
        {
            std::cout<<"mysql init failed!\n";
            return NULL;
        }
        if(mysql_real_connect(mysql,MYSQL_HOST,MYSQL_USER,
                    MYSQL_PASS,MYSQL_NAME,0,NULL,0)==NULL)//连接服务器
        {
            std::cout<<mysql_error(mysql)<<std::endl;
            mysql_close(mysql);
            return NULL;
        }
        if(mysql_set_character_set(mysql,"utf8")!=0)
        {//设置字符集
            std::cout<<mysql_error(mysql)<<std::endl;
            mysql_close(mysql);
            return NULL;
        }
        return mysql;

    }
    static void MysqlRelease(MYSQL *mysql)//数据库释放接口
    {
        if(mysql != NULL)
        {
            mysql_close(mysql);
        }
        return;
    }
    static bool  MysqlQuery(MYSQL *mysql, const std::string sql)//执行语句操作接口
    {//执行接口封装
        int ret = mysql_query(mysql,sql.c_str());
        if(ret != 0)//执行失败
        {
         std::cout<<sql<<std::endl;//要执行的语句
         std::cout<<mysql_error(mysql)<<std::endl;
         return false;
        }
        return true;
    }
    /
    //数据库访问类
    class TableVod
    {
        private:
            MYSQL *_mysql;
            std::mutex _mutex;
        public:
            TableVod()//数据库句柄初始化连接服务器
            {
                _mysql = MysqlInit();
                if(_mysql == NULL)
                {
                    exit(0);
                }
            }
            ~TableVod()//数据库句柄销毁
            {
                MysqlRelease(_mysql);
            }

	    //增
            bool Insert(const Json::Value &video)
            {
               const char* name = video["name"].asCString();
               const char* vdesc = video["vdesc"].asCString();
               const char *video_url = video["video_url"].asCString();
               const char* image_url = video["image_url"].asCString();
                char sql[8192] = {0};
#define VIDEO_INSERT "insert tb_video values(null,'%s','%s','%s','%s',now());"
                sprintf(sql,VIDEO_INSERT, name,vdesc,video_url,image_url);
                return MysqlQuery(_mysql,sql);
            }

	    //删
            bool Delete(int video_id)
            {
#define VIDEO_DELETE "delete from tb_video where id=%d;"
                char sql[8192] = {0};
                sprintf(sql,VIDEO_DELETE,video_id);
                return MysqlQuery(_mysql,sql);
            }

	    //改
            bool Update(int video_id,const Json::Value &video)
            {
#define VIDEO_UPDATE "update tb_video set name='%s',vdesc='%s' where id=%d;"
                char sql[8192] = {0};
                sprintf(sql,VIDEO_UPDATE,video["name"].asCString(),
                        video["vdesc"].asCString(),
                        video_id);
                return MysqlQuery(_mysql,sql);
            }

	    //查
            bool GetAll(Json::Value *video)
            {
#define VIDEO_GETALL "select * from tb_video;"
                _mutex.lock();
                bool ret = MysqlQuery(_mysql,VIDEO_GETALL);//查询结果集
                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 val;
                    val["id"] = std::stoi(row[0]);
                    val["name"] = row[1];
                    val["vdesc"] = row[2];
                    val["video_url"] = row[3];
                    val["image_url"] = row[4];
                    val["ctime"] = row[5];
                    video->append(val);//添加数组元素,每一条都是一个数组元素
                }
                mysql_free_result(res);//释放结果集
                return true;
            }
            bool GetOne(int video_id,Json::Value *video)
            {
#define VIDEO_GETONE "select * from tb_video where id=%d;"
                char sql_str[4096] = {0};
                sprintf(sql_str,VIDEO_GETONE,video_id);
                _mutex.lock();
                bool ret = MysqlQuery(_mysql,sql_str);
                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_row = mysql_num_rows(res);
                if(num_row != 1)
                {
                    std::cout<<"getone result error\n";
                    mysql_free_result(res);
                    return false;
                }
                MYSQL_ROW row = mysql_fetch_row(res);//从结果集获取一条结果
                (*video)["id"] = video_id;
                (*video)["name"] = row[1];
                (*video)["vdesc"] = row[2];
                (*video)["video_url"] = row[3];
                (*video)["image_url"] = row[4];
                (*video)["ctime"] = row[5];
                mysql_free_result(res);
                return true;
            }
    };
    class Util
    {
    public:
    	static bool WriteFile(const std::string &name,const std::string &content)
	{
		std::ofstream of;
		of.open(name,std::ios::binary);
		if(!of.is_open())
		{
			std::cout<<"open file failed!\n";
			return false;
		}
		of.write(content.c_str(),content.size());
		if(!of.good())
		{
			std::cout<<"write file failed!\n";
			return false;
		}
		of.close();
		return true;
	}
    };
}

主函数

#include <boost/algorithm/string.hpp>
#include "db.hpp"
#include "httplib.h"
#include <fstream>

#define WWWROOT "./wwwroot"

///video/**.mp4(数据库中的存储的的视频信息)

using namespace httplib;

vod_system::TableVod *tb_video;//why全局变量,因为httplib库是基于多线程



void VideoDelete(const Request &req, Response &rsp)
{
	//req.path = /video/1  req.matches存放正则表达式匹配到的内容
	//1.获取视频id
	int video_id= std::stoi(req.matches[1]);

	//2.从数据库中获取到对应视频信息
	Json::Value json_rsp;
	Json::FastWriter writer;
	Json::Value video;
	bool ret = tb_video->GetOne(video_id,&video);
	if(ret == false)
	{
		std::cout<< "mysql get video info failed!\n";
		rsp.status = 500;
		json_rsp["result"] = false;
		json_rsp["reason"] = "mysql get video info failed!";
		rsp.body = writer.write(json_rsp);
		rsp.set_header("Content-Type","application/json");
		return;
	}
	std::string vpath = WWWROOT + video["video_url"].asString();
	std::string ipath = WWWROOT + video["image_url"].asString();

	//3.删除视频文件,封面图文件
	//unlink删除指定名字的文件
	unlink(vpath.c_str());
	unlink(ipath.c_str());

	//4.删除数据库中的数据
	ret = tb_video->Delete(video_id);
	if(ret == false)
	{
		rsp.status = 500;
		std::cout<<"mysql delete video failed!\n";
		return;
	}
	return;
}

void VideoUpdate(const Request &req, Response &rsp)
{
    //1.获取视频id
	int video_id= std::stoi(req.matches[1]);
	Json::Value video;
	Json::Reader reader;
	bool ret = reader.parse(req.body ,video);//提交上来的需要修改的json序列化后的字符串
	if(ret ==false)
	{
		std::cout<<"update video : parse video json failed!\n";
		rsp.status = 400;//表示客户端错误
		return;
	}
	ret = tb_video->Update(video_id, video);
	if(ret == false)
	{
		std::cout<<"update video:mysql update failed!\n";
		rsp.status=5000;//服务器内部错误
		return;
	}
	return;
}

void VideoGetAll(const Request &req, Response &rsp)
{
    Json::Value videos;
	Json::FastWriter writer;
	bool ret = tb_video->GetAll(&videos);
	if(ret == false)
	{
		std::cout<<"getall video:mysql operation failed!\n";
		rsp.status = 500;
		return;
	}
	rsp.body = writer.write(videos);
	rsp.set_header("Content-Type", "application/json");
	
}

void VideoGetOne(const Request &req, Response &rsp)
{
    int video_id= std::stoi(req.matches[1]);
	Json::Value video;
	Json::FastWriter writer;
	bool ret = tb_video->GetOne(video_id,&video);
	if(ret == false)
	{
		std::cout<<"getone video:mysql operation failed!\n";
		rsp.status = 500;
		return;
	}
	rsp.body = writer.write(video);
	rsp.set_header("Content-Type", "application/json");
}

#define VIDEO_PATH "/video/"
#define IMAGE_PATH "/image/"
void VideoUpload(const Request &req, Response &rsp)
{
	//视频名称
    auto ret = req.has_file("video_name");//判断是否存在该字段
	if(ret == false)
	{
		std::cout<<"have no video name!\n";
		rsp.status = 400;//请求格式问题
		return;
	}
	const auto & file = req.get_file_value("video_name");//获取该字段对应的信息
	
	
	//视频描述
	ret = req.has_file("video_desc");
	if(ret == false)
	{
		std::cout<<"have no video desc!\n";
		rsp.status = 400;//请求格式问题
		return;
	}
	const auto& file1 = req.get_file_value("video_desc");
	

	//视频文件
	ret = req.has_file("video_file");
	if(ret == false)
	{
		std::cout<<"have no video file!\n";
		rsp.status = 400;//请求格式问题
		return;
	}
	const auto& file2 = req.get_file_value("video_file");
	

	//封面文件
	ret = req.has_file("image_file");
	if(ret == false)
	{
		std::cout<<"have no image file!\n";
		rsp.status = 400;//请求格式问题
		return;
	}
	const auto& file3 = req.get_file_value("image_file");
	const std::string &videoname = file.content;//视频名
	const std::string &videodesc = file1.content;//描述
	const std::string& videofile = file2.filename;//***.mp4
	const std::string& videocont = file2.content;//视频文件数据
	const std::string &imagefile = file3.filename;//***。jpg
	const std::string &imagecont = file3.content;//封面文件数据

	///组织路径
	std::string vurl = VIDEO_PATH + file2.filename;
	std::string iurl = IMAGE_PATH + file3.filename;
	std::string wwwroot = WWWROOT;//因为WWWROOT是const char *没有重载+
	vod_system::Util::WriteFile(wwwroot + vurl,file2.content);//组织出来的实际路径并完成文件写入
	
	vod_system::Util::WriteFile(wwwroot + iurl,file3.content);
	
	Json::Value video;
	video["name"] = videoname;
	video["vdesc"] = videodesc;
	video["video_url"] = vurl;
	video["image_url"] = iurl;

	ret = tb_video->Insert(video);
	if(ret == false)
	{
		rsp.status = 500;//服务器内部错误
		std::cout<<"insert video: mysql operation failed!\n";
		return;
	}
    rsp.set_redirect("/");
    return;

}

bool ReadFile(const std::string &name, std::string *body)
{
    std::ifstream ifile;
    ifile.open(name, std::ios::binary);
    if(!ifile.is_open())
    {
        printf("open file failed111:%s\n",name.c_str());
        ifile.close();
        return false;
    }
    ifile.seekg(0,std::ios::end);
    uint64_t length = ifile.tellg();
    ifile.seekg(0,std::ios::beg);
    body->resize(length);
    ifile.read(&(*body)[0],length);
    if(ifile.good() == false)
    {
        printf("read file failed:%s\n", name.c_str());
        ifile.close();
        return false;
    }
    ifile.close();
    return true;
}

void VideoPlay(const Request &req, Response &rsp)
{
    Json::Value video;
    int video_id = std::stoi(req.matches[1]);
	bool ret = tb_video->GetOne(video_id,&video);
	if(ret == false)
	{
		std::cout<<"getone video:mysql operation failed!\n";
		rsp.status = 500;
		return;
    }
    std::string newstr = video["video_url"].asString();
    std::string oldstr = "{{video_url}}";
    std::string play_html = "./wwwroot/single-video.html";
    ReadFile(play_html,&rsp.body);
    boost::algorithm::replace_all(rsp.body,oldstr,newstr);
    rsp.set_header("Content-Type", "text/html");
    return;

}

int main()
{
	tb_video = new vod_system::TableVod();

    Server srv;
	srv.set_base_dir("./wwwroot");
	///动态数据请求
    srv.Delete(R"(/video/(\d+))",VideoDelete);//正则表达式,\d表示匹配一个数字字符
            //+表示匹配字符一次或多次 
            //R"(string)"去除括号中字符串中每个字符的特殊含义
    srv.Put(R"(/video/(\d+))",VideoUpdate);
    srv.Get(R"(/video)",VideoGetAll);
    srv.Get(R"(/video(\d+))",VideoGetOne);
    srv.Post(R"(/video)",VideoUpload);
    srv.Get(R"(/play/(\d+))",VideoPlay);
    srv.listen("0.0.0.0",9000);//监听

    return 0;
}

/*//插入测试
void test()
{
    vod_system::TableVod tb_vod;
    Json::Value val;
    val["name"] = "电锯惊魂2";
    val["vdesc"] = "这是个比较净损的电影";
    val["video_url"] = "/video/saw2.mp4";
    val["image_url"] = "/video/saw2.jpg";
    tb_vod.Insert(val);
    return;
}*/

/*
void test()//查询测试
{
    vod_system::TableVod tb_vod;
    Json::Value val;
    tb_vod.GetOne(3,&val);
    Json::StyledWriter writer;
    std::cout<<writer.write(val)<<std::endl;

    return;
    
}*/

/*
void test()//删除测试
{
    vod_system::TableVod tb_vod;
    Json::Value val;
    val["name"] = "电锯惊魂";
    val["vdesc"] = "这是个比较净损的电影";
    val["video_url"] = "/video/saw.mp4";
    val["image_url"] = "/video/saw.jpg";
    tb_vod.Delete(2);
    return;
}*/

/*
void test()//修改测试
{
    vod_system::TableVod tb_vod;
    Json::Value val;
    val["name"] = "电锯惊魂";
    val["vdesc"] = "这是个很血腥的电影";
    val["video_url"] = "/video/saw.mp4";
    val["image_url"] = "/video/saw.jpg";
    tb_vod.Update(2,val);
    return;
}*/



/*void test1()
{
    vod_system::TableVod tb_vod;
    Json::Value val;
    val["name"] = "速度与激情9";
    val["vdesc"] = "这是个非常刺激的电影";
    val["video_url"] = "/video/speed.mp4";
    val["image_url"] = "/video/speed.jpg";
    tb_vod.Insert(val);
    return;
}*/
/*
int main()
{
    //局部功能测试
    test();
    return 0;
}*/


总结

项目源码

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值