视频点播系统
项目描述
一个用户可以通过浏览器上传视频,且对自己上传的视频进行管理,而其他用户可以通过浏览器观看视频。
概要设计
采用不太严谨的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;
}*/