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

实现服务器接口

我们用一个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_id
     int32_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_id
      int32_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. 获取到博客 id
      int32_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");
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值