基于C++的视频点播系统
視頻點播系統(tǒng)
- 項目描述
- 概要設(shè)計
- 技術(shù)調(diào)研
 
- 詳細(xì)設(shè)計
- 數(shù)據(jù)管理模塊
- 1.數(shù)據(jù)存儲
- 2.封裝實現(xiàn)數(shù)據(jù)庫訪問類
- 1.了解mysql的c語言庫接口
- jsoncpp的基本使用:
 
- 3.數(shù)據(jù)管理模塊代碼
 
- 前端界面模塊
- 1.完成前端html界面的編寫
 
- 業(yè)務(wù)處理模塊
- 1.http服務(wù)器的搭建:
- 2.請求與響應(yīng)的網(wǎng)絡(luò)通信接口設(shè)計
- 1.靜態(tài)頁面請求(首頁,播放)
- 2.動態(tài)數(shù)據(jù)請求
- 上傳的視頻文件重名如何處理?
- 上傳的文件冗余重復(fù)(名字不同,數(shù)據(jù)實際相同)
 
 
 
 
- 總結(jié)
項目描述
一個用戶可以通過瀏覽器上傳視頻,且對自己上傳的視頻進(jìn)行管理,而其他用戶可以通過瀏覽器觀看視頻。
概要設(shè)計
采用不太嚴(yán)謹(jǐn)?shù)?strong>MVC框架。此項目分模塊進(jìn)行設(shè)計——數(shù)據(jù)管理模塊:對數(shù)據(jù)進(jìn)行統(tǒng)一管理,外界只能通過此模塊訪問;用戶界面/前端界面模塊:實現(xiàn)用戶交互,提供前端界面;業(yè)務(wù)處理模塊:接收前端請求進(jìn)行處理完成用戶的需求。
 
技術(shù)調(diào)研
socket、http、tcp、json、mysql、前端三劍客(html、css、js)
詳細(xì)設(shè)計
數(shù)據(jù)管理模塊
1.數(shù)據(jù)存儲
采用MySQL數(shù)據(jù)庫——免費(fèi),采用c/s架構(gòu),可以遠(yuǎn)程訪問以及有統(tǒng)一接口,安全便于擴(kuò)展。
數(shù)據(jù)庫表的設(shè)計:
 視頻信息表:視頻id、視頻名稱、視頻描述、上傳時間、視頻文件路徑、封面圖路徑。
2.封裝實現(xiàn)數(shù)據(jù)庫訪問類
該類提供視頻信息的增刪改查(所有視頻/單個視頻);
 數(shù)據(jù)庫表的訪問類的實現(xiàn)
1.了解mysql的c語言庫接口
1.定義mysql句柄
 2.初始化mysql句柄
 3.連接mysql服務(wù)器
 4.設(shè)置客戶端字符編碼集
 5.切換選擇數(shù)據(jù)庫
 6.執(zhí)行語句(庫,表,數(shù)據(jù)操作—sql語句的執(zhí)行)增,刪,改–只要語句執(zhí)行成功,就表示完成了查-需要執(zhí)行語句成功后對數(shù)據(jù)進(jìn)行操作
 ①.將查詢結(jié)果保存到本地
 ②.獲取保存的結(jié)果集中的數(shù)據(jù)條數(shù)和列數(shù)3.遍歷逐條取出結(jié)果集中的每一條數(shù)據(jù)4.釋放結(jié)果集
 7.關(guān)閉句柄,釋放資源
 8.獲取某個接口執(zhí)行失敗原因的接口
jsoncpp的基本使用:
實現(xiàn)json格式的序列化與反序列化功能
json數(shù)據(jù)類型:對象 {} ,字符串,整數(shù),布爾,數(shù)組[]。
{“學(xué)生”:1001,“姓名”:“張三”,“年齡”:18,“婚否”:false,“成績”:[88,77,66]},
Json::Value 中間數(shù)據(jù)對象;
 val[“學(xué)號”] = 1001;
Json::Writer 序列化對象,將Json::Value中的各個數(shù)據(jù)序列化為字符串;
 Json::Writer 是基類一般使用它的子類:StyledWrite/FastWriter,后者為整行形式,會去掉空行,空格;前者為會添加換行,空格之類的。
 接口:
 std::string StyledWriter::write(val),將val按照json序列化格式序列化為字符串將其返回。
Json::Reader 反序列化對象,將一個json格式字符轉(zhuǎn)換為Json::Value;
 Reader::parse(const std::string &str,Json::Value &val)
 將str進(jìn)行反序列化,將其反序列化之后的結(jié)果放入val中,通過val形式獲取值。
