目录
一、.项目介绍
二、项目工具类的实现
1.文件处理类
(1.)结构
(2)判断文件是否存在
(3) 获取文件大小
(4)读取文件数据
(5) 写入文件数据
(6)创建目录
2,json工具类
(1)序列化
(2)反序列化
3 测试
(1)文件测试
(2)json测试
2,数据库操作类
(1)初始化
(2)销毁
(3)执行增删改sql语句
(4)类结构设计
(5) 增加数据
(6)修改数据
(7)删除数据
(8)查找数据
(9) 测试
二、服务端实现
1.接口设计
2,功能实现
(1)新增数据
(2)删除数据
(3)修改数据
(4)查找数据
三、服务端测试
四、全部代码链接
视频存储播放修改软件支持一下内容
1,视频的上传(视频与封面)
2,视频的修改(名称与描述)
3,视频的删除(删除名称、描述、视频内容)
4,视频的查找(查找想看的视频)
使用一个string 对象来初始化要处理的文件名称
c语言的access函数,存在返回0,失败返回-1。
第二个参数有
F_OK:是否存在
R_OK:是否可读
W_OK;是否可写
X_OK;是否可执行
接口实现
使用c语言函数stat 来获文件属性
我们只需要文件大小 st_size:
代码实现:
按照输出形参数返回,采用c++的io流,用二进制(binary)的方式读取。
c++io流写入:
mkdir函数:第二个参数是给定创建目录的权限。
json主要就是进行序列化与反序列化嘛。
把结构化数据,序列化成为string 对象
把string 对象反序列化为结构化数据
数据库要连接的服务器和数据库等信息
初始化一个mysql句柄:
连接数据库
设置字符格式:
一个必要的sql句柄
mutex:互斥锁:
对线程下,多个用户对数据库进行操作会有线程不安全的文件,需要加锁保证多线程的安全。
析构的时候释放资源
首先介绍我们的数据格式,分为四部分。
数据库aod_system的表 tb_video;表:
值得强调的是,我们的数据库里面保存的不是图片和视频,那样126格字符是存不下的,我们保存的是资源的所在的路径。
视频id:id 自增的,可以充当主键,一般也是比较推荐这样设置
视频名字:name
视频简介:info
视频路径:video
视频封面图片路径:image
sql insert语句插入数据:
通过sql update语句:修改视频名字和简介
通过sql delete语句:
通过sql select 语句查找:
三种查找都差不多,就是sql查找筛选语句不一样,其他地方类似处理。
查找所有
查找单个
查找相似
新增数据库
static void Insert(const httplib::Request &req, httplib::Response &rsp);
删除数据库
static void Delete(const httplib::Request &req, httplib::Response &rsp);
修改数据库
static void Update(const httplib::Request &req, httplib::Response &rsp) ;
查找一个数据库
static void SelectOne(const httplib::Request &req, httplib::Response &rsp);
查找所有
static void SelectAll(const httplib::Request &req, httplib::Response &rsp);
类成员:端口号和http库的服务端
static void Insert(const httplib::Request &req, httplib::Response &rsp)
{
// 检查用户请求是否合理正确。
if (req.has_file("name") == false ||
req.has_file("info") == false ||
req.has_file("video") == false ||
req.has_file("image") == false)
{
rsp.status = 400;
rsp.body = R"({"result":false, "reason":"上传的数据信息错误"})";
rsp.set_header("Content-Type", "application/json");
return;
}
httplib::MultipartFormData name = req.get_file_value("name"); // 视频名称
httplib::MultipartFormData info = req.get_file_value("info"); // 视频简介
httplib::MultipartFormData video = req.get_file_value("video"); // 视频文件
httplib::MultipartFormData image = req.get_file_value("image"); // 图片文件
// MultipartFormData {name, content_type, filename, content}
std::string video_name = name.content;
std::string video_info = info.content;
// ./www/image/变形金刚a.jpg
std::string root = WWWROOT;
std::string video_path = root + VIDEO_ROOT + video_name + video.filename;
std::string image_path = root + IMAGE_ROOT + video_name + image.filename;
// 加载视频到对应的文件video_path路径去。
if (FileUtil(video_path).SetContent(video.content) == false)
{
rsp.status = 500;
rsp.body = R"({"result":false, "reason":"视频文件存储失败"})";
rsp.set_header("Content-Type", "application/json");
return;
}
// 加载封面图片到对应的文件image_path路径去。
if (FileUtil(image_path).SetContent(image.content) == false)
{
rsp.status = 500;
rsp.body = R"({"result":false, "reason":"图片文件存储失败"})";
rsp.set_header("Content-Type", "application/json");
return;
}
//把文件属性插入到数据库中去。
//注意 图片 和 视频 在数据库中保存的是路径,不是他们的真实的数据。
Json::Value video_json;
video_json["name"] = video_name;
video_json["info"] = video_info;
video_json["video"] = VIDEO_ROOT + video_name + video.filename; // /video/变形金刚robot.mp4
video_json["image"] = IMAGE_ROOT + video_name + image.filename; // /video/变形金刚robot.mp4
if (tb_video->Insert(video_json) == false)
{
rsp.status = 500;
rsp.body = R"({"result":false, "reason":"数据库新增数据失败"})";
rsp.set_header("Content-Type", "application/json");
return;
}
rsp.set_redirect("/index.html", 303);
return;
}
remove:函数从文件系统中删除一个文件。
static void Delete(const httplib::Request &req, httplib::Response &rsp)
{
//****************************************************
// DELETE /video/1 1.1.0 我们规定的结构,删除的是1号视频
//****************************************************
// 1. 获取要删除 的视频ID
int video_id = std::stoi(req.matches[1]);
// 2. 删除视频以及图片文件
Json::Value video;
if (tb_video->SelectOne(video_id, &video) == false)
{
rsp.status = 500;
rsp.body = R"({"result":false, "reason":"不存在视频信息"})";
rsp.set_header("Content-Type", "application/json");//很重要;告诉http我们的传递数据格式是按照json。
return;
}
std::string root = WWWROOT;
//找到要删除的视频和图片的路径。
std::string video_path = root + video["video"].asString();
std::string image_path = root + video["image"].asString();
//调用remove函数去关闭一
remove(video_path.c_str());
remove(image_path.c_str());
// 4. 删除数据库信息
if (tb_video->Delete(video_id) == false)
{
rsp.status = 500;
rsp.body = R"({"result":false, "reason":"删除数据库信息失败"})";
rsp.set_header("Content-Type", "application/json");
return;
}
return;
}
static void Update(const httplib::Request &req, httplib::Response &rsp)
{
//****************************************************
// DELETE /video/1 1.1.0 我们规定的结构,删除的是1号视频
//****************************************************
// 1. 获取要修改的视频信息 1. 视频id, 2. 修改后的信息
int video_id = std::stoi(req.matches[1]);
Json::Value video;
if (JsonUtil::UnSerialize(req.body, &video) == false)
{
rsp.status = 400;
rsp.body = R"({"result":false, "reason":"新的视频信息格式解析失败"})";
rsp.set_header("Content-Type", "application/json");
return;
}
// 2. 修改数据库数据
if (tb_video->Update(video_id, video) == false)
{
rsp.status = 500;
rsp.body = R"({"result":false, "reason":"修改数据库信息失败"})";
//非常的重要,要不然http不知道你给返回的数据是啥格式,就按照默认走了。
rsp.set_header("Content-Type", "application/json");
return;
}
return;
}
static void SelectOne(const httplib::Request &req, httplib::Response &rsp)
{
// 1. 获取视频的ID
int video_id = std::stoi(req.matches[1]);
// 2. 在数据库中查询指定视频信息
Json::Value video;
if (tb_video->SelectOne(video_id, &video) == false)
{
rsp.status = 500;
rsp.body = R"({"result":false, "reason":"查询数据库指定视频信息失败"})";
rsp.set_header("Content-Type", "application/json");
return;
}
// 3. 组织响应正文--json格式的字符串
JsonUtil::Serialize(video, &rsp.body);
rsp.set_header("Content-Type", "application/json");
return;
}
static void SelectAll(const httplib::Request &req, httplib::Response &rsp)
{
// /video & /video?search="关键字"
bool select_flag = true; // 默认所有查询
std::string search_key;
if (req.has_param("search") == true)
{
select_flag = false; // 模糊匹配
search_key = req.get_param_value("search");
}
Json::Value videos;
if (select_flag == true)
{
if (tb_video->SelectAll(&videos) == false)
{
rsp.status = 500;
rsp.body = R"({"result":false, "reason":"查询数据库所有视频信息失败"})";
rsp.set_header("Content-Type", "application/json");
return;
}
}
else
{
if (tb_video->SelectLike(search_key, &videos) == false)
{
rsp.status = 500;
rsp.body = R"({"result":false, "reason":"查询数据库匹配视频信息失败"})";
rsp.set_header("Content-Type", "application/json");
return;
}
}
JsonUtil::Serialize(videos, &rsp.body);
rsp.set_header("Content-Type", "application/json");
return;
}
(6) 让服务端跑起来
Server(int port) : _port(port) {}
bool RunModule()
{
// 1. 初始化操作---初始化数据管理模块,创建指定的目录
tb_video = new TableVideo();
FileUtil(WWWROOT).CreateDirectory();
std::string root = WWWROOT;
std::string video_real_path = root + VIDEO_ROOT; // ./www/video/
FileUtil(video_real_path).CreateDirectory();
std::string image_real_path = root + IMAGE_ROOT; // ./www/image/
FileUtil(image_real_path).CreateDirectory();
// 2. 搭建http服务器,开始运行
// 1. 设置静态资源根目录
_srv.set_mount_point("/", WWWROOT);
// 2. 添加请求-处理函数映射关系
_srv.Post("/video", Insert);
_srv.Delete("/video/(\\d+)", Delete);
_srv.Put("/video/(\\d+)", Update);
_srv.Get("/video/(\\d+)", SelectOne);
_srv.Get("/video", SelectAll);
// 3. 启动服务器
_srv.listen("0.0.0.0", _port);
return true;
}
把服务起来,进行测试
请求全部
请求1号视频
请求4号视频
请求没有的视频:
到这里之后呢后端服务器设计就写完了,但是呢,看起来非常的low,因为我前端不是很会的,之后会复制一个模板,改一个前端带代码出来展示。因为没有前端,所有我们的视频界面也看不到,这个测试就只能简单的进行一下了。
新曾前端测试
我们上传三个视频
后面俩个是封面和视频上传顺序反了。
点击观看
服务器买的便宜,加载视频太卡了,哭死,就这样把,加载界面加载了几分钟,知道能看就可以了。 删除修改也是可以的。
Project: 这是一个用来写一些项目代码的练习仓库。我将会在这里更新我学到的项目代码,之后会通过博客的方式进行讲解,这是我的博客地址:https://blog.csdn.net/weixin_50374599?spm=109.2139.3001.5343。我会一直学习,持续的进步,希望大家关注我的博客一起进步。 - Gitee.com