cpp-d03-drogon-web开发入门
2023-03-10 本文已影响0人
国服最坑开发
![](https://img.haomeiwen.com/i3004399/29bb834a6569df9c.png)
排行来源: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例子:
分解一下:
-
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