当前位置: 首页 > news >正文

适合做网站服务器的主机天津做网站好的公司有哪些

适合做网站服务器的主机,天津做网站好的公司有哪些,网站做外国生意,计算机毕设网站开发中期报告目录 一、项目介绍 1.1 对视频共享点播系统的认识 1.2服务端程序负责功能 1.3 服务端功能模块划分 1.4 项目界面演示 1.5预备知识 二.环境搭建 2.1 安装 Jsoncpp 库 2.1.1 使用jsoncpp 2.2 引入httplib库 2.2.1 安装Git#xff08;如果你的系统尚未安装Git#xf…目录 一、项目介绍 1.1 对视频共享点播系统的认识 1.2服务端程序负责功能 1.3 服务端功能模块划分 1.4 项目界面演示 1.5预备知识 二.环境搭建 2.1 安装 Jsoncpp 库 2.1.1 使用jsoncpp 2.2 引入httplib库 2.2.1 安装Git如果你的系统尚未安装Git 2.2.2 克隆仓库 2.2.3 使用httplib 2.3 Mysql 数据库及开发包安装 2.3.1 安装MySQL服务器 2.3.2 安装MySQL客户端 2.3.3 安全配置安装后建议执行 2.3.4 启动、停止、重启 登录 MySQL服务 三.项⽬实现 3.1服务端⼯具类实现 3.1.1⽂件实⽤⼯具类设计 3.1.2 Json 实⽤⼯具类设计 3.2 服务端数据管理模块 3.2.1 视频数据表的设计 3.2.2 数据管理类设计 3.3 服务端业务处理模块 3.3.1 ⽹络通信接⼝设计 3.3.2 业务处理模块类的设计 3.3.2 最终合并调试 3.4 前端界⾯模块实现 3.4.1 前端视频展示⻚⾯ 3.4.2 前端视频观看页面的实现 四.项⽬总结 一、项目介绍 1.1 对视频共享点播系统的认识 搭建视频共享点播服务器可以让所有人通过浏览器访问服务器实现视频的上传观看以及管理并播放的功能。主要是完成服务器端的程序业务功能的实现以及前端访问界面 html 的编写能够支持客户端浏览器针对服务器上的所有视频进行操作。 1.2服务端程序负责功能 针对客⼾端上传的视频⽂件以及封⾯图⽚进⾏备份存储。 针对客⼾端上传的视频完成增删改查功能 ⽀持客⼾端浏览器进⾏视频的观看功能 1.3 服务端功能模块划分 该视频点播系统基本上包含四个模块数据管理、网络通信、业务处理、前端界面。 数据管理模块负责针对客户端上传的视频信息进行管理。网络通信模块搭建网络通信服务器实现与客户端通信。业务处理模块针对客户端的各个请求进行对应业务处理并响应结果。前端界面模块前端浏览器上视频共享点播的各个 html 页面在页面中支持增删改查以及观看功能。 1.4 项目界面演示 项目整体有俩个页面分别为主界面和观看界面 主界面主要    用于 视频展示、视频上传、视频搜索 观看界面主要用于 视频观看、视频信息修改、视频删除 以下为项目页面功能展示 1.5预备知识 认识 JsonCpp http://t.csdnimg.cn/lsz2ohttp://t.csdnimg.cn/lsz2o 认识 MySQL数据库的API http://t.csdnimg.cn/hpxg1http://t.csdnimg.cn/hpxg1 认识 httplib http://t.csdnimg.cn/SvQJzhttp://t.csdnimg.cn/SvQJz 二.环境搭建 我的服务器Ubuntu22.04 2.1 安装 Jsoncpp 库 sudo apt update sudo apt -y install libjsoncpp25 2.1.1 使用jsoncpp #include jsoncpp/json/json.h 2.2 引入httplib库 2.2.1 安装Git如果你的系统尚未安装Git sudo apt update sudo apt install git 2.2.2 克隆仓库 打开终端使用cd命令切换到你想要存放cpp-httplib库的目录然后运行以下命令来克隆仓库 git clone https://github.com/yhirose/cpp-httplib.git 2.2.3 使用httplib 直接在你的C代码中包含httplib.h头文件。你可以将其复制到你的项目中合适的位置然后在源文件中包含它 #include httplib.h 2.3 Mysql 数据库及开发包安装 2.3.1 安装MySQL服务器 sudo apt update //更新本地包数据库 sudo apt install mysql-server//安装最新版本的MySQL 2.3.2 安装MySQL客户端 sudo apt install mysql-client 2.3.3 安全配置安装后建议执行 sudo mysql_secure_installation//按照提示设置root用户的密码移除匿名用户禁止root用户远程登录等 sudo systemctl status mysql //确认MySQL服务状态 2.3.4 启动、停止、重启 登录 MySQL服务 sudo systemctl start mysql //启动服务 sudo systemctl stop mysql //停止服务 sudo systemctl restart mysql//重启服务mysql -u root -p 使用root用户登录 三.项⽬实现 3.1服务端⼯具类实现 3.1.1⽂件实⽤⼯具类设计 在视频点播系统中因为涉及到⽂件上传需要对上传的⽂件进⾏备份存储因此⾸先设计封装⽂件操作类这个类封装完毕之后则在任意模块中对⽂件进⾏操作时都将变的简单化 功能 构造函数 FileUtil(const std::string name) 接收一个字符串参数 name表示文件的路径和名称并将这个值赋给私有成员变量 _name。 Exists - 检查文件是否存在 使用 access 函数和 F_OK 标志来检查文件是否存在。如果 access 函数返回非0值表示文件不存在函数输出错误信息并返回 false。如果文件存在返回 true。 Size - 获取文件大小 首先检查文件是否存在如果不存在则返回0。使用 stat 函数获取文件的属性并将文件大小存储在 st.st_size 中。如果 stat 函数返回非0值表示获取文件属性失败函数输出错误信息并返回0。成功获取属性后返回文件大小。 GetContent - 读取文件内容 打开文件以二进制模式读取。如果文件无法打开输出错误信息并返回 false。使用 Size 函数获取文件大小并根据大小调整 body 字符串的容量。读取文件内容到 body 字符串中。如果读取失败输出错误信息关闭文件并返回 false。成功读取后关闭文件并返回 true。 SetContent - 向文件写入数据 打开文件以二进制模式写入。如果文件无法打开输出错误信息并返回 false。使用 write 函数将 body 字符串的内容写入文件。如果写入失败输出错误信息关闭文件并返回 false。成功写入后关闭文件并返回 true。 CreateDirectory - 创建目录 首先检查目录是否存在如果存在则直接返回 true。使用 mkdir 函数创建目录如果创建成功则返回 true。注意这个类使用了C标准库中的文件操作函数如 access、stat、ifstream、ofstream 和 mkdir。这些函数需要包含相应的头文件例如 fstream、sys/stat.h 和 unistd.h。 class FileUtil{private:std::string _name;//文件路径名称public:FileUtil(const std::string name):_name(name){}// 判断当前文件是否存在bool Exists(){//access的F_OK专门用于检测文件是否存在--- 存在则返回0int ret access(_name.c_str(), F_OK);if (ret ! 0) {std::cout 文件不存在\n;return false;}return true;}// 获取文件大小size_t Size() {if (this-Exists() false) {return 0;}struct stat st;//stat接口用于获取文件属性其中 st_size就是文件大小成员int ret stat(_name.c_str(), st);if (ret ! 0) {std::cout 获取文件属性失败\n;return 0;}return st.st_size;}// 读取文件数据到body中bool GetContent(std::string *body) {std::ifstream ifs;ifs.open(_name, std::ios::binary);if (ifs.is_open() false) {std::cout 文件打开失败\n;return false;}size_t flen this-Size();body-resize(flen);ifs.read((*body)[0], flen);if (ifs.good() false) {std::cout 读取文件内容失败\n;ifs.close();return false;}ifs.close();return true;}// 像文件写入数据bool SetContent(const std::string body) {std::ofstream ofs;ofs.open(_name, std::ios::binary);if (ofs.is_open() false) {std::cout 文件打开失败\n;return false;}ofs.write(body.c_str(), body.size());if (ofs.good() false) {std::cout 写入文件内容失败\n;ofs.close();return false;}ofs.close();return true;}//针对目录时创建目录bool CreateDirectory() {if (this-Exists()) {return true;}mkdir(_name.c_str(), 0777);return true;}}; 3.1.2 Json 实⽤⼯具类设计 功能 Serialize - 序列化函数 这个函数接受一个Json::Value类型的参数value和一个指向std::string的指针body。使用Json::StreamWriterBuilder创建一个Json::StreamWriter对象用于将Json::Value对象写入到字符串流中。通过write方法将value序列化到std::stringstream对象ss中。如果序列化失败write方法返回非0值则输出错误信息并返回false。成功序列化后将字符串流的内容赋值给*body并返回true。 UnSerialize - 反序列化函数 这个函数接受一个std::string类型的参数body和一个指向Json::Value的指针value。使用Json::CharReaderBuilder创建一个Json::CharReader对象用于从字符串中解析JSON数据。使用parse方法尝试解析body中的JSON数据并将结果存储在value指向的对象中。如果解析失败parse方法返回false则输出错误信息并返回false。成功解析后返回true。 class JsonUtil{public:// 序列化static bool Serialize(const Json::Value value, std::string *body) {Json::StreamWriterBuilder swb;std::unique_ptrJson::StreamWriter sw(swb.newStreamWriter());std::stringstream ss; int ret sw-write(value, ss);if (ret ! 0) {std::cout 序列化失败\n;return false;} *body ss.str();return true;}// 反序列化static bool UnSerialize(const std::string body, Json::Value *value) {Json::CharReaderBuilder crb;std::unique_ptrJson::CharReader cr(crb.newCharReader());std::string err;bool ret cr-parse(body.c_str(), body.c_str() body.size(), value, err);if (ret false) {std::cout 反序列化失败\n;return false;}return true;}}; 3.2 服务端数据管理模块 3.2.1 视频数据表的设计 在视频共享点播系统中视频数据和图⽚数据都存储在⽂件中⽽我们需要在数据库中管理⽤⼾上传 的每个视频信息。只是完成⼀个简单的视频信息表 MySQL 创建数据库 create database aod_system; 使用aod_system 数据库 use aod_system; 建表 create table tb_video(id int primary key auto_increment comment 视频ID,name varchar(32) comment 视频名称,info text comment 视频描述,video varchar(256) comment 视频⽂件url加上静态资源根⽬录就是实际存储路径,image varchar(256) comment 封⾯图⽚⽂件url加上静态资源根⽬录就是实际存储路径 );3.2.2 数据管理类设计 数据管理模块负责统⼀对于数据库中数据的增删改查管理其他所有模块要进⾏数据的操作都通过数 据管理模块完成。然⽽数据库中有可能存在很多张表每张表中数据⼜有不同要进⾏的数据操也各不相同因此咱 们将数据的操作分摊到每⼀张表上为每⼀张表中的数据操作都设计⼀个类通过类实例化的对象来 访问这张数据库表中的数据这样的话当我们要访问哪张表的时候使⽤哪个类实例化的对象即可。视频信息在接⼝之间的 传递因为字段数量可能很多因此使⽤ Json::Value 对象进⾏传递 功能 防止头文件重复包含使用 #ifndef、#define 和 #endif 宏来防止头文件被重复包含。 包含头文件包含自定义的 util.hpp 头文件和一些标准库头文件如 cstdlib、mutex 和 mysql/mysql.h。 命名空间定义了一个名为 aod 的命名空间用于封装相关的数据库操作。 宏定义定义了一些宏如数据库连接信息 HOST、USER、PASS 和 NAME。 MysqlInit 函数用于初始化MySQL连接包括创建MySQL句柄、连接到服务器和设置字符集。 MysqlDestroy 函数用于销毁MySQL连接关闭句柄。 MysqlQuery 函数用于执行SQL语句并检查执行是否成功。 TableVideo 类 私有成员 _mysql用于存储MySQL句柄。私有成员 _mutex用于多线程同步保证线程安全。构造函数初始化MySQL句柄。析构函数销毁MySQL句柄。成员函数 Insert向数据库表 tb_video 插入视频信息。成员函数 Update根据视频ID更新视频信息。成员函数 Delete根据视频ID删除视频信息。成员函数 SelectAll查询所有视频信息并将结果存储在 Json::Value 类型的参数中。成员函数 SelectOne根据视频ID查询单个视频信息。成员函数 SelectLike根据名称关键字进行模糊匹配查询视频信息。 错误处理在执行数据库操作时如果遇到错误会打印错误信息。 JSON操作使用 Json::Value 类型来处理JSON数据这需要包含JSONCPP库的相关头文件。 线程安全在 TableVideo 类中使用 std::mutex 来保证多线程环境下对数据库操作的线程安全。 资源管理在 SelectAll、SelectOne 和 SelectLike 函数中使用 mysql_store_result 保存查询结果并在操作完成后使用 mysql_free_result 释放结果集。 #ifndef __MY_DATA__ //防止头文件重复包含 #define __MY_DATA__ #include util.hpp #include cstdlib #include mutex #include mysql/mysql.hnamespace aod{ #define HOST 127.0.0.1 #define USER root #define PASS mima #define NAME aod_system//mysql的封装//初始化static MYSQL *MysqlInit() {//1初始化句柄MYSQL *mysql mysql_init(NULL);if (mysql NULL) {std::cout 初始化 MySQL 实例失败\n;return NULL;}//2 链接服务器if (mysql_real_connect(mysql, HOST, USER, PASS, NAME, 0, NULL, 0) NULL) {std::cout 连接MySQL服务器失败\n;mysql_close(mysql);return NULL;}// 3设置客户端字符集mysql_set_character_set(mysql, utf8);return mysql;}//销毁static void MysqlDestroy(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_errno(mysql) std::endl;return false;}return true;}class TableVideo{private:MYSQL *_mysql; // ⼀个对象就是⼀个客⼾端管理⼀张表std::mutex _mutex; // 防备操作对象在多线程中使⽤存在的线程安全 问题public:// 完成mysql句柄初始化TableVideo() {_mysql MysqlInit();if (_mysql NULL) {exit(-1);}}// 释放msyql操作句柄~TableVideo() {MysqlDestroy(_mysql);}// 新增-传⼊视频信息bool Insert(const Json::Value video) {//id name视频名 info视频简介 video视频路径 image图片路径std::string sql;sql.resize(4096 video[info].asString().size());//防止简介过长#define INSERT_VIDEO insert tb_video values(null, %s, %s, %s, %s);//可以对各个数据增加校验去增加各种规则比如视频名不能没有 等等等if (video[name].asString().size() 0) {return false;}//要完成的细致的话需要对各个数据进行校验因为不校验直接用就有可能出问题sprintf(sql[0], INSERT_VIDEO, video[name].asCString(),video[info].asCString(), video[video].asCString(),video[image].asCString());return MysqlQuery(_mysql, sql);}// 修改-传⼊视频id和信息bool Update(int video_id, const Json::Value video) {std::string sql;sql.resize(4096 video[info].asString().size());//防止简介过长#define UPDATE_VIDEO update tb_video set name%s, info%s where id%d;sprintf(sql[0], UPDATE_VIDEO, video[name].asCString(),video[info].asCString(), video_id);return MysqlQuery(_mysql, sql);}// 删除-传⼊视频IDbool Delete(int video_id) {#define DELETE_VIDEO delete from tb_video where id%d;char sql[1024] {0};sprintf(sql, DELETE_VIDEO, video_id);return MysqlQuery(_mysql, sql);}// 查询所有--输出所有视频信息bool SelectAll(Json::Value *videos) {#define SELECTALL_VIDEO select * from tb_video;_mutex.lock();//-----lock start 保护查询与保存结果到本地的过程bool ret MysqlQuery(_mysql, SELECTALL_VIDEO);if (ret false) {_mutex.unlock();return false;}//保存查询结果集MYSQL_RES *res mysql_store_result(_mysql);if (res NULL) {std::cout MySQL存储结果失败\n;_mutex.unlock();return false;}_mutex.unlock();//------lock end//查看结果有多少行并传入vidows中int num_rows mysql_num_rows(res);for (int i 0; i num_rows; i) {MYSQL_ROW row mysql_fetch_row(res);//取出一条结果Json::Value video;video[id] atoi(row[0]);video[name] row[1];video[info] row[2];video[video] row[3];video[image] row[4];videos-append(video);}mysql_free_result(res);//释放结果集return true;}// 查询单个-输⼊视频id, 输出信息bool SelectOne(int video_id, Json::Value *video) {#define SELECTONE_VIDEO select * from tb_video where id%d;char sql[1024] {0};sprintf(sql, SELECTONE_VIDEO, video_id);_mutex.lock();//-----lock start 保护查询与保存结果到本地的过程bool ret MysqlQuery(_mysql, sql);if (ret false) {_mutex.unlock();return false;}//保存查询结果集MYSQL_RES *res mysql_store_result(_mysql);if (res NULL) {std::cout MySQL存储结果失败\n;_mutex.unlock();return false;}_mutex.unlock();//------lock end//查看结果有多少行并传入vidows中int num_rows mysql_num_rows(res);if (num_rows ! 1) {std::cout 没有数据\n;mysql_free_result(res);return false;}MYSQL_ROW row mysql_fetch_row(res);//取出一条结果(*video)[id] video_id;(*video)[name] row[1];(*video)[info] row[2];(*video)[video] row[3];(*video)[image] row[4];mysql_free_result(res);//释放结果集return true;}// 模糊匹配 - 输⼊名称关键字输出视频信息bool SelectLike(const std::string key, Json::Value *videos){#define SELECTLIKE_VIDEO select * from tb_video where name like %%%s%%;char sql[1024] {0};sprintf(sql, SELECTLIKE_VIDEO, key.c_str());_mutex.lock();//-----lock start 保护查询与保存结果到本地的过程bool ret MysqlQuery(_mysql, sql);if (ret false) {_mutex.unlock();return false;}MYSQL_RES *res mysql_store_result(_mysql);if (res NULL) {std::cout MySQL存储结果失败\n;_mutex.unlock();return false;}_mutex.unlock();//------lock endint num_rows mysql_num_rows(res);for (int i 0; i num_rows; i) {MYSQL_ROW row mysql_fetch_row(res);Json::Value video;video[id] atoi(row[0]);video[name] row[1];video[info] row[2];video[video] row[3];video[image] row[4];videos-append(video);}mysql_free_result(res);return true;}}; }#endif3.3 服务端业务处理模块 3.3.1 ⽹络通信接⼝设计 认识 rest设计风格 http://t.csdnimg.cn/wxhtmhttp://t.csdnimg.cn/wxhtm 获取所有视频信息 请求 GET /video HTTP/1.1 响应 HTTP/1.1 200 OK [{info: 好电影,id: 1,image: /img/thumbs/mysql.png,name: Mysql注意事项,video: /video/movie.mp4,},{info: 好电影,id: 2,image: /img/thumbs/linux.png,name: Linux注意事项,video: /video/movie.mp4,} ] 搜索指定关键字名称视频信息 请求 GET /video?searchMysql HTTP/1.1 响应 HTTP/1.1 200 OK [{info: 好电影,id: 1,image: /img/thumbs/mysql.png,name: Mysql注意事项,video: /video/movie.mp4,} ] 获取指定视频信息 请求 GET /video/1 HTTP/1.1 响应 HTTP/1.1 200 OK [{info: 好电影,id: 1,image: /img/thumbs/mysql.png,name: Mysql注意事项,video: /video/movie.mp4,} ] 删除指定视频信息 请求 DELETE /video/1 HTTP/1.1 响应 HTTP/1.1 200 OK 修改指定视频信息 请求 PUT /video/1 HTTP/1.1 {info: 这是⼀个⾮常好的教学视频深⼊浅出引⼈深思,id: 1,image: /img/thumbs/mysql.png,name: Mysql注意事项,video: /video/movie.mp4, } 响应 HTTP/1.1 200 OK 上传视频信息以及⽂件 因为上传视频信息的时候会携带有视频⽂件和封⾯图⽚的⽂件上传⽽这些⽂件数据都是⼆进制 的⽤ json 不好传输因此在这⾥使⽤传统的 http 上传⽂件请求格式⽽并没有使⽤ restful ⻛格。 请求 POST /video HTTP/1.1 Content-Type: multipart/form-data; boundary---- WebKitFormBoundarydsrFiETIzKETHWkn ------WebKitFormBoundarydsrFiETIzKETHWkn Content-Disposition: form-data; namename Xhsell连接事项也就是视频名称 ------WebKitFormBoundarydsrFiETIzKETHWkn Content-Disposition: form-data; nameinfo ⼀部⾮常好看的视频的描述信息 ------WebKitFormBoundarydsrFiETIzKETHWkn Content-Disposition: form-data; nameimage; filenameimage.jpg Content-Type: text/plain image封⾯图⽚数据 ------WebKitFormBoundarydsrFiETIzKETHWkn Content-Disposition: form-data; namevideo; filenamevideo.mp4 Content-Type: text/plain video视频数据 ------WebKitFormBoundarydsrFiETIzKETHWkn Content-Disposition: form-data; namesubmit ------WebKitFormBoundarydsrFiETIzKETHWkn-- 响应 HTTP/1.1 303 See Other Location: / 3.3.2 业务处理模块类的设计 业务处理模块负责与客⼾端进⾏⽹络通信接收客⼾端的请求然后根据请求信息明确客⼾端端⽤ ⼾的意图进⾏业务处理并进⾏对应的结果响应。 在视频共享点播系统中业务处理主要包含两⼤功能1、⽹络通信功能的实现2、业务功能处理的实现 其中⽹络通信功能的实现咱们借助 httplib 库即可⽅便的搭建 http 服务器完成。这也是咱们将⽹ 络通信模块与业务处理模块合并在⼀起完成的原因。 功能 宏定义 WWWROOT定义了静态资源的根目录。 VIDEO_ROOT和IMAGE_ROOT定义了视频和图片资源的相对路径。 全局变量 tb_video一个TableVideo类型的指针作为全局变量用于在多线程中访问数据管理对象。 Server类 私有成员变量_port存储服务器监听的端口号。 私有成员变量_srvhttplib::Server类型的实例用于搭建HTTP服务器。 私有静态成员函数 Insert处理视频和图片的上传请求保存文件到指定目录并更新数据库。 Delete根据视频ID删除视频和图片文件以及数据库记录。 Update根据视频ID更新视频信息。 SelectOne根据视频ID查询单个视频信息。 SelectAll查询所有视频信息或根据关键字进行模糊查询。 公有构造函数 Server(int port)接收端口号作为参数初始化Server对象。 公有成员函数 RunModule初始化数据管理模块设置静态资源目录建立请求与处理函数的映射关系并启动服务器。 主要流程 在RunModule函数中首先初始化TableVideo对象和所需的目录结构。 使用httplib::Server设置静态资源目录并为不同的HTTP请求方法添加相应的处理函数。 启动服务器监听指定端口。 #include data.hpp #include httplib.hnamespace aod{ #define WWWROOT ./www #define VIDEO_ROOT /video/ #define IMAGE_ROOT /image/// 因为httplib基于多线程因此数据管理对象需要在多线程中访问为了便于访问定义全局变量TableVideo *tb_video NULL;// 这⾥为了更加功能模块划分清晰⼀些不使⽤lamda表达式完成否则所有的功能实现集中到⼀个函数中太过庞⼤class Server{private:int _port; // 服务器的 监听端⼝httplib::Server _srv; // ⽤于搭建http服务器private:// 对应的业务处理接⼝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.jpgstd::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;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 ;}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.mp4video_json[image] IMAGE_ROOT video_name image.filename;// /video/变形金刚robot.mp4if (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 ;}static void Delete(const httplib::Request req, httplib::Response rsp) {//1. 获取要删除 的视频IDint 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 ;}std::string root WWWROOT;std::string video_path root video[video].asString();std::string image_path root video[image].asString();remove(video_path.c_str());remove(image_path.c_str());//3. 删除数据库信息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) {//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:修改数据库信息失败});rsp.set_header(Content-Type, application/json);return ;}return ;}static void SelectOne(const httplib::Request req, httplib::Response rsp) {//1. 获取视频的IDint 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 ;}public: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;}}; }3.3.2 最终合并调试 #include server.hpp void ServerTest() {aod::Server server(9000);server.RunModule(); } int main() {ServerTest();return 0; } Makefile 代码 aod:aod.cpp util.hpp data.hpp server.hppg -stdc11 $^ -o $ -L/usr/lib64/mysql -ljsoncpp -lmysqlclient -lpthread3.4 前端界⾯模块实现 3.4.1 前端视频展示⻚⾯ !DOCTYPE html html langenheadmeta charsetutf-8meta nameviewport contentwidthdevice-width, initial-scale1meta namedescription contentmeta nameauthor contentOrcasThemesmeta http-equivX-UA-Compatible contentIEEdge /titleHome/title!-- Bootstrap core CSS --link hrefcss/bootstrap.css relstylesheet!-- Custom styles for this template --link relstylesheet hrefcss/screen.csslink relstylesheet hrefcss/animation.css!--[if IE 7]![endif]--link relstylesheet hrefcss/font-awesome.css!--[if lt IE 8]link relstylesheet hrefcss/ie.css typetext/css mediascreen, projection![endif]--link hrefcss/lity.css relstylesheetstyle[v-cloak] {display: none;}/stylestyle.search-block .form-inline {display: flex;align-items: center;}.search-block .input-group {width: 100%;/* 根据需要调整宽度这里设置为100%是为了适应容器宽度 */margin: 0;/* 移除外边距 */}.search-block .form-control {border-radius: 0.25rem;/* 输入框圆角 */}.search-block .btn-outline-secondary {background-color: transparent;/* 按钮背景色 */border-color: #ccc;/* 按钮边框色 */}.search-block .btn-outline-secondary:hover {background-color: #e9ecef;/* 鼠标悬浮时的按钮背景色 */}.search-block .btn-outline-secondary:focus,.search-block .btn-outline-secondary:active {background-color: #dde2e6;/* 聚焦或按下时的按钮背景色 */}.search-block {display: flex;align-items: center;/* 垂直居中对齐 */}.search-block .input-group {width: auto;/* 根据需要调整auto允许根据内容自适应宽度 */flex-grow: 1;/* 允许输入组占据剩余空间 */margin-bottom: 0;/* 移除底部边距 */}.search-block .form-control {border-radius: 0.25rem 0 0 0.25rem;/* 圆角只应用于输入框的左半部分 */}.search-block .btn-outline-secondary {border-radius: 0 0.25rem 0.25rem 0;/* 圆角只应用于按钮的右半部分 */border-left: none;/* 移除按钮左侧的边框与输入框对齐 */}.search-block .form-inline {display: flex;align-items: center;width: auto;/* 可以设置为特定宽度或自动 */}.search-block .input-group {flex-grow: 1;/* 允许输入组根据需要增长 */}.search-block .form-control {border-radius: 0.25rem 0 0 0.25rem;/* 圆角 */}.search-block .btn-outline-secondary {margin-left: -1px;/* 与输入框边框对齐 */border-radius: 0 0.25rem 0.25rem 0;/* 圆角 */}.input-group-append {display: flex;align-items: center;}#searchButton {white-space: nowrap;/* 防止按钮内的文本换行 */}.fa-search {margin-right: 5px;/* 根据需要调整搜索图标和按钮文本之间的间距 */}/stylelink relstylesheet hrefhttps://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.cssintegritysha512-4zCK9kqIH5OTEOcHLSb8txb5KQ0U5x1T6BjrrAa4LObyz1W65HlE6cRqN58p9tJJq6TjW7nPEK67E41wcrossoriginanonymous / /headbodydiv idmyapp!-- HOME 1 --div idhome1 classcontainer-fluid standard-bg!-- HEADER --div classrow header-topdiv classcol-lg-3 col-md-6 col-sm-5 col-xs-8a classmain-logo href#img srcimg/main-logo.png classmain-logo img-responsivealtMuvee Reviews titleMuvee Reviews/a/divdiv classcol-lg-6 hidden-md text-center hidden-sm hidden-xs/divdiv classcol-lg-3 col-md-6 col-sm-7 hidden-xsdiv classright-boxbutton typebutton classaccess-btn data-togglemodaldata-target#enquirypopup新增视频/button/div/div/div!-- MENU --div classrow home-mega-menu div classcol-md-12nav classnavbar navbar-defaultdiv classnavbar-headerbutton classnavbar-toggle typebutton data-togglecollapsedata-target.js-navbar-collapsespan classsr-onlyToggle navigation/spanspan classicon-bar/spanspan classicon-bar/spanspan classicon-bar/span/button/divdiv classcollapse navbar-collapse js-navbar-collapse megabg dropshd ul classnav navbar-navlia hrefindex.html视频点播/a/li/uldiv classsearch-blockform classform-inline d-flex w-100div classinput-groupinput typetext idsearchInput classform-control placeholderSearchnamesearchInput/div/form/div/div!-- /.nav-collapse --/nav/div/div!-- CORE --div classrow!-- SIDEBAR --div classcol-lg-2 col-md-4 hidden-sm hidden-xs/div!-- HOME MAIN POSTS --div classcol-lg-10 col-md-8section idhome-mainh2 classiconi classfa fa-television aria-hiddentrue/i视频列表/h2div classrow!-- ARTICLES --div classcol-lg-9 col-md-12 col-sm-12div classrow auto-cleararticle classcol-lg-3 col-md-6 col-sm-4 v-forvideo in videos!-- POST L size --div classpost post-mediumdiv classthumbra classafterglow post-thumb v-bind:href/video.html?idvideo.idtarget_blankspan classplay-btn-border titlePlayiclassfa fa-play-circle headline-roundaria-hiddentrue/i/spandiv classcactus-note ct-time font-size-1span02:02/span/divimg classimg-responsive v-bind:srcvideo.image alt#v-cloak/a/divdiv classinforh4a classtitle href# v-cloak{{video.name}}/a/h4span classposts-txt titlePosts from Channeliclassfa fa-thumbs-up aria-hiddentrue/i20.895/spandiv classratingsi classfa fa-star aria-hiddentrue/ii classfa fa-star aria-hiddentrue/ii classfa fa-star-half-o aria-hiddentrue/ii classfa fa-star-o/ii classfa fa-star-half/i/div/div/div/article/divdiv classclearfix spacer/div/div!-- RIGHT ASIDE --div classcol-lg-3 hidden-md col-sm-12 text-center top-sidebar/div/div/section/div/div/div!-- CHANNELS --div idchannels-block classcontainer-fluid channels-bg/div!-- BOTTOM BANNER --div idbottom-banner classcontainer text-center/div!-- FOOTER --div idfooter classcontainer-fluid footer-backgrounddiv classcontainerfooter!-- SECTION FOOTER --div classrow!-- SOCIAL --div classcol-lg-3 col-md-3 col-sm-6 col-xs-12div classrow auto-clear/div/div!-- TAGS --div classcol-lg-3 col-md-3 col-sm-6 col-xs-12/div!-- POST --div classcol-lg-3 col-md-3 col-sm-6 col-xs-12/div!-- LINKS --div classcol-lg-3 col-md-3 col-sm-6 col-xs-12/div/divdiv classrow copyright-bottom text-centerdiv classcol-md-12 text-centera href classfooter-logo titleVideo Magazine Bootstrap HTML5 templateimg srcimg/footer-logo.png classimg-responsive text-centeraltVideo Magazine Bootstrap HTML5 template/ap v-cloakCopyright copy; Author by {{author}}/p/div/div/footer/div/div!-- MODAL --div idenquirypopup classmodal fade in roledialogdiv classmodal-dialog!-- Modal content--div classmodal-content rowdiv classmodal-header custom-modal-headerbutton typebutton classclose data-dismissmodal×/buttonh2 classiconi classfa fa-television aria-hiddentrue/i新增视频/h2/divdiv classmodal-bodyform nameinfo_form classform-inline action/video methodpostenctypemultipart/form-datadiv classform-group col-sm-12input typetext classform-control namename placeholder输入视频名称/divdiv classform-group col-sm-12input typetext classform-control nameinfo placeholder输入视频简介/divdiv classform-group col-sm-12input typefile classform-control namevideo placeholder选择视频文件/divdiv classform-group col-sm-12input typefile classform-control nameimage placeholder选择封面图片/divdiv classform-group col-sm-12button classsubscribe-btn pull-right typesubmit titleSubscribe上传/button/div/form/div/div/div/div/div /body!-- JAVA SCRIPT -- !-- jQuery (necessary for Bootstraps JavaScript plugins) -- script srcjs/jquery-1.12.1.min.js/script script srcjs/bootstrap.min.js/script script srcjs/lity.js/script script srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscript$(document).ready(function () {$(.nav .dropdown).hover(function () {$(this).find(.dropdown-toggle).dropdown(toggle);});}); /script script// Vue 实例let app new Vue({el: #myapp,data: {author: ZhaoYiLong,videos: [], // 用于存储视频数据的数组searchQuery: // 用于存储搜索关键字},methods: {// 获取所有视频的方法get_allvideos: function () {fetch(/video).then(response {if (!response.ok) {throw new Error(Network response was not ok);}return response.json();}).then(data {this.videos data;}).catch(error {console.error(There has been a problem with your fetch operation:, error);});},// 搜索视频的方法search_videos: function () {var url /video?search encodeURIComponent(this.searchQuery);fetch(url).then(response response.json()).then(data {this.videos data;}).catch(error {console.error(There has been a problem with your fetch operation:, error);});}},// 在Vue实例创建后调用get_allvideos方法created: function () {this.get_allvideos();}});// 为搜索框添加键盘事件监听允许使用回车键进行搜索document.getElementById(searchInput).addEventListener(keypress, function (event) {var key event.which || event.keyCode;if (key 13) { // 13是回车键的键码event.preventDefault(); // 阻止表单的默认提交行为app.searchQuery document.getElementById(searchInput).value;app.search_videos();}});// 移除原有的搜索按钮点击事件监听因为我们现在使用回车键进行搜索// document.getElementById(searchButton).removeEventListener(click, ...);// // 为搜索按钮添加点击事件// document.getElementById(searchButton).addEventListener(click, function (event) {// event.preventDefault();// app.searchQuery document.getElementById(searchInput).value;// app.search_videos();// }); /script /body/html 3.4.2 前端视频观看页面的实现 !DOCTYPE html html langenheadmeta charsetutf-8meta nameviewport contentwidthdevice-width, initial-scale1meta namedescription contentmeta nameauthor contentOrcasThemesmeta http-equivX-UA-Compatible contentIEEdge /title/title!-- Bootstrap core CSS --link hrefcss/bootstrap.css relstylesheet!-- Custom styles for this template --link relstylesheet hrefcss/screen.csslink relstylesheet hrefcss/animation.css!--[if IE 7]![endif]--link relstylesheet hrefcss/font-awesome.css!--[if lt IE 8]link relstylesheet hrefcss/ie.css typetext/css mediascreen, projection![endif]--link hrefcss/lity.css relstylesheet/headbodydiv idmyapp!-- SINGLE VIDEO --div idsingle-video classcontainer-fluid standard-bg!-- HEADER --div classrow header-topdiv classcol-lg-3 col-md-6 col-sm-5a classmain-logo href#img srcimg/main-logo.png classmain-logo altMuvee Reviews titleMuvee Reviews/a/divdiv classcol-lg-6 hidden-md text-center hidden-sm hidden-xs/divdiv classcol-lg-3 col-md-6 col-sm-7 hidden-xsdiv classright-boxbutton typebutton classaccess-btn v-on:clickdelete_video()视频删除/buttonbutton typebutton classaccess-btn data-togglemodal data-target#enquirypopup视频修改/button/div/div/div!-- MENU --div classrow home-mega-menu div classcol-md-12nav classnavbar navbar-defaultdiv classnavbar-headerbutton classnavbar-toggle typebutton data-togglecollapse data-target.js-navbar-collapsespan classsr-onlyToggle navigation/spanspan classicon-bar/spanspan classicon-bar/spanspan classicon-bar/span/button/divdiv classcollapse navbar-collapse js-navbar-collapse megabg dropshd ul classnav navbar-navlia hrefindex.html视频点播/a/li/uldiv classsearch-blockforminput typesearch placeholderSearch/form/div/div!-- /.nav-collapse --/nav/div/div!-- SINGLE VIDEO --div classrow!-- SIDEBAR --div classcol-lg-2 col-md-4 hidden-sm hidden-xs/div!-- SINGLE VIDEO -- div idsingle-video-wrapper classcol-lg-10 col-md-8div classrow!-- VIDEO SINGLE POST --div classcol-lg-9 col-md-12 col-sm-12!-- POST L size --article classpost-video!-- VIDEO INFO --div classvideo-info!-- 16:9 aspect ratio --div classembed-responsive embed-responsive-16by9 video-embed-boxiframe v-bind:srcvideo.video classembed-responsive-item/iframe/divdiv classmetaboxspan classmeta-ii classfa fa-thumbs-up aria-hiddentrue/i20.895/spanspan classmeta-ii classfa fa-thumbs-down aria-hiddentrue/i3.981/spanspan classmeta-ii classfa fa-user/ia href# classauthor titleJohn DoeJohn Doe/a/spanspan classmeta-ii classfa fa-clock-o/iMarch 16. 2017/spanspan classmeta-ii classfa fa-eye/i1,347,912 views/spandiv classratingsi classfa fa-star aria-hiddentrue/ii classfa fa-star aria-hiddentrue/ii classfa fa-star-half-o aria-hiddentrue/ii classfa fa-star-o/ii classfa fa-star-half/i/div/div/divdiv classclearfix spacer/div!-- DETAILS --div classvideo-contenth2 classtitle main-head-title视频描述/h2p{{video.info}}/p/divdiv classclearfix spacer/div!-- MAIN ROLL ADVERTISE BOX --/article/div!-- VIDEO SIDE BANNERS --div classcol-lg-3 hidden-md hidden-sm/div/divdiv classclearfix spacer/divdiv classrow/div/div/div/div!-- CHANNELS --div idchannels-block classcontainer-fluid channels-bgdiv classcontainer-fluid div classcol-md-12!-- CHANNELS --section idchannels/sectiondiv classclearfix/div/div/div/div!-- BOTTOM BANNER --div idbottom-banner classcontainer text-center /div!-- FOOTER --div idfooter classcontainer-fluid footer-backgrounddiv classcontainerfooter!-- SECTION FOOTER --div classrow!-- TAGS --!-- POST --!-- LINKS --/divdiv classrow copyright-bottom text-centerdiv classcol-md-12 text-centera href classfooter-logo titleVideo Magazine Bootstrap HTML5 templateimg srcimg/footer-logo.png classimg-responsive text-center altVideo Magazine Bootstrap HTML5 template/a pCopyright copy; Author by {{author}}/p/div/div/footer/div/div!-- MODAL --div idenquirypopup classmodal fade in roledialogdiv classmodal-dialog!-- Modal content--div classmodal-content rowdiv classmodal-header custom-modal-headerbutton typebutton classclose data-dismissmodal×/buttonh2 classiconi classfa fa-television aria-hiddentrue/i视频信息修改/h2/divdiv classmodal-bodyform nameinfo_form classform-inline action# methodpostdiv classform-group col-sm-12input typetext classform-control namename v-modelvideo.name/divdiv classform-group col-sm-12input typetext classform-control nameinfo v-modelvideo.info/divdiv classform-group col-sm-12button classsubscribe-btn pull-right titleSubscribe v-on:click.preventupdate_video()提交/button/div/form/div/div/div/div/div/body!-- JAVA SCRIPT --!-- jQuery (necessary for Bootstraps JavaScript plugins) --script srcjs/jquery-1.12.1.min.js/scriptscript srcjs/bootstrap.min.js/scriptscript srcjs/lity.js/scriptscript srchttps://cdn.jsdelivr.net/npm/vue/dist/vue.js/scriptscript$(.nav .dropdown).hover(function() {$(this).find(.dropdown-toggle).dropdown(toggle);});/scriptscriptlet app new Vue({el: #myapp,data: {author: ZhaoYiLong,video: {}},methods: {get_param: function(name) {return decodeURIComponent((new RegExp([?|] name ([^;]?)(|#|;|$)).exec(location.href) || [, ])[1].replace(/\/g, %20)) || null},get_video: function() {var id this.get_param(id);$.ajax({url: /video/ id,type: get,context: this,success : function(result, status, xhr){this.video result;}})},update_video: function() {$.ajax({url: /video/ this.video.id,type: put,data: JSON.stringify(this.video),context: this,success : function(result, status, xhr){alert(修改视频信息成功);window.location.reload();}})},delete_video: function() {$.ajax({url: /video/ this.video.id,type: delete,context: this,success : function(result, status, xhr){alert(删除视频成功);window.location.href/index.html;}})}}});app.get_video();/script /html四.项⽬总结 项目名称C视频共享点播系统项目功能用户通过前端浏览器访问服务器获得展示与观看和操作的界面最终实现视频的上传以及观看的删改查等基础管理功能开发环境Ubuntu22.04云服务器 Vscode MySQL Makefile技术特点http服务器的搭建restful风格接口设计Json序列化线程池htmlcssjs 数据管理模块基于 MYSQL 进⾏数据管理封装数据管理类进⾏数据统⼀访问 业务处理模块 基于 HTTPLIB 搭建 HTTP 服务器使⽤ restful ⻛格 进⾏接⼝设计处理客⼾ 端业务请求   前端界⾯模块基于基础的 HTMLCSSJS 完成基于简单模板前端界⾯的修改与功能完成。 代码链接赵一龙/C-视频点播项目 - 码云 - 开源中国 (gitee.com)
http://www.dnsts.com.cn/news/36803.html