在安裝使用json時需要先進(jìn)行g(shù)cc的升級:gcc升級及jsoncpp安裝
3.數(shù)據(jù)管理模塊代碼
因為表中字段有多個,所以使用json序列化將多個字段整合成一個參數(shù)傳遞起來會方便很多。
//數(shù)據(jù)管理模塊 #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)//連接服務(wù)器{std::cout<<mysql_error(mysql)<<std::endl;mysql_close(mysql);return NULL;}if(mysql_set_character_set(mysql,"utf8")!=0){//設(shè)置字符集std::cout<<mysql_error(mysql)<<std::endl;mysql_close(mysql);return NULL;}return mysql;}static void MysqlRelease(MYSQL *mysql)//數(shù)據(jù)庫釋放接口{if(mysql != NULL){mysql_close(mysql);}return;}static bool MysqlQuery(MYSQL *mysql, const std::string sql)//執(zhí)行語句操作接口{//執(zhí)行接口封裝int ret = mysql_query(mysql,sql.c_str());if(ret != 0)//執(zhí)行失敗{std::cout<<sql<<std::endl;//要執(zhí)行的語句std::cout<<mysql_error(mysql)<<std::endl;return false;}return true;}///數(shù)據(jù)庫訪問類class TableVod{private:MYSQL *_mysql;std::mutex _mutex;public:TableVod()//數(shù)據(jù)庫句柄初始化連接服務(wù)器{_mysql = MysqlInit();if(_mysql == NULL){exit(0);}}~TableVod()//數(shù)據(jù)庫句柄銷毀{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);//查詢結(jié)果集if(ret ==false){_mutex.unlock();return false;}MYSQL_RES * res = mysql_store_result(_mysql);//保存結(jié)果集_mutex.unlock();if(res ==NULL){std::cout<<"store result failed!\n";return false;}int num = mysql_num_rows(res);//獲取結(jié)果集條數(shù)for(int i = 0;i<num;++i){MYSQL_ROW row = mysql_fetch_row(res);//遍歷結(jié)果集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);//添加數(shù)組元素,每一條都是一個數(shù)組元素}mysql_free_result(res);//釋放結(jié)果集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);//從結(jié)果集獲取一條結(jié)果(*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;}}; }
前端界面模塊
實現(xiàn)前端界面能夠與用戶進(jìn)行交互
1.完成前端html界面的編寫
html+css+js
 html:標(biāo)簽化語言,實現(xiàn)瀏覽器對于最粗糙的界面的渲染;
 css:層疊樣式語言,實現(xiàn)對html進(jìn)行樣式美化;
 js:javascript腳本語言,實現(xiàn)讓界面動態(tài)渲染,本次我們使用vue.js進(jìn)行前端頁面的渲染,在使用vue.js前需要本地安裝或者遠(yuǎn)程請求服務(wù)。
本次項目的界面并非從零開始編寫,在網(wǎng)上找的模板中做些修改即可,在把前端界面初步完成之后,需要使用ajax進(jìn)行交互
ajax :
 就像是http客戶端,相當(dāng)于當(dāng)前界面分離的一個客戶端與服務(wù)器進(jìn)行數(shù)據(jù)交互,說白了ajax的作用就是,從后臺獲取到數(shù)據(jù)。在本次項目中,我們使用jquery ajax,使用前和vue.js一樣需要本地安裝或者遠(yuǎn)程請求服務(wù)。
前端界面:
 負(fù)責(zé)展示當(dāng)前服務(wù)器上的所有視頻
單個視頻播放界面:
 視頻播放界面需要指定到底要播哪個視頻,所以需要回調(diào)函數(shù),會用到字符串替換boost庫,使用庫前先安裝。yum -y install boost boost_system
業(yè)務(wù)處理模塊
接收前端請求進(jìn)行業(yè)務(wù)處理最終響應(yīng)
1.http服務(wù)器的搭建:
實現(xiàn)與前端的網(wǎng)絡(luò)通信——接受客戶端請求,使用httplib庫完成http服務(wù)器的搭建。why不獨(dú)立實現(xiàn)http,使用庫項目難度降低,提高開發(fā)速度,用庫比自己實現(xiàn)更為穩(wěn)定。httplib可以幫助我們用更剪短的代碼來搭建http服務(wù)器,用戶只需要根據(jù)什么樣的服務(wù)去做相應(yīng)的處理就ok,從而不需要放心思至服務(wù)器的搭建而是更關(guān)注具體的業(yè)務(wù)。
httplib庫:
 組成:
 Server類:
 服務(wù)端類;
 用于搭建服務(wù)器,實現(xiàn)網(wǎng)絡(luò)通信,解析http請求,組織http響應(yīng);
 Server類中就一張map表。當(dāng)我們實現(xiàn)一個服務(wù)端時,就會在里面填充信息,請求與處理函數(shù)的映射表。
Request結(jié)構(gòu)體:
 將http請求數(shù)據(jù)解析后就能得到這個類的對象,包含了一次http請求中的所有信息;
