基于muduo库的图床云共享存储项目(四)
基于muduo库的图床云共享存储项目(四)
- 文件列表功能实现
- /api/myfiles&cmd=count 文件数量
- 功能介绍
- 代码实现
- /api/myfiles&cmd=normal 文件列表
- 功能介绍
- 代码实现
- 分享图片功能的实现
- /api/sharepic?cmd=share 请求图片分享
- 功能介绍
- 代码实现
- /api/sharepic?cmd=browse 请求浏览图片
- 功能介绍
- 代码实现
- /api/sharepic?cmd=normal 我的图片分享
- 功能介绍
- 代码实现
- /api/sharepic?cmd=cancel 取消图片分享
- 功能介绍
- 代码实现
上一章节我们实现了文件的上传以及秒传功能,接下来我们来实现人用户文件列表,现图片分享和文件删除功能。
文件列表功能实现
/api/myfiles&cmd=count 文件数量
对于文件列表,我们所需要考虑的因素就是一页可以存放多少个文件,然后将对应的的文件信息显示出来即可
功能介绍
请求URL
URL | http://192.168.1.6/api/myfiles?cmd=count |
---|---|
请求方式 | POST |
HTTP版本 | 1.1 |
Content-Type | application/json |
请求参数
参数名 | 含义 | 规则说明 | 是否必须 | 缺省值 |
---|---|---|---|---|
token | token | 同上 | 必填 | 无 |
user | 用户名称 | 不能超过32个字符 | 必填 | 无 |
返回结果参数说明
名称 | 含义 | 规则说明 |
---|---|---|
code | 结果值 | 0:验证成功 1:验证失败 |
total | 文件数量 |
处理逻辑
代码实现
api_myfile.h
#ifndef _API_MYFILES_H_
#define _API_MYFILES_H_
#include "api_common.h"
// /api/myfiles&cmd=count
int ApiMyfiles(std::string &url, std::string &post_data, std::string &str_json);#endif
api_myfile.cc
#include "api_myfile.h"// 数据反序列化
int decodeCountJson(std::string &str_json, std::string &user_name, std::string &token) {bool res;Json::Value root;Json::Reader jsonReader;res = jsonReader.parse(str_json, root);if (!res) {LOG_ERROR << "parse reg json failed ";return -1;}int ret = 0;// 用户名if (root["user"].isNull()) {LOG_ERROR << "user null";return -1;}user_name = root["user"].asString();//密码if (root["token"].isNull()) {LOG_ERROR << "token null";return -1;}token = root["token"].asString();return ret;
}// 序列化数据
int encodeCountJson(int ret, int total, string &str_json) {Json::Value root;root["code"] = ret;if (ret == 0) {root["total"] = total; // 正常返回的时候才写入token}Json::FastWriter writer;str_json = writer.write(root);return 0;
}// 查询数据库,根据user_file_list来查询对应的文件数量
int getUserFilesCount(CDBConn *db_conn, string &user_name, int &count) {int ret = 0;// 封装 sql 语句// select count(*) from user_file_list where user_name = 'gantaotao';std::string sql_str = FormatString("select count(*) from user_file_list where user = '%s'", user_name.c_str());// 操作sql语句CResultSet *result_set = db_conn->ExecuteQuery(sql_str.c_str());if (result_set && result_set->Next()) {// 存在在返回count = result_set->GetInt("count(*)");LOG_INFO << "count: " << count;ret = 0;delete result_set;} else {ret = -1;LOG_ERROR << "操作 " << sql_str << "失败";}return ret;
}// 获取对应的文件数量
int handleUserFilesCount(std::string &user_name, int &count) {// 获取对应的 sql 连接池CDBManager *db_manager = CDBManager::getInstance();CDBConn *db_conn = db_manager->GetDBConn("tuchuang_slave");AUTO_REL_DBCONN(db_manager, db_conn);int ret = getUserFilesCount(db_conn, user_name, count);return ret;
}int ApiMyfiles(std::string &url, std::string &post_data, std::string &str_json)
{char cmd[20]; std::string user_name;std::string token;int ret = 0;// 用户拥有的文件数量int total_count = 0;int start;// 一页的文件数量int count;// 解析url定义的参数,判断当前行为QueryParseKeyValue(url.c_str(), "cmd", cmd, NULL);if(strcmp(cmd, "count") == 0) {// 当前获取的是文件的数量操作// 首先进行反序列化操作if (decodeCountJson(post_data, user_name, token) < 0) {encodeCountJson(1, 0, str_json);LOG_ERROR << "decodeCountJson failed";return -1;}// 对token进行验证if (VerifyToken(user_name, token) < 0) {encodeCountJson(1, 0, str_json);LOG_ERROR << "VerifyToken failed";return -1;}// 然后获取对应的文件数量ret = handleUserFilesCount(user_name, total_count);if(ret < 0) {encodeCountJson(1, 0, str_json);} else {encodeCountJson(0, total_count, str_json);}return ret;} else if (strcmp(cmd, "normal") == 0) {} else {encodeGetFileListFailedJson(str_json); LOG_ERROR << "un handle" << cmd; }
}
- 在文件列表中,我们需要获取的就是用户拥有的文件数量,以及一页的文件数量,超过一页的限制以后就需要放置在下一页当中;
- 其实整个逻辑也是跟前面一样的,首先反序列化解析数据,然后进行处理,获取文件的数量,本质就是去 mysql 数据库中查找当前用户所拥有的文件总数,在将对应的总数返回即可;
/api/myfiles&cmd=normal 文件列表
获取到对应的文件数量以后,此时就可以来获取文件列表了,他需要显示的数据如下所示:
功能介绍
请求URL
URL | http://192.168.1.6/api/myfiles?cmd=normal |
---|---|
请求方式 | POST |
HTTP版本 | 1.1 |
Content-Type | application/json |
请求参数
参数名 | 含义 | 规则说明 | 是否必须 | 缺省值 |
---|---|---|---|---|
token | 令牌 | 同上 | 必填 | 无 |
user | 用户名称 | 不能超过32个字符 | 必填 | 无 |
count | 文件个数 | 文件个数需大于0 | 必填 | 无 |
start | 开始位置 | 必填 | 无 |
返回结果参数说明
名称 | 含义 | 规则说明 |
---|---|---|
files | 文件结果集 | “code”: 0正常,1失败 “count”: 返回的当前文件数量,比如2 “total”: 个人文件总共的数量 “user”: 用户名称, “md5”: md5值, “create_time”: 创建时间, “file_name”: 文件名, “share_status”: 共享状态, 0为没有共享, 1为共享 “pv”: 文件下载量,下载一次加1 “url”: URL, “size”: 文件大小, “type”: 文件类型 “type” :文件类型 “size” :文件大小 |
代码实现
api_myfile.cc
#include "api_myfile.h"// 数据反序列化
int decodeCountJson(std::string &str_json, std::string &user_name, std::string &token) {bool res;Json::Value root;Json::Reader jsonReader;res = jsonReader.parse(str_json, root);if (!res) {LOG_ERROR << "parse reg json failed ";return -1;}int ret = 0;// 用户名if (root["user"].isNull()) {LOG_ERROR << "user null";return -1;}user_name = root["user"].asString();//密码if (root["token"].isNull()) {LOG_ERROR << "token null";return -1;}token = root["token"].asString();return ret;
}//解析的json包
// 参数
// {
// "count": 2,
// "start": 0,
// "token": "3a58ca22317e637797f8bcad5c047446",
// "user": "gantaotao"
// }
int decodeFileslistJson(string &str_json, string &user_name, string &token,int &start, int &count) {bool res;Json::Value root;Json::Reader jsonReader;res = jsonReader.parse(str_json, root);if (!res) {LOG_ERROR << "parse reg json failed ";return -1;}int ret = 0;// 用户名if (root["user"].isNull()) {LOG_ERROR << "user null";return -1;}user_name = root["user"].asString();//密码if (root["token"].isNull()) {LOG_ERROR << "token null";return -1;}token = root["token"].asString();if (root["start"].isNull()) {LOG_ERROR << "start null";return -1;}start = root["start"].asInt();if (root["count"].isNull()) {LOG_ERROR << "count null";return -1;}count = root["count"].asInt();return ret;
}// 序列化数据
int encodeCountJson(int ret, int total, string &str_json) {Json::Value root;root["code"] = ret;if (ret == 0) {root["total"] = total; // 正常返回的时候才写入token}Json::FastWriter writer;str_json = writer.write(root);return 0;
}int encodeGetFileListFailedJson(string &str_json) {Json::Value root;root["code"] = 1;Json::FastWriter writer;str_json = writer.write(root);return 0;
}// 查询数据库,根据user_file_list来查询对应的文件数量
int getUserFilesCount(CDBConn *db_conn, string &user_name, int &count) {int ret = 0;// 封装 sql 语句// select count(*) from user_file_list where user_name = 'gantaotao';std::string sql_str = FormatString("select count(*) from user_file_list where user = '%s'", user_name.c_str());// 操作sql语句CResultSet *result_set = db_conn->ExecuteQuery(sql_str.c_str());if (result_set && result_set->Next()) {// 存在在返回count = result_set->GetInt("count(*)");LOG_INFO << "count: " << count;ret = 0;delete result_set;} else {ret = -1;LOG_ERROR << "操作 " << sql_str << "失败";}return ret;
}// 获取对应的文件数量
int handleUserFilesCount(std::string &user_name, int &count) {// 获取对应的 sql 连接池CDBManager *db_manager = CDBManager::getInstance();CDBConn *db_conn = db_manager->GetDBConn("tuchuang_slave");AUTO_REL_DBCONN(db_manager, db_conn);int ret = getUserFilesCount(db_conn, user_name, count);return ret;
}// 获取文件列表
int getUserFileList(string cmd, string &user_name, int &start, int &count, string &str_json)
{LOG_INFO << "getUserFileList into";int ret = 0;int total = 0;string str_sql;CDBManager *db_manager = CDBManager::getInstance();CDBConn *db_conn = db_manager->GetDBConn("tuchuang_slave");AUTO_REL_DBCONN(db_manager, db_conn);//获取总的文件数量ret = getUserFilesCount(db_conn, user_name, total);if(ret < 0) {LOG_ERROR << "getUserFilesCount failed";Json::Value root;root["code"] = 1;Json::FastWriter writer;str_json = writer.write(root);return -1;}// 当前文件数量为0,正常返回if(0 == total) {Json::Value root;root["code"] = 0;root["count"] = 0;root["total"] = 0;Json::FastWriter writer;str_json = writer.write(root);return 0;}// 去user_file_list以及file_info查找对应的文件信息str_sql = FormatString("select user_file_list.*, file_info.url, file_info.size, file_info.type from file_info, \user_file_list where user = '%s' and file_info.md5 = user_file_list.md5 limit %d, %d ", user_name.c_str(), start, count);LOG_INFO << "执行:" << str_sql;CResultSet *result_set = db_conn->ExecuteQuery(str_sql.c_str());if (result_set) {Json::Value root;Json::Value files;root["code"] = 0;root["total"] = total; //即使 total 不为0, file_index为0int file_index = 0;// 和查询结果对比 total// files又是一个数组while (result_set->Next()){// 获取每一个文件的对应的信息Json::Value file;file["user"] = result_set->GetString("user");file["md5"] = result_set->GetString("md5");file["create_time"] = result_set->GetString("create_time");file["file_name"] = result_set->GetString("file_name");file["share_status"] = result_set->GetInt("shared_status");file["pv"] = result_set->GetInt("pv");file["url"] = result_set->GetString("url");file["size"] = result_set->GetInt("size");file["type"] = result_set->GetString("type");files[file_index] = file;file_index++;}// 查询完毕以后进行赋值root["files"] = files;root["count"] = file_index;Json::FastWriter writer;str_json = writer.write(root);LOG_INFO << "str_json: " << str_json;delete result_set;return 0;} else {LOG_ERROR << "ExecuteQuery failed";Json::Value root;root["code"] = 1;Json::FastWriter writer;str_json = writer.write(root);return -1;}
}int ApiMyfiles(std::string &url, std::string &post_data, std::string &str_json)
{char cmd[20]; std::string user_name;std::string token;int ret = 0;// 用户拥有的文件数量int total_count = 0;int start;// 一页的文件数量int count;// 解析url定义的参数,判断当前行为QueryParseKeyValue(url.c_str(), "cmd", cmd, NULL);if(strcmp(cmd, "count") == 0) {// 当前获取的是文件的数量操作// 首先进行反序列化操作if (decodeCountJson(post_data, user_name, token) < 0) {encodeCountJson(1, 0, str_json);LOG_ERROR << "decodeCountJson failed";return -1;}// 对token进行验证if (VerifyToken(user_name, token) < 0) {encodeCountJson(1, 0, str_json);LOG_ERROR << "VerifyToken failed";return -1;}// 然后获取对应的文件数量ret = handleUserFilesCount(user_name, total_count);if(ret < 0) {encodeCountJson(1, 0, str_json);} else {encodeCountJson(0, total_count, str_json);}return ret;} else if (strcmp(cmd, "normal") == 0) {//反序列化if(decodeFileslistJson(post_data, user_name, token, start, count) < 0) {encodeGetFileListFailedJson(str_json);LOG_ERROR << "decodeCountJson failed";return -1;}// 对token进行验证if (VerifyToken(user_name, token) < 0) {encodeGetFileListFailedJson(str_json);LOG_ERROR << "VerifyToken failed";return -1;}// 获取文件列表getUserFileList(cmd, user_name, start, count, str_json);} else {encodeGetFileListFailedJson(str_json); LOG_ERROR << "un handle" << cmd; }
}
- 获取到文件的数量以后,我们就可以加载文件列表了,对于文件列表来说,就是需要获取到我们对应功能实现里面的数据库里面的信息。
- 这儿需要注意的点就在于,获取文件列表的时候,序列化的时候采用的json的处理方式相比于之前存在一点儿差异,也就 files 是作为一个数组的存在,他里面又存在对应的 file , file 是 files 这个数组里面的一些元素。
分享图片功能的实现
图片分享模块需要实现的就是将图片分享出去,别人是可以浏览的,同时我们也是可以取消分享的,他也依赖于一张新的表结构:
DROP TABLE IF EXISTS `share_picture_list`;
CREATE TABLE `share_picture_list` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
`user` varchar(32) NOT NULL COMMENT '文件所属用户',
`filemd5` varchar(256) NOT NULL COMMENT '文件md5',
`file_name` varchar(128) DEFAULT NULL COMMENT '文件名字',
`urlmd5` varchar(256) NOT NULL COMMENT '图床urlmd5',
`key` varchar(8) NOT NULL COMMENT '提取码',
`pv` int(11) DEFAULT '1' COMMENT '文件下载量,默认值为1,下载一次加1',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '文件创建时间',
PRIMARY KEY (`id`),
KEY `idx_user_filemd5` (`user`, `filemd5`),
KEY `idx_urlmd5_user` (`urlmd5`, `user`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COMMENT='图床文件列表';
我们会根据share_picture_list
里面的 filemd5 找到对应的 file_info
需要对应文件,然后将对应的文件在分享出去,此时客户端就可以看见对应分享的文件了
/api/sharepic?cmd=share 请求图片分享
功能介绍
请求URL
URL | http://192.168.1.6/api/sharepic?cmd=share |
---|---|
请求方式 | POST |
HTTP版本 | 1.1 |
Content-Type | application/json |
请求参数
参数名 | 含义 | 规则说明 | 是否必须 | 缺省值 |
---|---|---|---|---|
token | 令牌 | 同上 | 必填 | 无 |
user | 用户名称 | 不能超过32个字符 | 必填 | 无 |
md5 | md5值 | md5加密后的值 | 必填 | 无 |
filename | 文件名称 | 不能超过128个字符 | 必填 | 无 |
返回结果参数说明
名称 | 含义 | 规则说明 |
---|---|---|
code | 结果值 | 0: 成功 1: 失败 4:token验证失败 |
urlmd5 | 分享图片的标识 | 取消分享时也要该标识 |
代码实现
api_sharepicture.h
#ifndef _API_SHAREPICTURE_H_
#define _API_SHAREPICTURE_H_
#include "api_common.h"
int ApiSharepicture(string &url, string &post_data, string &str_json);#endif
api_sharepicture.cc
#include "api_sharepicture.h"//解析的json包
int decodeSharePictureJson(string &str_json, string &user_name, string &token,string &md5, string &filename) {bool res;Json::Value root;Json::Reader jsonReader;res = jsonReader.parse(str_json, root);if (!res) {LOG_ERROR << "parse reg json failed ";return -1;}if (root["token"].isNull()) {LOG_ERROR << "token null";return -1;}token = root["token"].asString();if (root["user"].isNull()) {LOG_ERROR << "user null";return -1;}user_name = root["user"].asString();if (root["md5"].isNull()) {LOG_ERROR << "md5 null";return -1;}md5 = root["md5"].asString();if (root["filename"].isNull()) {LOG_ERROR << "filename null";return -1;}filename = root["filename"].asString();return 0;
}// 进行序列化
int encodeSharePictureJson(int ret, string urlmd5, string &str_json) {Json::Value root;root["code"] = ret;if (HTTP_RESP_OK == ret)root["urlmd5"] = urlmd5;Json::FastWriter writer;str_json = writer.write(root);return 0;
}//分享图片
// 当前设计的是这个文件是否存在不关注
int handleSharePicture(const char *user, const char *filemd5,const char *file_name, string &str_json)
{// 获取数据库连接CDBManager *db_manager = CDBManager::getInstance();CDBConn *db_conn = db_manager->GetDBConn("tuchuang_slave");AUTO_REL_DBCONN(db_manager, db_conn);int ret = 0;string key;// 当前share_file_list里的urlmd5string urlmd5;urlmd5 = RandomString(32); // 这里我们先简单的,直接使用随机数代替 MD5的使用 可以使用token生成那个函数char create_time[TIME_STRING_LEN];time_t now;//获取当前时间now = time(NULL);strftime(create_time, TIME_STRING_LEN - 1, "%Y-%m-%d %H:%M:%S", localtime(&now));// 往对应的的share_file_list添加需要分享的这个文件string str_sql = FormatString("insert into share_picture_list (user, filemd5, file_name, urlmd5, `key`, pv, create_time) values ('%s', '%s', '%s', '%s', '%s', %d, '%s')", user, filemd5, file_name, urlmd5.c_str(), key.c_str(), 0, create_time);LOG_INFO << "执行:" << str_sql;if (!db_conn->ExecuteCreate(str_sql.c_str())) {LOG_ERROR << str_sql << " 操作失败";ret = -1;} else {ret = 0;}// if (ret == 0) {encodeSharePictureJson(HTTP_RESP_OK, urlmd5, str_json);} else {encodeSharePictureJson(HTTP_RESP_FAIL, urlmd5, str_json);}return 0;
}int ApiSharepicture(string &url, string &post_data, string &str_json) {char cmd[20];string user_name; //用户名string md5; //文件md5码string urlmd5;string filename; //文件名字string token;int ret = 0;//解析命令QueryParseKeyValue(url.c_str(), "cmd", cmd, NULL);LOG_INFO << "cmd = " << cmd;if (strcmp(cmd, "share") == 0) //分享文件{ret = decodeSharePictureJson(post_data, user_name, token, md5, filename);if (ret == 0) {handleSharePicture(user_name.c_str(), md5.c_str(), filename.c_str(), str_json);} else {// 回复请求格式错误encodeSharePictureJson(HTTP_RESP_FAIL, urlmd5, str_json);}} else if (strcmp(cmd, "browse") == 0) //请求浏览图片{} else if (strcmp(cmd, "normal") == 0) {}else {LOG_WARN << "un handle " << cmd;}return 0;}
- 当前我们对于分享图片功能的实现,我们是没有提前进行判断的,直接就往
share_file_list
的表中插入了这条记录,最终返回对应文件的urlmd5
即可。
/api/sharepic?cmd=browse 请求浏览图片
功能介绍
当前我们对于分享图片的功能已经进行了实现,那么对应分享出去的图片我们是需要可以进行浏览的,当前部分就是实现请求浏览图片的功能:
请求和应答
URL | http://192.168.1.6/api/sharepic?cmd=browse |
---|---|
请求方式 | POST |
HTTP | 版本 1.1 |
Content-Type | application/json |
请求参数
参数名 | 含义 | 规则说明 | 是否必须 | 缺省值 |
---|---|---|---|---|
urlmd5 | 分享图片的标识 | 必填 | 无 |
返回结果参数说明
名称 | 含义 | 规则说明 |
---|---|---|
code | 结果值 | 0:请求到 url 下载的 url 1:提取码错误 2:文件已经被删除 |
url | 图片下载地址 | |
user | 分享者 | |
time | 分享时间 | |
pv | 浏览次数 |
代码实现
#include "api_sharepicture.h"//解析的json包
int decodeSharePictureJson(string &str_json, string &user_name, string &token,string &md5, string &filename) {bool res;Json::Value root;Json::Reader jsonReader;res = jsonReader.parse(str_json, root);if (!res) {LOG_ERROR << "parse reg json failed ";return -1;}if (root["token"].isNull()) {LOG_ERROR << "token null";return -1;}token = root["token"].asString();if (root["user"].isNull()) {LOG_ERROR << "user null";return -1;}user_name = root["user"].asString();if (root["md5"].isNull()) {LOG_ERROR << "md5 null";return -1;}md5 = root["md5"].asString();if (root["filename"].isNull()) {LOG_ERROR << "filename null";return -1;}filename = root["filename"].asString();return 0;
}int decodeBrowsePictureJson(string &str_json, string &urlmd5) {bool res;Json::Value root;Json::Reader jsonReader;res = jsonReader.parse(str_json, root);if (!res) {LOG_ERROR << "parse reg json failed ";return -1;}if (root["urlmd5"].isNull()) {LOG_ERROR << "urlmd5 null";return -1;}urlmd5 = root["urlmd5"].asString();return 0;
}// 进行序列化
int encodeSharePictureJson(int ret, string urlmd5, string &str_json) {Json::Value root;root["code"] = ret;if (HTTP_RESP_OK == ret)root["urlmd5"] = urlmd5;Json::FastWriter writer;str_json = writer.write(root);return 0;
}int encodeBrowselPictureJson(int ret, int pv, string url, string user,string time, string &str_json) {Json::Value root;root["code"] = ret;if (ret == 0) {root["pv"] = pv;root["url"] = url;root["user"] = user;root["time"] = time;}Json::FastWriter writer;str_json = writer.write(root);return 0;
}// 分享图片
// 当前设计的是这个文件是否存在不关注
int handleSharePicture(const char *user, const char *filemd5,const char *file_name, string &str_json)
{// 获取数据库连接CDBManager *db_manager = CDBManager::getInstance();CDBConn *db_conn = db_manager->GetDBConn("tuchuang_slave");AUTO_REL_DBCONN(db_manager, db_conn);int ret = 0;string key;// 当前share_file_list里的urlmd5string urlmd5;urlmd5 = RandomString(32); // 这里我们先简单的,直接使用随机数代替 MD5的使用 可以使用token生成那个函数char create_time[TIME_STRING_LEN];time_t now;//获取当前时间now = time(NULL);strftime(create_time, TIME_STRING_LEN - 1, "%Y-%m-%d %H:%M:%S", localtime(&now));// 往对应的的share_file_list添加需要分享的这个文件string str_sql = FormatString("insert into share_picture_list (user, filemd5, file_name, urlmd5, `key`, pv, create_time) values ('%s', '%s', '%s', '%s', '%s', %d, '%s')", user, filemd5, file_name, urlmd5.c_str(), key.c_str(), 0, create_time);LOG_INFO << "执行:" << str_sql;if (!db_conn->ExecuteCreate(str_sql.c_str())) {LOG_ERROR << str_sql << " 操作失败";ret = -1;} else {ret = 0;}// if (ret == 0) {encodeSharePictureJson(HTTP_RESP_OK, urlmd5, str_json);} else {encodeSharePictureJson(HTTP_RESP_FAIL, urlmd5, str_json);}return 0;
}// 浏览图片的处理
int handleBrowsePicture(const char *urlmd5, string &str_json) {int ret = 0;string picture_url;string file_name;string user;string filemd5;string create_time;int pv = 0;CDBManager *db_manager = CDBManager::getInstance();CDBConn *db_conn = db_manager->GetDBConn("tuchuang_master");AUTO_REL_DBCONN(db_manager, db_conn);LOG_INFO << "urlmd5: " << urlmd5;// 执行sql语句,去对应的share_picture_list表中找这个图片string sql_cmd = FormatString( "select user, filemd5, file_name, pv, create_time from ""share_picture_list where urlmd5 = '%s'", urlmd5);LOG_INFO << "执行: " << sql_cmd;CResultSet * result_set = db_conn->ExecuteQuery(sql_cmd.c_str());// sql语句语句执行成功,构建我们需要的结果if (result_set && result_set->Next()) {user = result_set->GetString("user");filemd5 = result_set->GetString("filemd5");file_name = result_set->GetString("file_name");pv = result_set->GetInt("pv");create_time = result_set->GetString("create_time");delete result_set;} else {if (result_set) {delete result_set;}ret = -1;goto END;}// 通过对应的filemd5找到对应的文件MD5sql_cmd = FormatString("select url from file_info where md5 ='%s'", filemd5.c_str());LOG_INFO << "执行: " << sql_cmd;// 获取到对应的urlresult_set = db_conn->ExecuteQuery(sql_cmd.c_str());if (result_set && result_set->Next()) {picture_url = result_set->GetString("url");delete result_set;} else {if (result_set) {delete result_set;}ret = -1;goto END;}// 更新访问计数pv += 1;sql_cmd = FormatString( "update share_picture_list set pv = %d where urlmd5 = '%s'", pv, urlmd5);LOG_INFO << "执行: " << sql_cmd;if (!db_conn->ExecuteUpdate(sql_cmd.c_str())) {LOG_ERROR << sql_cmd << " 操作失败";ret = -1;goto END;}ret = 0;END:// 返回对应的结果if (ret == 0) {encodeBrowselPictureJson(HTTP_RESP_OK, pv, picture_url, user,create_time, str_json);} else {encodeBrowselPictureJson(HTTP_RESP_FAIL, pv, picture_url, user,create_time, str_json);}
}int ApiSharepicture(string &url, string &post_data, string &str_json) {char cmd[20];string user_name; //用户名string md5; //文件md5码string urlmd5;string filename; //文件名字string token;int ret = 0;//解析命令QueryParseKeyValue(url.c_str(), "cmd", cmd, NULL);LOG_INFO << "cmd = " << cmd;if (strcmp(cmd, "share") == 0) //分享文件{ret = decodeSharePictureJson(post_data, user_name, token, md5, filename);if (ret == 0) {handleSharePicture(user_name.c_str(), md5.c_str(), filename.c_str(), str_json);} else {// 回复请求格式错误encodeSharePictureJson(HTTP_RESP_FAIL, urlmd5, str_json);}} else if (strcmp(cmd, "browse") == 0) //请求浏览图片{ret = decodeBrowsePictureJson(post_data, urlmd5);LOG_INFO << "post_data: " << post_data << ", urlmd5: " << urlmd5;if (ret == 0) {handleBrowsePicture(urlmd5.c_str(), str_json);} else {// 回复请求格式错误encodeSharePictureJson(HTTP_RESP_FAIL, urlmd5, str_json);}} else if (strcmp(cmd, "normal") == 0) {} else {LOG_WARN << "un handle " << cmd;}return 0;
}
- 对于请求浏览图片来说,依赖于两个表,
share_file_list
和file_info
这两个表,首先需要根据分享图片生成的urlmd5
去对应的share_file_list
当中找到这个图片文件的filemd5
,然后再在对应的file_info
这个表中获取到对应的文件md5
,然后就获取当前图片文件的url
,后续通过这个url
才可以进行浏览。 - 这儿还需要注意的一个点是我们好需要更新对应的访问计数,每访问一次这个共享文件,对应的访问计数就需要进行++操作。
/api/sharepic?cmd=normal 我的图片分享
功能介绍
当前实现的就是获取到我的文件分享列表,其实跟我的文件列表新的实现过程相差不大。
请求和应答
URL | http://192.168.1.6/api/sharepic?cmd=normal |
---|---|
请求方式 | POST |
HTTP | 版本 1.1 |
Content-Type | application/json |
请求参数
参数名 | 含义 | 规则说明 | 是否必须 | 缺省值 |
---|---|---|---|---|
token | 令牌 | 必填 | 无 | |
user | 用户名称 | 不能超过 32 个字符 | 必填 | 无 |
count | 数量 | 必填 | 无 | |
start | 开始位置 | 必填 | 无 |
返回结果参数说明
名称 | 含义 | 规则说明 |
---|---|---|
files | 文件结果集 | “code”:0:正常;1:失败, “count”: 2,// 分页返回数量,如果为 0 则不需要解析 files “total”: 2,总的文件数量, “user”: 用户名称, “filemd5”: 文件 md5 值, “urlmd5”: 图传共享时的 URL, “create_time”: 创建时间, “file_name”: 文件名, “pv”: 文件浏览量,浏览一次加 1, “size”: 文件大小。 |
代码实现
#include "api_sharepicture.h"//解析的json包
int decodeSharePictureJson(string &str_json, string &user_name, string &token,string &md5, string &filename) {bool res;Json::Value root;Json::Reader jsonReader;res = jsonReader.parse(str_json, root);if (!res) {LOG_ERROR << "parse reg json failed ";return -1;}if (root["token"].isNull()) {LOG_ERROR << "token null";return -1;}token = root["token"].asString();if (root["user"].isNull()) {LOG_ERROR << "user null";return -1;}user_name = root["user"].asString();if (root["md5"].isNull()) {LOG_ERROR << "md5 null";return -1;}md5 = root["md5"].asString();if (root["filename"].isNull()) {LOG_ERROR << "filename null";return -1;}filename = root["filename"].asString();return 0;
}int decodeBrowsePictureJson(string &str_json, string &urlmd5) {bool res;Json::Value root;Json::Reader jsonReader;res = jsonReader.parse(str_json, root);if (!res) {LOG_ERROR << "parse reg json failed ";return -1;}if (root["urlmd5"].isNull()) {LOG_ERROR << "urlmd5 null";return -1;}urlmd5 = root["urlmd5"].asString();return 0;
}//解析的json包
int decodePictureListJson(string &str_json, string &user_name, string &token,int &start, int &count) {bool res;Json::Value root;Json::Reader jsonReader;res = jsonReader.parse(str_json, root);if (!res) {LOG_ERROR << "parse reg json failed ";return -1;}if (root["token"].isNull()) {LOG_ERROR << "token null";return -1;}token = root["token"].asString();if (root["user"].isNull()) {LOG_ERROR << "user null";return -1;}user_name = root["user"].asString();if (root["start"].isNull()) {LOG_ERROR << "start null";return -1;}start = root["start"].asInt();if (root["count"].isNull()) {LOG_ERROR << "count null";return -1;}count = root["count"].asInt();return 0;
}// 进行序列化
int encodeSharePictureJson(int ret, string urlmd5, string &str_json) {Json::Value root;root["code"] = ret;if (HTTP_RESP_OK == ret)root["urlmd5"] = urlmd5;Json::FastWriter writer;str_json = writer.write(root);return 0;
}int encodeBrowselPictureJson(int ret, int pv, string url, string user,string time, string &str_json) {Json::Value root;root["code"] = ret;if (ret == 0) {root["pv"] = pv;root["url"] = url;root["user"] = user;root["time"] = time;}Json::FastWriter writer;str_json = writer.write(root);return 0;
}// 分享图片
// 当前设计的是这个文件是否存在不关注
int handleSharePicture(const char *user, const char *filemd5,const char *file_name, string &str_json)
{// 获取数据库连接CDBManager *db_manager = CDBManager::getInstance();CDBConn *db_conn = db_manager->GetDBConn("tuchuang_slave");AUTO_REL_DBCONN(db_manager, db_conn);int ret = 0;string key;// 当前share_file_list里的urlmd5string urlmd5;urlmd5 = RandomString(32); // 这里我们先简单的,直接使用随机数代替 MD5的使用 可以使用token生成那个函数char create_time[TIME_STRING_LEN];time_t now;//获取当前时间now = time(NULL);strftime(create_time, TIME_STRING_LEN - 1, "%Y-%m-%d %H:%M:%S", localtime(&now));// 往对应的的share_file_list添加需要分享的这个文件string str_sql = FormatString("insert into share_picture_list (user, filemd5, file_name, urlmd5, `key`, pv, create_time) values ('%s', '%s', '%s', '%s', '%s', %d, '%s')", user, filemd5, file_name, urlmd5.c_str(), key.c_str(), 0, create_time);LOG_INFO << "执行:" << str_sql;if (!db_conn->ExecuteCreate(str_sql.c_str())) {LOG_ERROR << str_sql << " 操作失败";ret = -1;} else {ret = 0;}// if (ret == 0) {encodeSharePictureJson(HTTP_RESP_OK, urlmd5, str_json);} else {encodeSharePictureJson(HTTP_RESP_FAIL, urlmd5, str_json);}return 0;
}// 浏览图片的处理
int handleBrowsePicture(const char *urlmd5, string &str_json) {int ret = 0;string picture_url;string file_name;string user;string filemd5;string create_time;int pv = 0;CDBManager *db_manager = CDBManager::getInstance();CDBConn *db_conn = db_manager->GetDBConn("tuchuang_master");AUTO_REL_DBCONN(db_manager, db_conn);LOG_INFO << "urlmd5: " << urlmd5;// 执行sql语句,去对应的share_picture_list表中找这个图片string sql_cmd = FormatString( "select user, filemd5, file_name, pv, create_time from ""share_picture_list where urlmd5 = '%s'", urlmd5);LOG_INFO << "执行: " << sql_cmd;CResultSet * result_set = db_conn->ExecuteQuery(sql_cmd.c_str());// sql语句语句执行成功,构建我们需要的结果if (result_set && result_set->Next()) {user = result_set->GetString("user");filemd5 = result_set->GetString("filemd5");file_name = result_set->GetString("file_name");pv = result_set->GetInt("pv");create_time = result_set->GetString("create_time");delete result_set;} else {if (result_set) {delete result_set;}ret = -1;goto END;}// 通过对应的filemd5找到对应的文件MD5sql_cmd = FormatString("select url from file_info where md5 ='%s'", filemd5.c_str());LOG_INFO << "执行: " << sql_cmd;// 获取到对应的urlresult_set = db_conn->ExecuteQuery(sql_cmd.c_str());if (result_set && result_set->Next()) {picture_url = result_set->GetString("url");delete result_set;} else {if (result_set) {delete result_set;}ret = -1;goto END;}// 更新访问计数pv += 1;sql_cmd = FormatString( "update share_picture_list set pv = %d where urlmd5 = '%s'", pv, urlmd5);LOG_INFO << "执行: " << sql_cmd;if (!db_conn->ExecuteUpdate(sql_cmd.c_str())) {LOG_ERROR << sql_cmd << " 操作失败";ret = -1;goto END;}ret = 0;END:// 返回对应的结果if (ret == 0) {encodeBrowselPictureJson(HTTP_RESP_OK, pv, picture_url, user,create_time, str_json);} else {encodeBrowselPictureJson(HTTP_RESP_FAIL, pv, picture_url, user,create_time, str_json);}
}//获取共享图片个数
int getSharePicturesCount(CDBConn *db_conn, string &user_name, int &count) {int ret = 0;// 从mysql加载if (DBGetSharePictureCountByUsername(db_conn, user_name, count) < 0) {LOG_ERROR << "DBGetSharePictureCountByUsername failed";return -1;}return ret;
}// 获取共享文件列表
void handleGetSharePicturesList(const char *user, int start, int count, string &str_json)
{int ret = 0;char sql_cmd[SQL_MAX_LEN] = {0};CResultSet *result_set = NULL;int total = 0;int file_count = 0;Json::Value root;CDBManager *db_manager = CDBManager::getInstance();CDBConn *db_conn = db_manager->GetDBConn("tuchuang_slave");AUTO_REL_DBCONN(db_manager, db_conn);// 获取对应的文件总数total = 0;string temp_user = user;ret = getSharePicturesCount(db_conn, temp_user, total);if (ret < 0) {LOG_ERROR << "getSharePicturesCount failed";ret = -1;goto END;}// 执行对应的sql语句sprintf(sql_cmd,"select share_picture_list.user, share_picture_list.filemd5, share_picture_list.file_name,share_picture_list.urlmd5, share_picture_list.pv, \share_picture_list.create_time, file_info.size from file_info, share_picture_list where share_picture_list.user = '%s' and \file_info.md5 = share_picture_list.filemd5 limit %d, %d", user, start, count);LOG_INFO << "执行: " << sql_cmd;result_set = db_conn->ExecuteQuery(sql_cmd);if (result_set) {// 遍历所有的内容// 获取大小Json::Value files;while (result_set->Next()) {Json::Value file;file["user"] = result_set->GetString("user");file["filemd5"] = result_set->GetString("filemd5");file["file_name"] = result_set->GetString("file_name");file["urlmd5"] = result_set->GetString("urlmd5");file["pv"] = result_set->GetInt("pv");file["create_time"] = result_set->GetString("create_time");file["size"] = result_set->GetInt("size");files[file_count] = file;file_count++;}if (file_count > 0) {root["files"] = files;}ret = 0;delete result_set;} else {ret = -1;}
END:if (ret != 0) {Json::Value root;root["code"] = 1;} else {root["code"] = 0;root["count"] = file_count;root["total"] = total;}str_json = root.toStyledString();LOG_INFO << "str_json: " << str_json;return;}int ApiSharepicture(string &url, string &post_data, string &str_json) {char cmd[20];string user_name; //用户名string md5; //文件md5码string urlmd5;string filename; //文件名字string token;int ret = 0;//解析命令QueryParseKeyValue(url.c_str(), "cmd", cmd, NULL);LOG_INFO << "cmd = " << cmd;if (strcmp(cmd, "share") == 0) //分享文件{ret = decodeSharePictureJson(post_data, user_name, token, md5, filename);if (ret == 0) {handleSharePicture(user_name.c_str(), md5.c_str(), filename.c_str(), str_json);} else {// 回复请求格式错误encodeSharePictureJson(HTTP_RESP_FAIL, urlmd5, str_json);}} else if (strcmp(cmd, "browse") == 0) //请求浏览图片{ret = decodeBrowsePictureJson(post_data, urlmd5);LOG_INFO << "post_data: " << post_data << ", urlmd5: " << urlmd5;if (ret == 0) {handleBrowsePicture(urlmd5.c_str(), str_json);} else {// 回复请求格式错误encodeSharePictureJson(HTTP_RESP_FAIL, urlmd5, str_json);}} else if (strcmp(cmd, "normal") == 0) {int start = 0;int count = 0;ret = decodePictureListJson(post_data, user_name, token, start, count);if (ret == 0) {handleGetSharePicturesList(user_name.c_str(), start, count, str_json);} else {// 回复请求格式错误encodeSharePictureJson(HTTP_RESP_FAIL, urlmd5, str_json);}}else {LOG_WARN << "un handle " << cmd;}return 0;}
- 获取分享文件列表主要就是 handleGetSharePicturesList 这个接口的实现,其实逻辑也很简单,就是去对应的
file_info
和share_picture_list
查找到我们对应的需要的信息,然后返回在进行序列化返回对应的数据即可。
/api/sharepic?cmd=cancel 取消图片分享
功能介绍
当前实现的就是取消我们的对应文件分享的操作。
请求和应答
参数名 | 含义 | 规则说明 | 是否必须 | 缺省值 |
---|---|---|---|---|
token | 令牌 | 必填 | 无 | |
urlmd5 | urlmd5 | 必填 | 无 |
返回结果参数说明
名称 | 含义 | 规则说明 |
---|---|---|
code | 结果值 | 0: 成功 1: 失败 |
代码实现
int decodeCancelPictureJson(string &str_json, string &user_name,string &urlmd5) {bool res;Json::Value root;Json::Reader jsonReader;res = jsonReader.parse(str_json, root);if (!res) {LOG_ERROR << "parse reg json failed ";return -1;}if (root["user"].isNull()) {LOG_ERROR << "user null";return -1;}user_name = root["user"].asString();if (root["urlmd5"].isNull()) {LOG_ERROR << "urlmd5 null";return -1;}urlmd5 = root["urlmd5"].asString();return 0;
}int encodeCancelPictureJson(int ret, string &str_json) {Json::Value root;root["code"] = ret;Json::FastWriter writer;str_json = writer.write(root);return 0;
}
//取消分享文件
void handleCancelSharePicture(const char *user, const char *urlmd5,string &str_json) {int ret = 0;char sql_cmd[SQL_MAX_LEN] = {0};CDBManager *db_manager = CDBManager::getInstance();CDBConn *db_conn = db_manager->GetDBConn("tuchuang_master");AUTO_REL_DBCONN(db_manager, db_conn);//删除在共享图片列表的数据sprintf(sql_cmd, "delete from share_picture_list where user = '%s' and urlmd5 = '%s'", user, urlmd5);LOG_INFO << "执行: " << sql_cmd;if (!db_conn->ExecutePassQuery(sql_cmd)) {LOG_ERROR << sql_cmd << " 操作失败";encodeCancelPictureJson(HTTP_RESP_FAIL, str_json);} else {encodeCancelPictureJson(HTTP_RESP_OK, str_json);}
}
- 删除共享文件其实就是从对应的数据库中将文件删除就可以了,这个逻辑是非常简单的。
以上就是本节实现的内容,后续更新关注下一章节。