【HTTP图片服务器】【项目记录4】:服务器API设计&封装数据库操作

一、服务器 API 设计

要实现一个 HTTP 服务器,HTTP 服务器需要接受到 http请求,再返回 http响应,此处需要约定不同的请求来表示不同的操作方式,例如:有些请求表示上传图片,有些请求表示查看图片,有些表示删除图片。

此处我们使用 RESTful风格 的设计。

何为 RESTful风格 ?

  1. http method 来表示操作的动词: POST增、DELETE删、PUT改、GET查
  2. http path表示操作的对象。
  3. 补充信息用 body 传递,body 中通常使用 JSON 格式的数据,响应数据通常也用 JSON 格式组织。

何为 JSON ?

  1. JSON 源于 JavaScript,是一种轻量级的数据交换格式,最主要的用途之一就是序列化。
  2. 对象格式一般为形如 “key:value” 的键值对
  3. JSON 的优点:简洁易读易编写,支持任何类型,扩展性高。

如何使用 JSON ?

  1. 本项目使用语言为 C++,故选用 jsoncpp 库操作和解析 JSON 格式数据。
  2. Reader::parse (Reader是类,parse是方法),把一个 JSON 字符串转成 Json::Value 对象。
  3. Write::write (Write类,write方法),把一个 Json::Value 对象转成 JSON 字符串。
  4. 如何安装 jsoncpp:yum install jsoncpp-devel

具体设计:

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、查看所有图片信息

请求: 
GET /image/

响应:
HTTP/1.1 200 OK 
[
{
	"image_id": 1,
    "image_name": "测试.png",
    "content_type": "image/png",
    "md5": "123456" ,
     ···
}
{
	"image_id": 2,
    "image_name": "测试2.png",
    "content_type": "image/png",
    "md5": "654321" ,
     ···
}
]

3、查看指定图片元信息

请求:   
GET /image/:image_id
 
响应: 
HTTP/1.1 200 OK 
{ 
    "image_id": 1, 
    "image_name": "测试.png", 
    "content_type": "image/png", 
    "md5": "123456" 
} 

4、查看指定图片内容

请求: 
GET /image/show/:image_id 
 
响应:   
HTTP/1.1 200 OK 
content-type: image/png 
[图片]

5、删除图片

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

二、封装数据库操作

//db.hpp

#include <stdint.h>
#include <string>
#include <memory>
#include <mysql/mysql.h>
#include <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", "12345678",
			"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 };
			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)["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 image_system

测试db.hpp:

//db_test.cc

#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(_MSC_VER)
#pragma warning(disable : 4996)
#endif

#include <iostream>
#include "db.hpp"
using namespace image_system;
void TestImageTable() {
	bool ret = false;
	Json::StyledWriter writer;
	MYSQL* mysql = MySQLInit();
	Json::Value image;
	image["image_name"] = "测试.jpg";
	image["size"] = 16 * 1024;
	image["upload_time"] = "2020/11/03";
	image["md5"] = "123456";
	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;
}

db_test.cc的Makefile:

FLAGS=-std=c++11 -L/usr/lib64/mysql -lmysqlclient -ljsoncpp -lpthread -g

.PHONY:all
all:db_test

db_test:db_test.cc db.hpp
 g++ db_test.cc -o db_test $(FLAGS)
 
.PHONY:clean
clean:
 rm db_test

总结:
第一部分数据库模块全部完成,第二部分服务器模块已完成 API 设计。
接下来进行服务器设计。

下一篇:【HTTP图片服务器】【项目记录5】:服务器设计

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值