私人博客定制---服务器接口封装

实现服务器接口

我们用一个http服务器作为底层,但是c++中并没有先成的http服务器,所以我在GitHub上找到一个牛人写的http服务器,拿来直接用,节省本项目开发的时间
这是服务器的链接地址
上面有详细的使用方法,本文就不再解释具体如何实现,就直接用该cpp-httplib这个库来进行开发

https://github.com/yhirose/cpp-httplib.git

然后我们就要实现相应的接口了

  1. 首先我们先要让我们的服务器和数据库连通,所以我们先要进行数据库客户端的初始化和释放
  2. 第二步我们就要设置一些自定义的路由(此处的路由并不是IP里的路由,而是指的是http中对应的方法+path对应到相应的处理函数上),要实现新增博客,查看博客等在数据库里所对应的相应的功能
  3. 第三步,我们要设置静态文件目录,把我们将来写好的网页放到这个目录里

和数据库建立链接

在这一步中,连接很简单,调用我们封装好的数据库API就行,但是断开连接就比较麻烦,因为整个服务器一但启动,他会进入到监听状态,所以必须等服务器关闭时,我们才能断开连接,而我们一般在Linux下关闭服务器都是使用ctrl+c来进行关闭。ctrl+c是一个信号,所以我们可以当触发这个信号时,就进行断开连接操作。

  using namespace httplib;      using namespace blog_system;      //1. 先和数据库建立好链接      mysql = blog_system::MySQLInit();      signal(SIGINT,[](int){blog_system::MySQLRelease(mysql);exit(0);});                                                                                                                                             //2.创建相关数据库处理对象                           BlogTable blog_table(mysql);                         TagTable tag_table(mysql);

我们在进行信号处理时,第二个参数,是一个回调函数,当第一个参数触发时,执行后面回调函数里的内容,但是要写一个函数太麻烦,这里使用c++11中提供的lambda表达式。这样可以使代码更简洁,更容易进行维护。

实现新增博客

