2020年11月26日11:36:59
c++高性能web框架drogon入门教程一 linux环境搭建和demo运行
c++高性能web框架drogon入门教程二 windows10下安装drogon,配合vscoede搭建开发环境
c++高性能web框架drogon入门教程三 控制器和数据库客户端使用
c++高性能web框架drogon入门教程四 orm使用,csp使用
c++高性能web框架drogon入门教程五 实例小项目,web和api实例代码
powershell
在vscode cmake编译,注意
drogon_ctl -v
查看你的库是否连接成功
Libraries:
postgresql: no (batch mode: no)
mariadb: yes
sqlite3: yes
openssl: yes
brotli: yes
boost: no
c-ares: yes
因为要使用到mysql
控制器
drogon_ctl create controller -h <[namespace::]class_name>
drogon_ctl create controller -h demo::v1::User
控制器头文件
TestCtrl.h
#pragma once
#include <drogon/HttpController.h>
using namespace drogon;
namespace web
{
class TestCtrl:public drogon::HttpController<TestCtrl>
{
public:
METHOD_LIST_BEGIN
// METHOD_ADD(TestCtrl::tt,"/tt",Get);
ADD_METHOD_TO(TestCtrl::name,"/name",Get);
ADD_METHOD_TO(TestCtrl::tt,"/tt",Get);
METHOD_LIST_END
void tt(const HttpRequestPtr& req,std::function<void (const HttpResponsePtr &)> &&callback);
void name(const HttpRequestPtr& req,std::function<void (const HttpResponsePtr &)> &&callback) const;
};
}
注意:ADD_METHOD_TO和METHOD_ADD方法的区别
METHOD_ADD是按照空间名称+文件名称+方法名称
http://127.0.0.1:888/web/TestCtrl/name
ADD_METHOD_TO
就是直接
http://127.0.0.1:888/name
一般传统的mvc我们会分文件夹,比如web,admin,api之类的来区分控制器文件入口,这个就需要去修改CMakeLists.txt
aux_source_directory(controllers CTL_SRC)
aux_source_directory(filters FILTER_SRC)
aux_source_directory(plugins PLUGIN_SRC)
aux_source_directory(models MODEL_SRC)
HttpSimpleController和HttpController注意区分一下
配置数据库,这个有两个配置文件一个是config.json,还有一个models下面的model.json
main.cc
#include <drogon/drogon.h>
int main() {
//Set HTTP listener address and port
// drogon::app().addListener("0.0.0.0",888);
//Load config file
drogon::app().loadConfigFile("../../config.json");
//Run HTTP framework,the method will block in the internal event loop
drogon::app().run();
return 0;
}
我编译的是在build/debug测试,注意你的config.json文件相对应的位置
/* This is a JSON format configuration file
*/
{
//ssl:The global ssl files setting
// "ssl": {
// "cert": "../../trantor/trantor/tests/server.pem",
// "key": "../../trantor/trantor/tests/server.pem"
// },
"listeners": [
{
//address: Ip address,0.0.0.0 by default
"address": "0.0.0.0",
//port: Port number
"port": 888,
//https: If true, use https for security,false by default
"https": false
}
// ,
// {
// "address": "0.0.0.0",
// "port": 443,
// "https": true,
// //cert,key: Cert file path and key file path, empty by default,
// //if empty, use the global setting
// "cert": "",
// "key": "",
// //use_old_tls: enable the TLS1.0/1.1, false by default
// "use_old_tls": false
// }
],
"db_clients": [
{
//name: Name of the client,'default' by default
//"name":"",
//rdbms: Server type, postgresql,mysql or sqlite3, "postgresql" by default
"rdbms": "mysql",
//filename: Sqlite3 db file name
//"filename":"",
//host: Server address,localhost by default
"host": "172.18.1.9",
//port: Server port, 5432 by default
"port": 3306,
//dbname: Database name
"dbname": "v2",
//user: 'postgres' by default
"user": "zx",
//passwd: '' by default
"passwd": "zx",
//is_fast: false by default, if it is true, the client is faster but user can't call
//any synchronous interface of it.
"is_fast": false,
//client_encoding: The character set used by the client. it is empty string by default which
//means use the default character set.
//"client_encoding": "",
//connection_number: 1 by default, if the 'is_fast' is true, the number is the number of
//connections per IO thread, otherwise it is the total number of all connections.
"connection_number": 1
}
],
"app": {
//threads_num: The number of IO threads, 1 by default, if the value is set to 0, the number of threads
//is the number of CPU cores
"threads_num": 1,
//enable_session: False by default
"enable_session": false,
"session_timeout": 0,
//document_root: Root path of HTTP document, defaut path is ./
"document_root": "./",
//home_page: Set the HTML file of the home page, the default value is "index.html"
//If there isn't any handler registered to the path "/", the home page file in the "document_root" is send to clients as a response
//to the request for "/".
"home_page": "index.html",
//static_file_headers: Headers for static files
/*"static_file_headers": [
{
"name": "field-name",
"value": "field-value"
}
],*/
//upload_path: The path to save the uploaded file. "uploads" by default.
//If the path isn't prefixed with /, ./ or ../,
//it is relative path of document_root path
"upload_path": "uploads",
/* file_types:
* HTTP download file types,The file types supported by drogon
* by default are "html", "js", "css", "xml", "xsl", "txt", "svg",
* "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg",
* "gif", "bmp", "ico", "icns", etc. */
"file_types": [
"gif",
"png",
"jpg",
"js",
"css",
"html",
"ico",
"swf",
"xap",
"apk",
"cur",
"xml"
],
//locations: An array of locations of static files for GET requests.
"locations": [{
//uri_prefix: The URI prefix of the location prefixed with "/", the default value is "" that disables the location.
//"uri_prefix": "/.well-known/acme-challenge/",
//default_content_type: The default content type of the static files without
//an extension. empty string by default.
"default_content_type": "text/plain",
//alias: The location in file system, if it is prefixed with "/", it
//presents an absolute path, otherwise it presents a relative path to
//the document_root path.
//The default value is "" which means use the document root path as the location base path.
"alias": "",
//is_case_sensitive: indicates whether the URI prefix is case sensitive.
"is_case_sensitive": false,
//allow_all: true by default. If it is set to false, only static files with a valid extension can be accessed.
"allow_all": true,
//is_recursive: true by default. If it is set to false, files in sub directories can't be accessed.
"is_recursive": true,
//filters: string array, the filters applied to the location.
"filters": []
}],
//max_connections: maximum connections number,100000 by default
"max_connections": 100000,
//max_connections_per_ip: maximum connections number per clinet,0 by default which means no limit
"max_connections_per_ip": 0,
//Load_dynamic_views: False by default, when set to true, drogon
//compiles and loads dynamically "CSP View Files" in directories defined
//by "dynamic_views_path"
"load_dynamic_views": false,
//dynamic_views_path: If the path isn't prefixed with /, ./ or ../,
//it is relative path of document_root path
"dynamic_views_path": [
"./views"
],
//dynamic_views_output_path: Default by an empty string which means the output path of source
//files is the path where the csp files locate. If the path isn't prefixed with /, it is relative
//path of the current working directory.
"dynamic_views_output_path": "",
//enable_unicode_escaping_in_json: true by default, enable unicode escaping in json.
"enable_unicode_escaping_in_json": true,
//log: Set log output, drogon output logs to stdout by default
"log": {
//log_path: Log file path,empty by default,in which case,logs are output to the stdout
//"log_path": "./",
//logfile_base_name: Log file base name,empty by default which means drogon names logfile as
//drogon.log ...
"logfile_base_name": "",
//log_size_limit: 100000000 bytes by default,
//When the log file size reaches "log_size_limit", the log file is switched.
"log_size_limit": 100000000,
//log_level: "DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
//The TRACE level is only valid when built in DEBUG mode.
"log_level": "DEBUG"
},
//run_as_daemon: False by default
"run_as_daemon": false,
//relaunch_on_error: False by default, if true, the program will be restart by the parent after exiting;
"relaunch_on_error": false,
//use_sendfile: True by default, if true, the program
//uses sendfile() system-call to send static files to clients;
"use_sendfile": true,
//use_gzip: True by default, use gzip to compress the response body's content;
"use_gzip": true,
//use_brotli: False by default, use brotli to compress the response body's content;
"use_brotli": false,
//static_files_cache_time: 5 (seconds) by default, the time in which the static file response is cached,
//0 means cache forever, the negative value means no cache
"static_files_cache_time": 5,
//simple_controllers_map: Used to configure mapping from path to simple controller
"simple_controllers_map": [{
"path": "/path/name",
"controller": "controllerClassName",
"http_methods": [
"get",
"post"
],
"filters": [
]
}],
//idle_connection_timeout: Defaults to 60 seconds, the lifetime
//of the connection without read or write
"idle_connection_timeout": 60,
//server_header_field: Set the 'Server' header field in each response sent by drogon,
//empty string by default with which the 'Server' header field is set to "Server: drogon/version string\r\n"
"server_header_field": "",
//enable_server_header: Set true to force drogon to add a 'Server' header to each HTTP response. The default
//value is true.
"enable_server_header": true,
//enable_date_header: Set true to force drogon to add a 'Date' header to each HTTP response. The default
//value is true.
"enable_date_header": true,
//keepalive_requests: Set the maximum number of requests that can be served through one keep-alive connection.
//After the maximum number of requests are made, the connection is closed.
//The default value of 0 means no limit.
"keepalive_requests": 0,
//pipelining_requests: Set the maximum number of unhandled requests that can be cached in pipelining buffer.
//After the maximum number of requests are made, the connection is closed.
//The default value of 0 means no limit.
"pipelining_requests": 0,
//gzip_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
//file with the extension ".gz" in the same path and send the compressed file to the client.
//The default value of gzip_static is true.
"gzip_static": true,
//br_static: If it is set to true, when the client requests a static file, drogon first finds the compressed
//file with the extension ".br" in the same path and send the compressed file to the client.
//The default value of br_static is true.
"br_static": true,
//client_max_body_size: Set the maximum body size of HTTP requests received by drogon. The default value is "1M".
//One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
"client_max_body_size": "1M",
//max_memory_body_size: Set the maximum body size in memory of HTTP requests received by drogon. The default value is "64K" bytes.
//If the body size of a HTTP request exceeds this limit, the body is stored to a temporary file for processing.
//Setting it to "" means no limit.
"client_max_memory_body_size": "64K",
//client_max_websocket_message_size: Set the maximum size of messages sent by WebSocket client. The default value is "128K".
//One can set it to "1024", "1k", "10M", "1G", etc. Setting it to "" means no limit.
"client_max_websocket_message_size": "128K"
},
//plugins: Define all plugins running in the application
"plugins": [{
//name: The class name of the plugin
//"name": "drogon::plugin::SecureSSLRedirector",
//dependencies: Plugins that the plugin depends on. It can be commented out
"dependencies": [],
//config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
//It can be commented out
"config": {
"ssl_redirect_exempt": [".*\\.jpg"],
"secure_ssl_host": "localhost:8849"
}
}],
//custom_config: custom configuration for users. This object can be get by the app().getCustomConfig() method.
"custom_config": {}
}
model.json
{
//rdbms: server type, postgresql,mysql or sqlite3
"rdbms": "mysql",
//filename: sqlite3 db file name
//"filename":"",
//host: server address,localhost by default;
"host": "172.18.1.9",
//port: server port, 5432 by default;
"port": 3306,
//dbname: Database name;
"dbname": "v2",
//schema: valid for postgreSQL, "public" by default;
"schema": "public",
//user: User name
"user": "zx",
//password or passwd: Password
"password": "zx",
//client_encoding: The character set used by drogon_ctl. it is empty string by default which
//means use the default character set.
//"client_encoding": "",
//table: An array of tables to be modelized. if the array is empty, all revealed tables are modelized.
"tables": [],
"restful_api_controllers": {
"enabled": false,
// resource_uri: The URI to access the resource, the default value
// is '/*' in which the asterisk represents the table name.
// If this option is set to a empty string, the URI is composed of the namespaces and the class name.
"resource_uri": "/*",
// class_name: "Restful*Ctrl" by default, the asterisk represents the table name.
// This option can contain namespaces.
"class_name": "Restful*Ctrl",
// filters: an array of filter names.
"filters": [],
// db_client: the database client used by the controller. this option must be consistent with
// the configuration of the application.
"db_client": {
//name: Name of the client,'default' by default
"name": "default",
//is_fast:
"is_fast": false
},
// directory: The directory where the controller source files are stored.
"directory": "controllers",
// generate_base_only: false by default. Set to true to avoid overwriting custom subclasses.
"generate_base_only": false
}
}
TestCtrl.cc
#include "TestCtrl.h"
using namespace web;
void TestCtrl::tt(const HttpRequestPtr &req,
std::function<void (const HttpResponsePtr &)> &&callback)
{
Json::Value ret;
ret["result"]="ok11111";
ret["token"]=drogon::utils::getUuid();
ret["name"] = "zx";
auto resp=HttpResponse::newHttpJsonResponse(ret);
callback(resp);
}
void TestCtrl::name(const HttpRequestPtr &req,
std::function<void (const HttpResponsePtr &)> &&callback) const
{
auto clientPtr = drogon::app().getDbClient();
auto f = clientPtr->execSqlAsyncFuture("select * from admin");
auto r = f.get(); // Block until we get the result or catch the exception;
std::cout << r.size() << " rows selected!" << std::endl;
int i = 0;
for (auto row : r)
{
std::cout << i++ << ": user name is " << row["real_name"].as<std::string>() << std::endl;
}
Json::Value ret;
ret["result"]="ok";
ret["user_name"]="Jack";
ret["gender"]=1;
auto resp=HttpResponse::newHttpJsonResponse(ret);
callback(resp);
}
运行 web.exe,访问http://127.0.0.1:888/name
在控制台就打印出你输出 std::cout << i++ << ": user name is " << row["real_name"].as<std::string>() << std::endl;
drogon_ctl create model <model_path>
drogon_ctl create model models
你的model.json配置的没问题,但是我目前测试发现生成的数据库表实体会有些生成有些有问题,std::string 但是有些会生成 ustd::string,编译出错
已经反馈给作者了
2020年11月26日14:31:06
小bug已经解决
经过沟通之后发现,我的数据库是之前为了数据精度,吧基本上很多int bigint全都改成decimal 但是之前这个数据为了防止负数造成数据溢出,所以有添加unsigned
但是因为数据库是从5.5到5.7,修改完数据库int bigint全都改成decimal之后,没有报错,所以就没有注意到这个问题
刚好这次拿我项目数据做测试,就出现生成数据表实体出错
数据库实体会出现很多警告,请暂时忽略他们
warning C4267: “参数”: 从“size_t”转换到“drogon::orm::Row::SizeType”,可能丢失数据
warning C4244: “参数”: 从“const int64_t”转换到“u_short”,可能丢失数据
message : 查看对正在编译的函数 模板 实例化“drogon::orm::internal::SqlBinder &drogon::orm::internal::SqlBinder::operator <<<const int64_t&>(T)”的引用 [D:\cpp\web\build\web.vcxproj]
[build] with
[build] [
[build] T=const int64_t &
[build] ]
注意新生成的model文件,需要重新camke,建议删除build文件夹下的文件在cmake
cmake -DCMAKE_TOOLCHAIN_FILE=D:/cpp/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows -G"Visual Studio 16 2019" ..