相关文章:

  • 网站服务器是指什么在哪里做网站比较好
  • 做响应式网站费用建一个公司网站多少钱
  • 如何创建个人网站模板网站改标题不改版 k
  • 怎么搞自己的网站在线生成短链接网址
  • 购物网站建设网网页设计制作一个网站
  • 社交网站制作南宁网站建设团队
  • dw php网站建设视频教程企业网站pv是什么
  • 全国领先网站制作WaP网站模块
  • 专业做logo的网站微信公众号对接网站如何做
  • 网站上线 串词如何做旅游休闲网站
  • 亿达城市建设官方网站免费做网站推荐
  • 做网站要学什么西安做企业网站排名
  • 宁波网站建设开发长江工程建设局网站
  • 自己怎么在网上做网站王磊网站建设
  • 青岛营销型网站推广定兴网站建设
  • 蓝色网站特点怎样购买起名软件自己做网站
  • 商务网站网络环境设计购买保险的网站
  • 培训网站欣赏wordpress添加自定义导航
  • 学校英语网站栏目名称外面网站怎么做
  • 做网站项目需求分析是什么重庆网站建设价格费用
  • 招商网站建设的必要性有哪些免费的云服务器
  • 北京怎么做网站推广织梦是什么网站
  • 株洲新站seo1688关键词怎么优化
  • 我国大宗商品交易所厦门谷歌seo公司
  • wordpress网站制作app江小白发展过程中采用了哪些网络营销方式
  • 福永网站优化广州网站制作怎样
  • 连云港商城网站开发设计双流县规划建设局网站
  • 洛阳网站建设官网wordpress 创建 rss
  • 淘宝客网站建设方案书如何给网站做关键字
  • 网站分类表.案例 商务网站的推广策略