Linux项目---图床

目录

项目背景:

项目描述:

核心需求:

相关技术:

md5算法:

GitHub上的cpp-httplib开源库

json 和 jsoncpp 的使用:

正则表达式:

模块划分:

项目流程:

   数据库设计:

  服务器API设计:

  服务端实现:

 


项目背景:

       当我们在一些软件进行写作或者数据分享的时候,有时候需要上传一些图片来进行辅助说明,当我们上传一张本地图片后,网页就会显示我们所上传的图片,比如博客,简书,知乎等;

        一般来讲这些文档主要有三种格式:HTML、CSS、JS。HTML相当于网页的骨架,CSS相当于网页的衣服,用来规定网页的样式,比如字体大小以及排版等等,而Javascript主要负责一些动态的逻辑,比如在网页上按下一个按键后会显示什么等等。

      一张图片能在网页上显示的原因是网页的HTML文档中嵌入了这张图片的URL,我们可以知道是有一个专门的服务器存储了这张图片,向外提供了一个URL链接让其他端口来访问这张图片。这个专门存储图片的服务器叫做图片服务器也叫做图床。
      本项目就是实现一个简单的HTTP图片服务器,用这个服务器来存储图片,针对每张图片提供一个唯一的URL,有了这个URL之后其他网页就可以借助它把图片展示出来。

 

项目描述:

  1. 实现一个 HTTP 服务器,用该服务器来存储图片;
  2. 针对每个图片提供一个唯一的url, 使用 url 对图片进行访问,;
  3. 提供对图片的增删改查能力,同时搭配简单的页面辅助完成图片上传和展示;

 

核心需求:

  • 利用 HTTP 服务器来为每个图片提供一个唯一访问的 url
  • 使用 Json 封装 http 请求,响应
  • 提供上传图片,查看图片信息/内容以及删除图片接口
  • 使用 lambda 表达式替换函数

相关技术:

  • 实现环境:Linux MySQL-5.5.60 cpp-httplib 库
  • 涉及技术:HTTP 协议 Json C++11 lambda 表达式
  • md5算法:

  1. MD5不可逆的原因是其是一种散列函数,使用的是hash算法
  2. 比如发送一个电子文档,发送前,我先得到MD5的输出结果a。然后在对方收到电子文档后,对方也得到一个MD5的输出结果b。如果a与b一样就代表中途未被篡改。
  3. 比如我提供文件下载,为了防止不法分子在安装程序中添加木马,我可以在网站上公布由安装文件得到的MD5输出结果,SVN在检测文件是否在CheckOut后被修改过,也是用到了MD5.
  4. md5这个字段用来进行校验图片内容正确性
  5. 上传图片之后,服务器就可以计算一个该图片的md5值
  6. 后续用户下载图片的时候,也能获取到该图片的md5,用户可以吧自己计算的md5和服务器计算的md5对比,就知道自己的图片是否下载正确了。
  • GitHub上的cpp-httplib开源库

  1. 支持的 HTTP 方法 
  • GET
  • POST
  • Multipart File Upload
  • Form Encoded
  • PUT
  • HEAD
  • DELETE

使用cpp-httplib构建 HTTP 服务器提供约定的 API 接口;

需要一个http服务器,能接受http请求,回http响应,需要约定不同的请求方式来表示不通的操作方式,例如有些请求表示上传图片,一些请求表示查看图片,一些表示删除图片

  • http方法分类

HTTP/1.1协议中共定义了八种方法(也叫“动作”)来以不同方式操作指定的资源;

  • OPTIONS:这个方法可使服务器传回该资源所支持的所有HTTP请求方法。用'*'来代替资源名称,向Web服务器发送OPTIONS请求,可以测试服务器功能是否正常运作。
  • HEAD:与GET方法一样,都是向服务器发出指定资源的请求。只不过服务器将不传回资源的本文部分。
  • GET:向指定的资源发出“显示”请求。
  • POST:向指定资源提交数据,请求服务器进行处理(例如提交表单或者上传文件)。数据被包含在请求本文中。这个请求可能会创建新的资源或修改现有资源,或二者皆有。
  • PUT:向指定资源位置上传其最新内容。
  • DELETE:请求服务器删除Request-URI所标识的资源。
  • TRACE:回显服务器收到的请求,主要用于测试或诊断。
  • CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。

 

  • json 和 jsoncpp 的使用:

  1. 使用 JSON 作为数据交互格式

  2. json 出自 JavaScript, 是一种非常方便的键值对数据组织格式,主要用途之一就是序列化.
    C++ 中可以使用 jsoncpp 这个库来解析和构造 json 数据

    yum install jsoncpp-devel 

 

  • 正则表达式:

  1. 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。

 