Response類:
 響應(yīng)信息類,通常其中的數(shù)據(jù)需要用戶自己添加。
 
 正則表達(dá)式:
 用來檢索和替換符合文本規(guī)則的文本
2.請求與響應(yīng)的網(wǎng)絡(luò)通信接口設(shè)計
1.靜態(tài)頁面請求(首頁,播放)
①GET/index.html HTTP/1.1(首頁)
 響應(yīng):
 HTTP/1.1 200 OK
 …(正文index.html文件數(shù)據(jù))
②GET/video.html?id=1
 響應(yīng):
 HTTP/1.1 200 OK
 …(正文video.html文件數(shù)據(jù))
2.動態(tài)數(shù)據(jù)請求
視頻數(shù)據(jù)信息的增刪改查
 多個視頻對象的序列化設(shè)計——采用restful風(fēng)格網(wǎng)絡(luò)接口設(shè)計
 1. 基于http,正文數(shù)據(jù)使用xml或者json格式進(jìn)行序列化,我們采用json格式序列化;json是一種輕量化的數(shù)據(jù)交換格式,采用完全獨(dú)立于編程語言的文本格式來存儲和表示數(shù)據(jù)。
 Json數(shù)值對象:數(shù)組、數(shù)字、字符串;
 eg:表示多個學(xué)生信息[{name:“zhangsan”,age:18,score:[77,88,99],marry:false},{name:“zhangsan”,age:18,score:[77,88,99],marry:false}]
2. restful風(fēng)格里面定義了四種操作類型:新增(POST)、獲取(GET)、修改(PUT)、刪除(DELETE)。
①新增視頻信息:
 請求:
 POST /video HTTP/1.1
 頭部…
 正文{name:“變形金剛”…}
 響應(yīng):
 <1>HTTP/1.1 200 OK
 頭部…
 無正文
 <2>HTTP/1.1 500 SEVER ERROR
 …
 {result:false,reason:“mysql err”}
 (不適宜json格式,因為視頻數(shù)據(jù)大,存在風(fēng)險,使用http默認(rèn)的文件上傳操作html操作)
 原生的文件上傳,正文中分為多個表單數(shù)據(jù)域,每個域表示的是不同的提交的表單項(視頻文件數(shù)據(jù),封面圖片數(shù)據(jù),視頻名稱,視頻描述)收到請求進(jìn)行解析。
 1.將視頻文件數(shù)據(jù),以及圖片數(shù)據(jù)存儲到對應(yīng)文件中;
 2.將視頻路徑,圖片路徑,視頻名稱,描述存儲到數(shù)據(jù)庫。
上傳的視頻文件重名如何處理?
當(dāng)前做法:直接覆蓋式寫入
 預(yù)想做法:每個用戶上傳的文件名都以一種獨(dú)一無二的形式命名(時間戳+用戶名+某種算法)。
上傳的文件冗余重復(fù)(名字不同,數(shù)據(jù)實際相同)
當(dāng)前做法:不作處理;
 預(yù)想做法:計算每個文件的md5值存放到視頻信息數(shù)據(jù)庫中,每個上傳的視頻文件都要計算md5,然后到數(shù)據(jù)庫中查找有沒有相同md5的文件,如果有,則直接將url路徑拿過來就行,不用存放冗余文件數(shù)據(jù)。
MD5: 是一種信息摘要算法,常用于文件數(shù)據(jù)的唯一標(biāo)識,針對一個文件的數(shù)據(jù)進(jìn)行大量用算得到一個md5值;文件內(nèi)容一有差別得到的MD5值大不相同。Linux中MD5sum命令就是計算文件的MD5值。
②刪除視頻信息:
 請求:
 DELETE /video?id=1 HTTP/1.1
 …
 無正文
 響應(yīng):
 HTTP/1.1 200 OK
 …
 正確響應(yīng)則無正文
③修改視頻信息:
 請求:
 PUT /video/1(或者/video?id=1) HTTP/1.1
 …
 {name:"", desc:"", …}
 響應(yīng):
 HTTP/1.1 200 OK
 …
④獲取視頻信息:
 獲取所有:
 請求:
 GET /video HTTP/1.1
 …
 無正文
 響應(yīng):
 HTTP/1.1 200 OK
 …
 [{視頻1信息},{視頻2信息}…]
獲取單個視頻信息:
 請求:
 GET /video/1 HTTP/1.1
 …
 響應(yīng):
 HTTP/1.1 200 OK
 …
 {視頻信息}
http協(xié)議實現(xiàn)
 http服務(wù)器:實質(zhì)是tcp服務(wù)器,上層使用http協(xié)議約定數(shù)據(jù)格式。