我们要先接受请求消息中的body,并把它转化成json,也就是把HHTP中的我们看不懂或者是太难理解的请求,转化为j我们能看懂或是看起来比较方便的json格式。
而我们要实现新增博客必须要经历以下几个步骤

  1. 首先我们肯定要接受http的请求消息,这里就是一个Post请求
  2. 我们要对这个消息进行校验,但是http的格式并不好让我们进行校验,所以我们要先把http的格式转化为json格式,方便我们进行校验
  3. 校验完后,我们就可以调用我们封装好的mysql的API对数据进行操作
  4. 最后我们还要封装正确的返回结果,给用户友好的提示
  5. 这里我们并不使用异常处理,我们使用错误判定,这样更好,虽然代码比较乱,但是可以很容易理解。而且c++中异常处理比较差,功能比较有限
  6. 不光是这个接口,我们每个博客接口都必须捕捉到blog_table这个对象
 server.Post("/blog", [&blog_table](const Request& req, Response& resp) {printf("新增博客!\n");//创建一些我们需要用到的对象Json::FastWriter writer;  //写对象Json::Reader reader;  //读取对象Json::Value req_json; //请求对象                                                                                                                                                                       Json::Value resp_json;  //响应对象//1.获取到请求中的body并解析成json//parse函数中第一个参数是需要解析的字符串//第二个参数是把解析后的字符串放到哪个对象中//第三个参数是注释,默认是true,所以我就不管了bool ret = reader.parse(req.body,req_json);if(!ret){//解析出错,给用户提示printf("解析请求失败! %s\n",req.body.c_str());//构造一个相应对象,告诉客户端出错了resp_json["ok"] = false;resp_json["reason"] = "提交的数据格式有误!\n";resp.status = 400;//返回给客户端,第二个参数设置反回的数据类型resp.set_content(writer.write(resp_json), "application/json");return;}//2. 进行参数校验//这些字段如果缺任何一个,都代表有错if (req_json["title"].empty() || req_json["content"].empty()|| req_json["tag_id"].empty() || req_json["create_time"].empty()) {resp_json["ok"] = false;resp_json["reason"] = "博客的格式出错!\n";resp.status = 400;resp.set_content(writer.write(resp_json), "application/json");return; }//3.调用数据库接口进行操作ret = blog_table.Insert(req_json);if (!ret) {printf("插入博客失败!\n");resp_json["ok"] = false;resp_json["reason"] = "插入失败!\n";resp.status = 500;resp.set_content(writer.write(resp_json), "application/json");return;}//4.封装正确的返回结果resp_json["ok"] = true;resp.set_content(writer.write(resp_json), "application/json");return;});

查看所有博客

server.Get("/blog", [&blog_table](const Request& req, Response& resp) {    printf("查看所有博客!\n");    Json::Reader reader;    Json::FastWriter writer;    Json::Value resp_json;    //如果没传tag_id,返回的是空字符串     const std::string& tag_id = req.get_param_value("tag_id");    // 对于查看博客来说 API 没有请求参数, 不需要解析参数和校验了, 直接构造结果即可    //  1. 调用数据库接口查询数据    Json::Value blogs;    bool ret = blog_table.SelectAll(&blogs, tag_id);    if (!ret) {    resp_json["ok"] = false;    resp_json["reason"] = "查看博客失败\n";    resp.status = 500;    resp.set_content(writer.write(resp_json), "application/json");    return;    }        // 2. 构造响应结果    resp.set_content(writer.write(blogs), "application/json");    return;    });    

查看一篇博客

查看一篇博客内容
查看blog_id,如果这里只写blog_id,这个httplib的库并不能识别,我又仔细看了
这个库的文档,他用了正则表达式,所以我又学习了一些正则表达式的内容
我们可以用\d+ 表示匹配一个数字,但是这里又可能会引发c++中的转义字符,所以我们需要c++11中提供的R()使转义字符不生效
学习正则表达式

 server.Get(R"(/blog/(\d+))", [&blog_table](const Request& req, Response& resp) {//1.解析获取到blog_idint32_t blog_id = std::stoi(req.matches[1].str());printf("查看id为  %d  的博客!\n",blog_id);Json::Value resp_json;Json::FastWriter writer;//2.直接调用数据库操作bool ret = blog_table.SelectOne(blog_id, &resp_json);if (!ret) {resp_json["ok"] = false;resp_json["reason"] = "查看指定博客失败!\n";resp.status = 404;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;
});

删除博客

server.Delete(R"(/blog/(\d+))", [&blog_table](const Request& req, Response& resp) {Json::Value resp_json;Json::FastWriter writer;// 1. 解析获取 blog_id//使用 matches[1] 就能获取到 blog_idint32_t blog_id = std::stoi(req.matches[1].str());printf("删除 id 为%d 的博客!\n",blog_id);// 2. 调用数据库接口删除博客bool ret = blog_table.Delete(blog_id);if (!ret) {resp_json["ok"] = false;resp_json["reason"] = "删除博客失败!\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;});     

修改博客

修改博客就是重新插入新博客,所以我们又要校验博客信息,当然再校验之前还是需要对博客进行解析。

server.Put(R"(/blog/(\d+))", [&blog_table](const Request& req, Response& resp) {Json::Reader reader;Json::FastWriter writer;Json::Value req_json;Json::Value resp_json;// 1. 获取到博客 idint32_t blog_id = std::stoi(req.matches[1].str());printf("修改 id为 %d的博客!\n",blog_id);// 2. 解析博客信息bool ret = reader.parse(req.body, req_json);if (!ret) {resp_json["ok"] = false;resp_json["reason"] = "解析博客失败!\n";resp.status = 400;resp.set_content(writer.write(resp_json), "application/json");return ;}//一定要记得补充上 blog_id req_json["blog_id"] = blog_id;  //从path中得到的id设置到json对象中// 3. 校验博客信息if (req_json["title"].empty() || req_json["content"].empty()|| req_json["tag_id"].empty()) {// 请求解析出错, 返回一个400响应resp_json["ok"] = false;resp_json["reason"] = "更新博客格式错误\n";resp.status = 400;resp.set_content(writer.write(resp_json), "application/json");return;}// 4. 调用数据库接口进行修改ret = blog_table.Update(req_json);if (!ret) {resp_json["ok"] = false;resp_json["reason"] = "更新失败!\n";resp.status = 500;resp.set_content(writer.write(resp_json), "application/json");return;}// 5. 封装正确的数据resp_json["ok"] = true;resp.set_content(writer.write(resp_json), "application/json");return;});

新增标签

新增标签跟新增博客是一样的道理,都需要把依赖对象传进来,然后先进行格式校验,校验前先进行解析,校验完后再调用mysqlAPI,最后带着结果返回。

server.Post("/tag", [&tag_table](const Request& req, Response& resp) {    Json::Reader reader;    Json::FastWriter writer;    Json::Value req_json;    Json::Value resp_json;    printf("新增标签!\n");    // 1. 请求解析成 Json 格式    bool ret = reader.parse(req.body, req_json);    if (!ret) {    resp_json["ok"] = false;    resp_json["reason"] = "解析失败\n";    resp.status = 400;    resp.set_content(writer.write(resp_json), "application/json");    return ;    }    // 2. 校验标签格式    if (req_json["tag_name"].empty()) {    resp_json["ok"] = false;    resp_json["reason"] = "标签格式有误!\n";    resp.status = 400;    resp.set_content(writer.write(resp_json), "application/json");    return;    }         // 3. 调用数据库接口, 插入标签    ret = tag_table.Insert(req_json);    if (!ret) {    resp_json["ok"] = false;    resp_json["reason"] = "插入标签失败!\n";    resp.status = 500;    resp.set_content(writer.write(resp_json), "application/json");    return;    }    // 4. 返回正确的结果    resp_json["ok"] = true;                                                                                                                                                                                resp.set_content(writer.write(resp_json), "application/json");    });    

删除标签

server.Delete(R"(/tag/(\d+))", [&tag_table](const Request& req, Response& resp) {    Json::Value resp_json;    Json::FastWriter writer;    // 1. 解析出 tag_id    int tag_id = std::stoi(req.matches[1].str());    printf("要删除的标签id 为 %d\n",tag_id);    // 2. 执行数据库操作删除标签    bool ret = tag_table.Delete(tag_id);    if (!ret) {    resp_json["ok"] = false;    resp_json["reason"] = "删除所有标签失败\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;    });   

获取所有标签

 server.Get("/tag", [&tag_table](const Request& req, Response& resp) {    printf("获取所有标签\n");Json::Reader reader;Json::FastWriter writer;Json::Value resp_json;// 1. 调用数据库接口查询数据Json::Value tags;bool ret = tag_table.SelectAll(&tags);if (!ret) {resp_json["ok"] = false;resp_json["reason"] = "查找所有标签失败\n";resp.status = 500;resp.set_content(writer.write(resp_json), "application/json");return;}// 2. 构造响应结果resp.set_content(writer.write(tags), "application/json");return;
});

获取静态文件目录

 server.set_base_dir("./wwwroot");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383136.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

私人博客定制

项目背景 可行性方面 需求分析: 详细设计: 数据库设计 博客管理API的设计 标签相关API 服务器端的实现 对数据库操作进行封装 对服务器操作进行封装 客户端实现 具体操作 使用markdown 具体实现 测试 项目效果展示 维护 完整代码 项目…

初识c++中的函数模板

函数模板 函数模板概念 函数模板:编译器生成代码的一个规则。函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。 函数模板格式 //要让这个函数与类型无关 //Add函数模板 template…

深入理解c++中的函数模板

非类型模板参数 模板参数分类类型形参与非类型形参。 类型形参:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。 非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使…

c++中的IO流

c语言中的IO操作 标准类型的输入输出: 输入------>数据来源是通过键盘进行输入输出------>程序中的数据输出到控制台 c语言中: scanf:输入 printf:输出 两个函数的相同点 1 —格式串 2 —不定参数 两个函数的缺陷 1 —用户要提供数据的格式—用户要记忆大量的格式串—…

201301 JAVA2~3级---走格子

请编写一个函数(允许增加子函数),计算n x m的棋盘格子(n为横向的格子数,m为竖向的格子数)沿着各自边缘线从左上角走到右下角,总共有多少种走法,要求不能走回头路,即&…

复习Linux基本操作----常见指令

Linux基本操作 ls命令 ls(list):相当于windows上的文件资源管理器 语法: ls [选项][目录或文件] 功能:对于目录,该命令列出该目录下的所有子目录与文件。对于文件,将列出文件名以及其他信息。 常用选项: -a 列出目…

复习Linux基础操作---权限操作

shell命令以及运行原理 Linux严格意义上说的是一个操作系统,我们称之为“核心(kernel)“ ,但我们一般用户,不能直接使用kernel。而是通过kernel的“外壳”程序,也就是所谓的shell,来与kernel沟…

【剑指offer】_01 (二维数组中的查找)

题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该…

【剑指offer】_02替换空格

题目描述 请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 解题思路 首先我们先算出整个字符串的长度,还有总共多少个空格。因为空格只占一个字节&#…

【剑指offer】_04 重建二叉树

题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。 解题思路 用前序的顺序…

再谈c++中的多态

何为多态 多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。 多态的实现 在继承的体系下 基类中必须有虚函数(被virtual关键字修饰的成员函数),在派生类中必须…

再谈c++中的继承

继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了…

红黑树概念及其相关操作的实现

红黑树的概念 红黑树,是一种二叉搜索树,但它并不像AVL树一样,每个结点绑定一个平衡因子。但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过 对任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c…

模拟实现STL中map和set容器

红黑树的迭代器 //红黑树的迭代器 template<class T> struct RBTreeIterator {typedef RBTreeNode<T>Node;typedef RBTreeIterator<T> Self; public:RBTreeIterator(Node* pNode nullptr):_pNode(pNode){}//具有指针操作T& operator*(){return _pNode-…

【剑指offer】_05 连续子数组最大和

题目描述 HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢&#…

排序上---(排序概念,常见排序算法,直接插入,希尔排序,直接选择排序,堆排序)

排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&#xff0c;若经过排序&…

排序下---(冒泡排序,快速排序,快速排序优化,快速排序非递归,归并排序,计数排序)

排序上 排序上 交换类排序 基本思想&#xff1a;所谓交换&#xff0c;就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置&#xff0c;交换排序的特点是&#xff1a;将键值较大的记录向序列的尾部移动&#xff0c;键值较小的记录向序列的前部移动。 冒泡…

哈希的概念及其操作

哈希概念 顺序结构以及平衡树中&#xff0c;元素关键码与其存储位置之间没有对应的关系&#xff0c;因此在查找一个元素时&#xff0c;必须要经过关键码的多次比较。顺序查找时间复杂度为O(N)&#xff0c;平衡树中为树的高度&#xff0c;即O( Log2N)&#xff0c;搜索的效率取决…

软件工程---1.概述

软件的特征 抽象&#xff1a; 不可触摸&#xff0c;逻辑实体&#xff0c;可记录&#xff0c;但看不到复制成本低&#xff1a;不受物质材料的限制&#xff0c;不受物理定律或加工过程的制约&#xff0c;与开发成本相比&#xff0c;复制成本很低无折旧、受硬件制约、未完全摆脱手…

软件工程---2.软件过程

三个模型 瀑布模型增量模型集成和配置模型 没有适用于所有不同类型软件开发的过程模型。 瀑布模型 需求定义系统和软件的设计实现与单元测试集成与系统测试运行与维护 瀑布模型的特征 从上一项活动中接受该项活动的工作成果&#xff08;工作产品&#xff09;&#xff0c;作…