模块划分:

  • 数据存储模块:

  • 服务器模块:

  • 客户端模块:

  • 测试模块

项目流程:

   数据库设计:

 1.安装MySQL C API操作数据库:

yum install mysql-devel

代码中使用时需要链接上 MySQL 提供的库

-L /usr/lib64/mysql -lmysqlclient

创建图片表

文件
数据库:数据库设计(表的结构(表头信息),个数)

create database if not exists image_system;
use image_system;

drop table if exists image_table;
create table image_table(
image_id int not null primary key auto_increment,
image_name varchar(256),
size int,
upload_time varchar(50),
md5 varchar(128),
type varchar(128),
path varchar(1024)
);

insert into image_table values(null,'test.png',1024,'2019/08/26',
'aaaabbbbcccc','png','./data/test.png');

 

2.数据库插入数据:

mysql_insert.cc

// 1. 初始化句柄
// 2. 建立连接
// 3. 设置编码格式
// 4. 拼装 SQL 语句
// 5. 执行 SQL 语句
// 6. 关闭句柄
#include <cstdio>
#include <cstdlib>
#include <memory>
#include <mysql/mysql.h>
int main() {
 // 1. 初始化句柄
 MYSQL* connect_fd = mysql_init(NULL);
 // 2. 建立链接
 // mysql_init 返回的指针
 // 主机地址
 // 用户名
 // 密码
 // 数据库名
 // 端口号
 // unix_socket
 // client_flag
 if (mysql_real_connect(connect_fd, "127.0.0.1", "root", "",
 "image_system", 3306, NULL, 0) == NULL) {
  printf("连接失败! %s\n", mysql_error(connect_fd));
  return 1;
}
 // 3. 设置编码格式
 mysql_set_character_set(connect_fd, "utf8");
 // 4. 拼装 SQL 语句
 char sql[4096] = {0};
 char image_name[] = "滑稽.jpg";

//数据库查找数据
mysql_select.cc
 int size = 16 * 1024;
 char upload_time[] = "2019/05/14";
 char md5[] = "123456";
 char content_type[] = "jpg";
 char path[] = "./滑稽.jpg";
 sprintf(sql, "insert into image_table values(null, '%s', %d, '%s', '%s', '%s', '%s')",
   image_name, size, upload_time, md5, content_type, path);
 // 5. 执行 SQL 语句
 int ret = mysql_query(connect_fd, sql);
 if (ret != 0) {
  printf("执行 sql 失败! %s\n", mysql_error(connect_fd));
  return 1;
}
 // 6. 关闭句柄
 mysql_close(connect_fd);
 printf("执行成功!\n");
 return 0;
}

 

3.数据库查找数据;

mysql_select.cc