協(xié)議格式:
 首行:
 ①請求行:請求方法(GET/HEAD/POST/PUT…),URL(統(tǒng)一資源定位符http://user:pass@ip:port/path?key=val#ch),協(xié)議版本(0.9/1.0/1.1/2.0)
 ②協(xié)議行:協(xié)議版本,響應(yīng)狀態(tài)碼,狀態(tài)碼描述;1××協(xié)議切換/2××正確處理/3××重定向/4××客戶端錯誤/5××服務(wù)端錯誤
頭部:
 鍵值對組成的頭部字段
 Content-Type:正文類型
 Content-Length:正文長度,解決http拈包問題
 Connection:控制長短連接
 Location:重定向新鏈接
 Cookie、Set-Cookie:維護(hù)http通信狀態(tài)–保存在客戶端持續(xù)傳輸維護(hù)狀態(tài)
 session:保存在服務(wù)端,通過cookie傳遞sessionid,包含客戶端隱私信息和狀態(tài)信息
空行:
 \r\n:間隔頭部與正文,標(biāo)識頭部結(jié)束位置
正文:
 提交響應(yīng)的數(shù)據(jù)
在基本完成模塊搭建之后,使用postman模擬客戶端對服務(wù)端進(jìn)行請求來交互。
#include <iostream> #include <mysql/mysql.h> #include <jsoncpp/json/json.h> #include <mutex> #include <fstream>//數(shù)據(jù)管理模塊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)//連接服務(wù)器{std::cout<<mysql_error(mysql)<<std::endl;mysql_close(mysql);return NULL;}if(mysql_set_character_set(mysql,"utf8")!=0){//設(shè)置字符集std::cout<<mysql_error(mysql)<<std::endl;mysql_close(mysql);return NULL;}return mysql;}static void MysqlRelease(MYSQL *mysql)//數(shù)據(jù)庫釋放接口{if(mysql != NULL){mysql_close(mysql);}return;}static bool MysqlQuery(MYSQL *mysql, const std::string sql)//執(zhí)行語句操作接口{//執(zhí)行接口封裝int ret = mysql_query(mysql,sql.c_str());if(ret != 0)//執(zhí)行失敗{std::cout<<sql<<std::endl;//要執(zhí)行的語句std::cout<<mysql_error(mysql)<<std::endl;return false;}return true;}///數(shù)據(jù)庫訪問類class TableVod{private:MYSQL *_mysql;std::mutex _mutex;public:TableVod()//數(shù)據(jù)庫句柄初始化連接服務(wù)器{_mysql = MysqlInit();if(_mysql == NULL){exit(0);}}~TableVod()//數(shù)據(jù)庫句柄銷毀{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);//查詢結(jié)果集if(ret ==false){_mutex.unlock();return false;}MYSQL_RES * res = mysql_store_result(_mysql);//保存結(jié)果集_mutex.unlock();if(res ==NULL){std::cout<<"store result failed!\n";return false;}int num = mysql_num_rows(res);//獲取結(jié)果集條數(shù)for(int i = 0;i<num;++i){MYSQL_ROW row = mysql_fetch_row(res);//遍歷結(jié)果集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);//添加數(shù)組元素,每一條都是一個數(shù)組元素}mysql_free_result(res);//釋放結(jié)果集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);//從結(jié)果集獲取一條結(jié)果(*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;}}; }主函數(shù)
#include <boost/algorithm/string.hpp> #include "db.hpp" #include "httplib.h" #include <fstream>#define WWWROOT "./wwwroot"///video/**.mp4(數(shù)據(jù)庫中的存儲的的視頻信息)using namespace httplib;vod_system::TableVod *tb_video;//why全局變量,因為httplib庫是基于多線程void VideoDelete(const Request &req, Response &rsp) {//req.path = /video/1 req.matches存放正則表達(dá)式匹配到的內(nèi)容//1.獲取視頻idint video_id= std::stoi(req.matches[1]);//2.從數(shù)據(jù)庫中獲取到對應(yīng)視頻信息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.刪除數(shù)據(jù)庫中的數(shù)據(jù)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.獲取視頻idint 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;//服務(wù)器內(nèi)部錯誤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");//獲取該字段對應(yīng)的信息//視頻描述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;//***.mp4const std::string& videocont = file2.content;//視頻文件數(shù)據(jù)const std::string &imagefile = file3.filename;//***。jpgconst std::string &imagecont = file3.content;//封面文件數(shù)據(jù)///組織路徑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;//服務(wù)器內(nèi)部錯誤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");///動態(tài)數(shù)據(jù)請求srv.Delete(R"(/video/(\d+))",VideoDelete);//正則表達(dá)式,\d表示匹配一個數(shù)字字符//+表示匹配字符一次或多次 //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);//監(jiān)聽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; }*/總結(jié)
項目源碼
總結(jié)
以上是生活随笔為你收集整理的基于C++的视频点播系统的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: AI时代下的围棋
- 下一篇: 我的世界圈服务器领地显示无效领地,我的世
