美文网首页web
cpp-d03-drogon-web开发入门

cpp-d03-drogon-web开发入门

作者: 国服最坑开发 | 来源:发表于2023-03-10 10:30 被阅读0次
    Ranking
    排行来源:https://www.techempower.com/benchmarks/

    今天来学习一下由国人开发的疯狂刷棒的api 框架:drogon

    0x00 准备C++WEB开发环境

    从源码安装,生成项目配置工具。

    git clone [https://github.com/an-tao/drogon](https://github.com/an-tao/drogon)
    cd drogon
    git submodule update --init
    mkdir build
    cmake .. -B .
    make && sudo make install
    

    中途缺啥,直接brew install,大概率可直接解决

    安装完成后,可以使用命令行工具drogon_ctl快捷命令创建和维护代码。
    也可以使用别名:dg_ctl

    查看基础用法:

    $ drogon_ctl help create
    Use create command to create some source files of drogon webapp
    
    Usage:drogon_ctl create <view|controller|filter|project|model> [-options] <object name>
    
    drogon_ctl create view <csp file name> [-o <output path>] [-n <namespace>] [--path-to-namespace] //create HttpView source files from csp files, namespace is prefixed of path-to-namespace
    
    drogon_ctl create controller [-s] <[namespace::]class_name> //create HttpSimpleController source files
    
    drogon_ctl create controller -h <[namespace::]class_name> //create HttpController source files
    
    drogon_ctl create controller -w <[namespace::]class_name> //create WebSocketController source files
    
    drogon_ctl create controller -r <[namespace::]class_name> [--resource=...]//create restful controller source files
    
    drogon_ctl create filter <[namespace::]class_name> //create a filter named class_name
    
    drogon_ctl create plugin <[namespace::]class_name> //create a plugin named class_name
    
    drogon_ctl create project <project_name> //create a project named project_name
    
    drogon_ctl create model <model_path> [--table=<table_name>] [-f]//create model classes in model_path
    

    0x01 创建第一个项目

    • 创建项目
    drogon_ctl create project dc_hello
    

    使用CLion打开此项目是可以直接运行的,访问本机 80 服务,返回404.

    • 添加一个 index响应
      调整main.cpp, 增加一个handler响应处理。
    #include <drogon/drogon.h>
    using namespace drogon;
    int main() {
      drogon::app().addListener("0.0.0.0", 80);
      drogon::app().registerHandler("/",
                                    [](const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) {
                                      auto resp = HttpResponse::newHttpResponse();
                                      resp->setBody("hello world");
                                      callback(resp);
                                    });
      drogon::app().run();
      return 0;
    }
    
    
    • 新增一个Controller,用于处理复杂rest api处理

    开始之前,先看一个url例子:

    http://localhost/api/v1/user/get

    分解一下:

    • api/v1 : 在drogon中, 是以namespace的形式存在
    • user : Controller 处理类,也符合Rest中实体的名称定义
    • get : 在Controller上的某个具体行为

    接下来,开始操作

    cd controllers
    drogon_ctl create controller -h api::v1::User
    

    生成文件后,手动在CMakeFiles.txt 中加上 .cc 文件。

    add_executable(${PROJECT_NAME} main.cc controllers/api_v1_User.cc)
    

    接下来,修改两个文件:

    • .h
    #pragma once
    #include <drogon/HttpController.h>
    using namespace drogon;
    namespace api::v1 {
    class User : public drogon::HttpController<User> {
     public:
      METHOD_LIST_BEGIN
        METHOD_ADD(User::get, "/get", Get);
      METHOD_LIST_END
      void get(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback);
    };
    }
    
    • .cc
    #include "api_v1_User.h"
    using namespace api::v1;
    void User::get(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) {
      Json::Value rst;
      rst["code"] = 0;
      rst["message"] = "ok";
      auto resp = HttpResponse::newHttpJsonResponse(rst);
      callback(resp);
    }
    

    编译运行测试接口:

    $ curl localhost/api/v1/user/get 
    {"code":0,"message":"ok"}
    

    0x02 多种参数获取方式

    一、URL参数

    直接上代码:

      // 增加URI配置, {1}对应方法后面的第一个参数
      METHOD_ADD(User::get_info, "/info/{1}", Get);
      void get_info(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, std::string name);
      void User::get_info(const HttpRequestPtr &req,
                        std::function<void(const HttpResponsePtr &)> &&callback,
                        std::string name) {
      Json::Value rst;
      rst["code"] = 0;
      rst["message"] = "hello: " + name;
      auto resp = HttpResponse::newHttpJsonResponse(rst);
      callback(resp);
    }
    
    

    效果 :

    $ curl localhost/api/v1/user/info/demo 
    {"code":0,"message":"hello: demo"}
    

    二、query参数

      METHOD_ADD(User::get_detail, "/detail?name={1}", Get);
      void get_detail(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, std::string name);
    
      void User::get_detail(const HttpRequestPtr &req,
                          std::function<void(const HttpResponsePtr &)> &&callback,
                          std::string name) {
      Json::Value rst;
      rst["code"] = 0;
      rst["message"] = "detail: " + name;
      auto resp = HttpResponse::newHttpJsonResponse(rst);
      callback(resp);
    }
    

    上面两种,感觉是同一类处理方法,通过类似正则的方式去获取相应的参数。

    三、json Body参数

    编写一个POST方式,提交json的接口例:

      METHOD_ADD(User::add, "/add", Post);
      void add(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback);
      void User::add(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) {
      auto param = req->getJsonObject();
    
      Json::Value rst;
      rst["code"] = 0;
    
      if (param) {
        auto name = (*param)["name"].asString();
        rst["message"] = "user added :" + name;
      }
      auto resp = HttpResponse::newHttpJsonResponse(rst);
      callback(resp);
    }
    
    

    验证:

    $ curl -XPOST localhost/api/v1/user/add -d '{"name":"Cook"}' -H"content-type:application/json"
    {"code":0,"message":"user added :Cook"}
    

    四、json请求参数,自动转为Bean

    在.h文件中, 需要预定义一个转换方法:

    namespace api::v1 {
    struct UserParam {
      std::string name;
      std::string email;
    };
    }
    
    namespace drogon {
    template<>
    inline api::v1::UserParam fromRequest(const HttpRequest &req) {
      auto json = req.getJsonObject();
      api::v1::UserParam param;
      if (json) {
        param.name = (*json)["name"].asString();
        param.email = (*json)["email"].asString();
      }
      return param;
    }
    }
    

    然后编写路由匹配和方法定义:

      METHOD_ADD(User::add_user, "/add/user", Post);
      // 注意: 这里第一个参数是转换后的结构体对象,可以自动提取转换
      void add_user(UserParam &&pUserParam, std::function<void(const HttpResponsePtr &)> &&callback) const;
      void User::add_user(UserParam &&pUserParam, std::function<void(const HttpResponsePtr &)> &&callback) const {
      Json::Value rst;
      rst["code"] = 0;
      rst["message"] = pUserParam.name + ":" + pUserParam.email;
      auto resp = HttpResponse::newHttpJsonResponse(rst);
      callback(resp);
    }
    
    

    0x03 小结

    至此,已经具体API开发的基本能力了, 后续增加其他体验:

    • redis
    • mysql
    • 日志
    • 切面

    最后,也是最重要的官方学习文档:
    https://github.com/drogonframework/drogon-docs/blob/master/CHN-03-%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B.md

    相关文章

      网友评论

        本文标题:cpp-d03-drogon-web开发入门

        本文链接:https://www.haomeiwen.com/subject/jpnzldtx.html