// 1. 初始化句柄
// 2. 建立连接
// 3. 设置编码格式
// 4. 拼装 SQL 语句
// 5. 执行 SQL 语句
// 6. 遍历查询结果
// 7. 释放结果集
// 8. 关闭句柄
#include <cstdio>
#include <cstdlib>
#include <mysql/mysql.h>
int main() {
 // 1. 初始化句柄
 MYSQL* connect_fd = mysql_init(NULL);
 // 2. 建立链接
 // mysql_init 返回的指针
 // 主机地址
 // 用户名
 // 密码
 // 数据库名
 // 端口号
 // unix_socket
 // client_flag
 if (mysql_real_connect(connect_fd, "127.0.0.1", "root", "",
 "image_system", 3306, NULL, 0) == NULL) {
  printf("连接失败! %s\n", mysql_error(connect_fd));
  return 1;
}
 // 3. 设置编码格式

服务器 API 设计
新增图片
 mysql_set_character_set(connect_fd, "utf8");
 // 4. 拼装 SQL 语句
char sql[1024 * 4] = {0};
sprintf(sql, "select * from image_table");
 // 5. 执行 SQL 语句
 int ret = mysql_query(connect_fd, sql);
 if (ret < 0) {
  printf("执行 sql 失败! %s\n", mysql_error(connect_fd));
  return 1;
}
 // 6. 遍历查询结果
 MYSQL_RES* result = mysql_store_result(connect_fd);
 if (result == NULL) {
  printf("获取结果失败! %s\n", mysql_error(connect_fd));
  return 1;
}
 // a) 获取行数和列数
 int rows = mysql_num_rows(result);
 int fields = mysql_num_fields(result);
 printf("rows: %d, fields: %d\n", rows, fields);
 // b) 打印结果
 for (int i = 0; i < rows; ++i) {
  MYSQL_ROW row = mysql_fetch_row(result);
  for (int j = 0; j < fields; ++j) {
   printf("%s\t", row[j]);
 }
  printf("\n");
}
 // 7. 释放结果集
 mysql_free_result(result);
 // 8. 关闭句柄
 mysql_close(connect_fd);
 printf("执行成功!\n");
 return 0;
}

  服务器API设计:

  1. 新增图片:
    请求:
    POST /image
    Content-Type: application/x-www-form-urlencoded
    ------WebKitFormBoundary5muoelvEmAAVUyQB
    Content-Disposition: form-data; name="filename"; filename="图标.jpg"
    Content-Type: image/jpeg
    ......[图片正文].....
    响应:
    HTTP/1.1 200 OK
    {
    "ok": true,
    }

     

  2. 查看图片信息:
  3. 查看所有图片元信息
  4. 请求:
    GET /image/
    HTTP/1.1 200 OK
    [
    {
        "image_id": 1,
        "image_name": "1.png",
        "content_type": "image/png",
        "md5": "[md5值]"
     }
    ]
  5. 查看指定图片元信息
  6. 请求:
    GET /image/:image_id
    响应:
    HTTP/1.1 200 OK
    {
    "image_id": 1,
    "image_name": "1.png",
    "content_type": "image/png",
    "md5": "[md5值]"
    }
  7. 查看图片内容
  8. 请求: 
    GET /image/show/:image_id 
    响应: 
    HTTP/1.1 200 OK 
    content-type: image/png 
    [响应 body 中为 图片内容 数据]

 

删除图片:

请求: 
DELETE /image/:image_id 
响应: 
HTTP/1.1 200 OK 
{ 
 "ok": true 
}

  服务端实现:

  1. 数据库操作:

    接口设计

    db.hpp

      

     namespace image_system {
         static MYSQL* MySQLInit() {}
         static void MySQLRelease(MYSQL* mysql) {}
        class ImageTable {
         ImageTable(MYSQL* mysql) { }
         bool Insert(const Json::Value& image);
         bool SelectAll(Json::Value* images);
         bool SelectOne(int32_t image_id, Json::Value* image);
         bool Delete(int image_id);
        };
        }

     

  2. 使用JSON作为数据交互格式:

    json 出自 JavaScript, 是一种非常方便的键值对数据组织格式, 目前被业界广泛使用.

    C++ 中可以使用 jsoncpp 这个库来解析和构造 json 数据

  3. 测试数据库:
    // 实现一个数据库接口测试程序, 用来验证前面的数据库接口是否正确
    #include <iostream> 
    #include "db.hpp" 
    using namespace image_system; 
    void TestImageTable() { 
     bool ret = false; 
     // 更友好的格式化显示 Json 
     Json::StyledWriter writer; 
     MYSQL* mysql = MySQLInit(); 
     Json::Value image; 
     image["name"] = "滑稽.jpg"; 
     image["size"] = 16 * 1024; 
     image["upload_time"] = "2019/01/01"; 
     image["md5"] = "987654321"; 
     image["content_type"] = "image/jpg"; 
     image["path"] = "./滑稽.jpg"; 
     std::cout << "==============测试插入=====================" << std::endl; 
     ImageTable image_table(mysql); 
     ret = image_table.Insert(image); 
     std::cout << "Insert: " << ret << std::endl; 
     std::cout << "==============测试查找=====================" << std::endl; 
     Json::Value images; 
     ret = image_table.SelectAll(&images); 
     std::cout << "SelectAll: " << ret << std::endl 
     << writer.write(images) << std::endl; 
     Json::Value image_out; 
     ret = image_table.SelectOne(1, &image_out); 
     std::cout << "SelectOne: " << ret << std::endl 
     << writer.write(image_out) << std::endl; 
     std::cout << "==============测试删除=====================" << std::endl; 
     int image_id = 2; 
     ret = image_table.Delete(image_id); 
     std::cout << "Delete: " << ret << std::endl; 
     MySQLRelease(mysql); 
    } 
    int main() { 
     TestImageTable(); 
     return 0; 
    }
  4. 服务器基本框架:
  5. 使用 cpp-httplib
    #include "httplib.h" 
    int main() { 
     using namespace httplib; 
     Server server; 
     server.Get("/", [](const Request& req, Response& resp) { 
     (void)req; 
     resp.set_content("<html>hello</html>", "text/html"); 
     }); 
     server.set_base_dir("./wwwroot"); 
     server.listen("0.0.0.0", 9094); 
     return 0; 
    }
    g++ main.cc -lpthread -std=c++11
    /// 
    // 构建 HTTP 服务器提供约定的 API 接口
    /// 
    #include <signal.h> 
    #include <jsoncpp/json/json.h> 
    #include "util.hpp" 
    #include "db.hpp" 
    #include "httplib.h" 
    #include <openssl/md5.h> 
    std::string StringMD5(const std::string& str); 
    const std::string base_path = "./image_data/"; 
    MYSQL* mysql = NULL; 
    int main() { 
     using namespace httplib; 
     using namespace image_system; 
     Server server; 
     // 1. 数据库客户端初始化和释放
     mysql = MySQLInit(); 
     signal(SIGINT, [](int) { MySQLRelease(mysql); exit(0);}); 
     ImageTable image_table(mysql); 
     // 2. 先按照 cpp-httplib 的文档演示基本的图片上传处理过程
     server.Post("/image_test", [](const Request& req, Response& resp) { 
     }); 
     // 3. 新增图片. 
     server.Post("/image", [&image_table](const Request& req, Response& resp) { 
     }); 
     // 4. 查看所有图片的元信息
     server.Get("/image", [&image_table](const Request& req, Response& resp) { 
     }); 
     // 5. 查看图片元信息
     // raw string(c++ 11), 转义字符不生效. 用来表示正则表达式正好合适
     // 关于正则表达式, 只介绍最基础概念即可. \d+ 表示匹配一个数字
     // http://help.locoy.com/Document/Learn_Regex_For_30_Minutes.htm 
     server.Get(R"(/image/(\d+))", [&image_table](const Request& req, Response& resp) { 
     }); 
     // 6. 查看图片内容
     server.Get(R"(/image/show/(\d+))", [&image_table](const Request& req, Response& resp) { 
     }); 
     // 设置静态文件目录
     server.set_base_dir("./wwwroot"); 
     server.listen("0.0.0.0", 9094); 
     return 0; 
    } 
    // 需要包含头文件
    // #include <openssl/md5.h> 
    // Makefile 需要 -lcrypto 
    std::string StringMD5(const std::string& str) { 
     const int MD5LENTH = 16; 
     unsigned char MD5result[MD5LENTH]; 
     // 调用 openssl 的函数计算 md5 
     MD5((const unsigned char*)str.c_str(),str.size(),MD5result); 
     // 转换成字符串的形式方便存储和观察
     char output[1024] = {0}; 
     int offset = 0; 
     for (int i = 0; i < MD5LENTH; ++i) { 
     offset += sprintf(output + offset, "%x", MD5result[i]); 
     } 
     return std::string(output); 
    }

     

  6. 测试上传图片:
    server.Post("/image_test", [](const Request& req, Response& resp) { 
     auto size = req.files.size(); 
     bool ret = req.has_file("filename"); 
     const auto& file = req.get_file_value("filename"); 
     // file.filename 
     // file.content_type 
     auto body = req.body.substr(file.offset, file.length); 
     LOG(INFO) << "size: " << size << ", ret: " << ret << ", " << file.filename << ", " 
     << file.content_type << ", " << file.offset << ", " << file.length << 
    std::endl; 
     FileUtil::WriteFile(file.filename, req.body.substr(file.offset, file.length)); 
     resp.set_content("ok", "text/html"); 
     });
    一个HTTP服务器的作用是接收到http请求,并根据请求返回相应的http响应。
    在HTTP协议中,用户自定制携带一些信息上传给服务器有多种方法,一种比较传统的方法是借助URL中query_string查询字符串来携带一些信息。
    那么我们可以直接使用浏览器构造http请求。
    我们上传图片借助一个HTML文件,在这里我们依旧使用别人封装好的简单的上传方法。
    我们的http请求都使用9090端口,在使用前我们先查看一下端口有没有被占用,具体命令:
    <html> 
    <head> 
     <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> 
    </head> 
    <body> 
     <form method="POST" enctype="multipart/form-data" 
    action="http://47.98.116.42:9094/image"> 
     <table> 
     <tr> 
     <td>文件上传:</td> 
     <td><input type="file" name="filename"/></td> 
     </tr> 
     <tr> 
     <td></td> 
     <td><input type="submit" value="上传"/></td> 
     </tr> 
     </table> 
     </form> 
    </body> 
    </html>

     

  7. 实现接口:

    各个接口代码实现

    db.hpp

    // 这个文件相当于 model 层. 
    // 只进行数据的基本 CURD , 不涉及到更复杂的数据加工
    #pragma once 
    #include <cstdlib> 
    #include <cstring> 
    #include <stdint.h> 
    #include <string> 
    #include <memory> 
    #include <mysql/mysql.h> 
    #include <jsoncpp/json/json.h> 
    namespace image_system { 
    static MYSQL* MySQLInit() { 
     MYSQL* connect_fd = mysql_init(NULL); 
     if (mysql_real_connect(connect_fd, "127.0.0.1", "root", "", 
     "image_system", 3306, NULL, 0) == NULL) { 
     printf("连接失败! %s\n", mysql_error(connect_fd)); 
     return NULL; 
     } 
     mysql_set_character_set(connect_fd, "utf8"); 
     return connect_fd; 
    } 
    static void MySQLRelease(MYSQL* mysql) { 
     mysql_close(mysql); 
    } 
    class ImageTable { 
    public: 
     ImageTable(MYSQL* mysql) : mysql_(mysql) { } 
     bool Insert(const Json::Value& image) { 
     char sql[4096] = {0}; 
     sprintf(sql, "insert into image_table values(null, '%s', %d, '%s','%s', '%s', '%s')", 
     image["name"].asCString(), image["size"].asInt(), image["upload_time"].asCString(), 
     image["md5"].asCString(), image["content_type"].asCString(), 
    image["path"].asCString()); 
     int ret = mysql_query(mysql_, sql); 
     if (ret != 0) { 
     printf("执行 sql 失败! sql=%s, %s\n", sql, mysql_error(mysql_)); 
     return false; 
     } 
     return true; 
     } 
     bool SelectAll(Json::Value* images) { 
     char sql[1024 * 4] = {0}; 
     // 可以根据 tag_id 来筛选结果
     sprintf(sql, "select * from image_table"); 
     int ret = mysql_query(mysql_, sql); 
     if (ret != 0) { 
     printf("执行 sql 失败! %s\n", mysql_error(mysql_));
     return false; 
     } 
     MYSQL_RES* result = mysql_store_result(mysql_); 
     if (result == NULL) { 
     printf("获取结果失败! %s\n", mysql_error(mysql_)); 
     return false; 
     } 
     int rows = mysql_num_rows(result); 
     for (int i = 0; i < rows; ++i) { 
     MYSQL_ROW row = mysql_fetch_row(result); 
     Json::Value image; 
     image["image_id"] = atoi(row[0]); 
     image["image_name"] = row[1]; 
     image["size"] = atoi(row[2]); 
     image["upload_time"] = row[3]; 
     image["md5"] = row[4]; 
     image["content_type"] = row[5]; 
     image["path"] = row[6]; 
     images->append(image); 
     } 
     return true; 
     } 
     bool SelectOne(int32_t image_id, Json::Value* image) { 
     char sql[1024 * 4] = {0}; 
     sprintf(sql, "select * from image_table where image_id = %d", image_id); 
     int ret = mysql_query(mysql_, sql); 
     if (ret != 0) { 
     printf("执行 sql 失败! %s\n", mysql_error(mysql_)); 
     return false; 
     } 
     MYSQL_RES* result = mysql_store_result(mysql_); 
     if (result == NULL) { 
     printf("获取结果失败! %s\n", mysql_error(mysql_)); 
     return false; 
     } 
     int rows = mysql_num_rows(result); 
     if (rows != 1) { 
     printf("查找结果不为 1 条. rows = %d!\n", rows); 
     return false; 
     } 
     MYSQL_ROW row = mysql_fetch_row(result); 
     (*image)["image_id"] = atoi(row[0]); 
     (*image)["name"] = row[1]; 
     (*image)["size"] = atoi(row[2]); 
     (*image)["upload_time"] = row[3]; 
     (*image)["md5"] = row[4]; 
     (*image)["content_type"] = row[5]; 
     (*image)["path"] = row[6]; 
     return true; 
     } 
     bool Delete(int image_id) {
    char sql[1024 * 4] = {0}; 
     sprintf(sql, "delete from image_table where image_id=%d", image_id); 
     int ret = mysql_query(mysql_, sql); 
     if (ret != 0) { 
     printf("执行 sql 失败! sql=%s, %s\n", sql, mysql_error(mysql_)); 
     return false; 
     } 
     return true; 
     } 
    private: 
     MYSQL* mysql_; 
    }; 
    } // end blog_system
     
    实现完整上传图片接口
    // 3. 新增图片. 
     server.Post("/image", [&image_table](const Request& req, Response& resp) { 
     Json::FastWriter writer; 
     Json::Value resp_json; 
     LOG(INFO) << "新增图片" << std::endl; 
     // 1. 进行参数校验
     bool ret = req.has_file("filename"); 
     if (!ret) { 
     resp_json["ok"] = false; 
     resp_json["reason"] = "req has no filename field!"; 
     resp.status = 400; 
     resp.set_content(writer.write(resp_json), "application/json"); 
     return; 
     } 
     // 2. 构造 Json 格式数据, 并调用数据层接口插入数据
     const auto& file = req.get_file_value("filename"); 
     const std::string& image_body = req.body.substr(file.offset, file.length); 
     Json::Value image; 
     image["name"] = file.filename; 
     image["size"] = (int)file.length; 
     image["upload_time"] = TimeUtil::FormatTime(); 
     image["md5"] = StringMD5(image_body); 
     image["content_type"] = file.content_type; 
     // 为了防止重复, 用 md5 作为文件名更稳妥
     image["path"] = base_path + file.filename; 
     ret = image_table.Insert(image); 
     if (!ret) { 
     resp_json["ok"] = false; 
     resp_json["reason"] = "insert db failed!"; 
     resp.status = 500; 
     resp.set_content(writer.write(resp_json), "application/json"); 
     return; 
     } 
     // 3. 保存文件实体
     FileUtil::WriteFile(image["path"].asString(), image_body); 
     // 4. 构造响应
     resp_json["ok"] = true; 
     resp.set_content(writer.write(resp_json), "text/html"); 
     });
    实现查看所有图片元信息接口
     // 4. 查看所有图片的元信息
     server.Get("/image", [&image_table](const Request& req, Response& resp) { 
     (void) req; 
     Json::Reader reader; 
     Json::FastWriter writer; 
     Json::Value resp_json; 
     LOG(INFO) << "查看所有图片信息: " << std::endl; 
     // 1. 调用数据库接口查询数据
     Json::Value images; 
     bool ret = image_table.SelectAll(&images); 
     if (!ret) { 
     resp_json["ok"] = false; 
     resp_json["reason"] = "SelectAll failed!\n"; 
     resp.status = 500; 
     resp.set_content(writer.write(resp_json), "application/json"); 
     return; 
     } 
     // 2. 构造响应结果
     resp.set_content(writer.write(images), "application/json"); 
     return; 
     });
    实现查看单个图片元信息接口
     // 5. 查看图片元信息
     // raw string(c++ 11), 转义字符不生效. 用来表示正则表达式正好合适
     // 关于正则表达式, 只介绍最基础概念即可. \d+ 表示匹配一个数字
     // http://help.locoy.com/Document/Learn_Regex_For_30_Minutes.htm 
     server.Get(R"(/image/(\d+))", [&image_table](const Request& req, Response& resp) { 
     Json::Reader reader; 
     Json::FastWriter writer; 
     Json::Value resp_json; 
     // 1. 获取到图片 id 
     int image_id = std::stoi(req.matches[1]); 
     LOG(INFO) << "查看图片信息: " << image_id << std::endl;
    // 2. 调用数据库接口查询数据
     Json::Value image; 
     bool ret = image_table.SelectOne(image_id, &image); 
     if (!ret) { 
     resp_json["ok"] = false; 
     resp_json["reason"] = "SelectOne failed!\n"; 
     resp.status = 500; 
     resp.set_content(writer.write(resp_json), "application/json"); 
     return; 
     } 
     // 3. 构造响应结果
     resp.set_content(writer.write(image), "application/json"); 
     return; 
     });

    实现查看图片内容接口

     // 6. 查看图片内容
     server.Get(R"(/image/show/(\d+))", [&image_table](const Request& req, Response& resp) { 
     Json::Reader reader; 
     Json::FastWriter writer; 
     Json::Value resp_json; 
     // 1. 获取到图片 id 
     int image_id = std::stoi(req.matches[1]); 
     LOG(INFO) << "查看图片信息: " << image_id << std::endl; 
     // 2. 调用数据库接口查询数据
     Json::Value image; 
     bool ret = image_table.SelectOne(image_id, &image); 
     if (!ret) { 
     resp_json["ok"] = false; 
     resp_json["reason"] = "SelectOne failed!\n"; 
     resp.status = 500; 
     resp.set_content(writer.write(resp_json), "application/json"); 
     return; 
     } 
     std::string image_body; 
     ret = FileUtil::ReadFile(image["path"].asString(), &image_body); 
     if (!ret) { 
     resp_json["ok"] = false; 
     resp_json["reason"] = "path open failed\n"; 
     resp.status = 500; 
     resp.set_content(writer.write(resp_json), "application/json"); 
     return; 
     } 
     // 3. 构造响应结果
     resp.set_content(image_body, image["content_type"].asCString()); 
     return; 
     });

    实现删除图片接口

     // 7. 删除图片
     server.Delete(R"(/image/(\d+))", [&image_table](const Request& req, Response& resp) { 
     Json::Value resp_json; 
     Json::FastWriter writer; 
     // 1. 解析获取 blog_id 
     // 使用 matches[1] 就能获取到 blog_id 
     // LOG(INFO) << req.matches[0] << "," << req.matches[1] << "\n"; 
     int image_id = std::stoi(req.matches[1]); 
     LOG(INFO) << "删除指定图片: " << image_id << std::endl; 
     // 2. 调用数据库接口删除博客
     bool ret = image_table.Delete(image_id); 
     if (!ret) { 
     resp_json["ok"] = false; 
     resp_json["reason"] = "Delete failed!\n"; 
     resp.status = 500; 
     resp.set_content(writer.write(resp_json), "application/json"); 
     return; 
     } 
     // 3. 包装正确的响应
     resp_json["ok"] = true; 
     resp.set_content(writer.write(resp_json), "application/json"); 
     return; 
     });

     

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值