Make user can use a custom type parameter instead of the first parameter in handlers of HttpControllers (#284)

This commit is contained in:
An Tao 2019-10-19 14:27:34 +08:00 committed by GitHub
parent 3a3a5636e8
commit e7b6ba27bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 112 additions and 30 deletions

View File

@ -68,7 +68,7 @@ int main()
Drogon provides some interfaces for adding controller logic directly in the main() function, for example, user can register a handler like this in Drogon:
```c++
app.registerHandler("/test?username={1}",
app.registerHandler("/test?username={name}",
[](const HttpRequestPtr& req,
std::function<void (const HttpResponsePtr &)> &&callback,
const std::string &name)
@ -158,9 +158,9 @@ class User : public drogon::HttpController<User>
public:
METHOD_LIST_BEGIN
//use METHOD_ADD to add your custom processing function here;
METHOD_ADD(User::getInfo, "/{1}", Get); //path is /api/v1/User/{arg1}
METHOD_ADD(User::getDetailInfo, "/{1}/detailinfo", Get); //path is /api/v1/User/{arg1}/detailinfo
METHOD_ADD(User::newUser, "/{1}", Post); //path is /api/v1/User/{arg1}
METHOD_ADD(User::getInfo, "/{id}", Get); //path is /api/v1/User/{arg1}
METHOD_ADD(User::getDetailInfo, "/{id}/detailinfo", Get); //path is /api/v1/User/{arg1}/detailinfo
METHOD_ADD(User::newUser, "/{name}", Post); //path is /api/v1/User/{arg1}
METHOD_LIST_END
//your declaration of processing function maybe like this:
void getInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;

View File

@ -11,7 +11,7 @@
Drogon的主要应用平台是Linux也支持Mac OS、FreeBSD目前还不支持Windows。它的主要特点如下
* 网络层使用基于epoll(MacOS/FreeBSD下是kqueue)的非阻塞IO框架提供高并发、高性能的网络IO。详细请见[性能测试](https://github.com/an-tao/drogon/wiki/13-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95)
* 网络层使用基于epoll(MacOS/FreeBSD下是kqueue)的非阻塞IO框架提供高并发、高性能的网络IO。详细请见[性能测试](https://github.com/an-tao/drogon/wiki/13-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95)和[TFB Live Results](https://tfb-status.techempower.com/)
* 全异步编程模式;
* 支持Http1.0/1.1(server端和client端)
* 基于template实现了简单的反射机制使主程序框架、控制器(controller)和视图(view)完全解耦;

View File

@ -7,7 +7,7 @@ class CustomCtrl : public drogon::HttpController<CustomCtrl, false>
METHOD_LIST_BEGIN
// use METHOD_ADD to add your custom processing function here;
METHOD_ADD(CustomCtrl::hello,
"/{1}",
"/{userName}",
Get,
"CustomHeaderFilter"); // path is /customctrl/{arg1}
METHOD_LIST_END

View File

@ -374,9 +374,8 @@ void ApiTest::get2(const HttpRequestPtr &req,
callback(res);
}
void ApiTest::jsonTest(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
std::shared_ptr<Json::Value> &&json)
void ApiTest::jsonTest(std::shared_ptr<Json::Value> &&json,
std::function<void(const HttpResponsePtr &)> &&callback)
{
Json::Value ret;
if (json)

View File

@ -18,7 +18,7 @@ class ApiTest : public drogon::HttpController<ApiTest>
"drogon::IntranetIpFilter");
METHOD_ADD(ApiTest::rootPost, "", Post, Options);
METHOD_ADD(ApiTest::get,
"/get/{2:p2}/{1}",
"/get/{2:p2}/{1:p1}",
Get); // path is /api/v1/apitest/get/{arg2}/{arg1}
METHOD_ADD(ApiTest::your_method_name,
"/{PI}/List?P2={}",
@ -26,10 +26,10 @@ class ApiTest : public drogon::HttpController<ApiTest>
METHOD_ADD(ApiTest::staticApi, "/static", Get, Options); // CORS
METHOD_ADD(ApiTest::staticApi, "/static", Post, Put, Delete);
METHOD_ADD(ApiTest::get2,
"/get/{1}",
"/get/{}",
Get); // path is /api/v1/apitest/get/{arg1}
ADD_METHOD_TO(ApiTest::get2,
"/absolute/{1}",
"/absolute/{}",
Get); // path is /absolute/{arg1}
METHOD_ADD(ApiTest::jsonTest, "/json", Post);
METHOD_ADD(ApiTest::formTest, "/form", Post);
@ -54,9 +54,8 @@ class ApiTest : public drogon::HttpController<ApiTest>
std::function<void(const HttpResponsePtr &)> &&callback);
void rootPost(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback);
void jsonTest(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
std::shared_ptr<Json::Value> &&json);
void jsonTest(std::shared_ptr<Json::Value> &&json,
std::function<void(const HttpResponsePtr &)> &&callback);
void formTest(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback);
void attributesTest(

View File

@ -122,7 +122,7 @@ using namespace drogon;
namespace drogon
{
template <>
string_view fromRequest<string_view>(const HttpRequest &req)
string_view fromRequest(const HttpRequest &req)
{
return req.body();
}
@ -143,12 +143,13 @@ int main()
.addListener("0.0.0.0", 8849, true);
}
// Class function example
app().registerHandler("/api/v1/handle1/{1}/{2}/?p3={3}&p4={4}", &A::handle);
app().registerHandler("/api/v1/handle11/{1}/{2}/?p3={3}&p4={4}",
app().registerHandler("/api/v1/handle1/{}/{}/?p3={}&p4={}", &A::handle);
app().registerHandler(
"/api/v1/handle11/{int p1}/{string p2}/?p3={string p3}&p4={int p4}",
&A::staticHandle);
// Lambda example
app().registerHandler(
"/api/v1/handle2/{1}/{2}",
"/api/v1/handle2/{int a}/{float b}",
[](const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
int a, // here the `a` parameter is converted from the number 1
@ -186,7 +187,7 @@ int main()
const std::string &,
int)>
func = std::bind(&A::handle, &tmp, _1, _2, _3, _4, _5, _6);
app().registerHandler("/api/v1/handle4/{4}/{3}/{1}", func);
app().registerHandler("/api/v1/handle4/{4:p4}/{3:p3}/{1:p1}", func);
app().setDocumentRoot("./");
app().enableSession(60);

View File

@ -273,8 +273,11 @@ class HttpBinder : public HttpBinderBase
}
template <typename... Values,
bool isClassFunction = traits::isClassFunction,
bool isDrObjectClass = traits::isDrObjectClass>
typename std::enable_if<isClassFunction && !isDrObjectClass, void>::type
bool isDrObjectClass = traits::isDrObjectClass,
bool isNormal = std::is_same<typename traits::first_param_type,
HttpRequestPtr>::value>
typename std::enable_if<isClassFunction && !isDrObjectClass && isNormal,
void>::type
callFunction(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
Values &&... values)
@ -284,8 +287,11 @@ class HttpBinder : public HttpBinderBase
}
template <typename... Values,
bool isClassFunction = traits::isClassFunction,
bool isDrObjectClass = traits::isDrObjectClass>
typename std::enable_if<isClassFunction && isDrObjectClass, void>::type
bool isDrObjectClass = traits::isDrObjectClass,
bool isNormal = std::is_same<typename traits::first_param_type,
HttpRequestPtr>::value>
typename std::enable_if<isClassFunction && isDrObjectClass && isNormal,
void>::type
callFunction(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
Values &&... values)
@ -295,14 +301,58 @@ class HttpBinder : public HttpBinderBase
(*objPtr.*_func)(req, std::move(callback), std::move(values)...);
}
template <typename... Values,
bool isClassFunction = traits::isClassFunction>
typename std::enable_if<!isClassFunction, void>::type callFunction(
const HttpRequestPtr &req,
bool isClassFunction = traits::isClassFunction,
bool isNormal = std::is_same<typename traits::first_param_type,
HttpRequestPtr>::value>
typename std::enable_if<!isClassFunction && isNormal, void>::type
callFunction(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
Values &&... values)
{
_func(req, std::move(callback), std::move(values)...);
}
////////////////////////////////////////////////////////////////
template <typename... Values,
bool isClassFunction = traits::isClassFunction,
bool isDrObjectClass = traits::isDrObjectClass,
bool isNormal = std::is_same<typename traits::first_param_type,
HttpRequestPtr>::value>
typename std::enable_if<isClassFunction && !isDrObjectClass && !isNormal,
void>::type
callFunction(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
Values &&... values)
{
static auto &obj = getControllerObj<typename traits::class_type>();
(obj.*_func)((*req), std::move(callback), std::move(values)...);
}
template <typename... Values,
bool isClassFunction = traits::isClassFunction,
bool isDrObjectClass = traits::isDrObjectClass,
bool isNormal = std::is_same<typename traits::first_param_type,
HttpRequestPtr>::value>
typename std::enable_if<isClassFunction && isDrObjectClass && !isNormal,
void>::type
callFunction(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
Values &&... values)
{
static auto objPtr =
DrClassMap::getSingleInstance<typename traits::class_type>();
(*objPtr.*_func)((*req), std::move(callback), std::move(values)...);
}
template <typename... Values,
bool isClassFunction = traits::isClassFunction,
bool isNormal = std::is_same<typename traits::first_param_type,
HttpRequestPtr>::value>
typename std::enable_if<!isClassFunction && !isNormal, void>::type
callFunction(const HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
Values &&... values)
{
_func((*req), std::move(callback), std::move(values)...);
}
/////////////
};
} // namespace internal

View File

@ -85,6 +85,39 @@ struct FunctionTraits<
{
static const bool isHTTPFunction = true;
typedef void class_type;
typedef HttpRequestPtr first_param_type;
};
template <typename ReturnType, typename... Arguments>
struct FunctionTraits<
ReturnType (*)(HttpRequestPtr &req,
std::function<void(const HttpResponsePtr &)> &&callback,
Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
{
static const bool isHTTPFunction = false;
typedef void class_type;
};
template <typename ReturnType, typename... Arguments>
struct FunctionTraits<
ReturnType (*)(HttpRequestPtr &&req,
std::function<void(const HttpResponsePtr &)> &&callback,
Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
{
static const bool isHTTPFunction = false;
typedef void class_type;
};
// normal function for HTTP handling
template <typename T, typename ReturnType, typename... Arguments>
struct FunctionTraits<
ReturnType (*)(T &&customReq,
std::function<void(const HttpResponsePtr &)> &&callback,
Arguments...)> : FunctionTraits<ReturnType (*)(Arguments...)>
{
static const bool isHTTPFunction = true;
typedef void class_type;
typedef T first_param_type;
};
// normal function