見出し画像

[Drogon]HTTPSimpleControllerでボタンが押された回数を数える

前回の記事では、コントローラで受け取ったパラメータを基に、ViewでオーソドックスなHelloを表示するプログラムを例示しました。

しかし多くのアプリケーションでは、画面に表示されたページから何らかのパラメータを受け取り、コントローラで何らかの処理を行って結果で表示を更新するという動きが大半だと思います。

今回はボタンをクリックされた回数を数える簡単なサンプルで、その動作の実現方法を解説していきたいと思います。

プロジェクトの作り方は前回の記事のにありますので、そちらを参考にしていただければと思います。今回はソースコードまで一気に行きます。

コントローラのコード

まずは、コントローラ側のソースコードです。ちなみに using namespace drogon; の記載が自動生成されるので、drogon名前空間内のクラスやメソッドを呼び出すときにdrogon::は不要ですが、解説ということでなるべく書くようにしています。
書き忘れてもビルド通るからたまに抜けているかもしれません。

  • buttonCounter.h

 #pragma  once
 #include  <drogon/HttpSimpleController.h>

using namespace drogon;

class buttonCounter : public drogon::HttpSimpleController<buttonCounter>
{
  public:
    virtual void asyncHandleHttpRequest(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback) override;
    PATH_LIST_BEGIN
    PATH_ADD( "/counter", drogon::Get );
    PATH_LIST_END
};

ここでは、ユーザからのアクセスをした際に表示されるルートパスと、HTTPリクエストを利用して実際のカウント処理を行う/counterというパスを登録しています。

  • buttonCounter.cc

 #include  "buttonCounter.h"

void buttonCounter::asyncHandleHttpRequest(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback)
{
    drogon::HttpViewData viewData;
    auto param = req->getParameter("currentCount");
    std::ostringstream os;
    int num = 0;

    if(!param.empty())
    {
        auto ss = std::istringstream(param);
        ss >> num;
        if(num < 10)
        {
            num++;
        }
        else
        {
            num = 0;
        }
    }
    os << num;

    viewData.insert("clickCount", os.str());
    
    callback(
        drogon::HttpResponse::newHttpViewResponse("buttonView.csp", viewData)
    );
}

何のことはない、0~10まで数え上げて0に戻る簡単なソースコードに、Drogonのリクエスト送出の仕組みが入っただけのコードです。

ビューのコード

  • buttonView.csp

<!DOCTYPE html>
<html>
<%c++
    auto count=@@.get<std::string>("clickCount");
%>
<head>
    <meta charset="UTF-8">
    <title>Button Count Example</title>
</head>

<body>
    <div>You Click the Button {% count %} Times.</div>
	<form action="/counter" method="get">
        <button type="submit" name="currentCount" value={% count %}>Click Me!</button>
	</form> 
</body>
</html>

ビューのコードでは、ボタンのアクションに/counterパスへのリクエストを書くことで、Controllerの数え上げ処理にリクエストを送っています。

この時、buttonのname属性がリクエストパラメータのkey名に、valueが値になります。

CSPファイルの中では、{%%}で挟まれた文字列は変数名として解釈され、その値が展開されますが、このとき使用できるのは、char や std::string クラスなどの文字列型に限られることに注意が必要です。

ビルドして実行

このような画面が表示されます。

うまくカウントされるかな?

ボタンを押してカウントアップされれば正しく動いています。

どうやら問題なさそうだ

今回はHTTPSimpleControllerを使用してアプリを作りました。

このコントローラ、ハンドラで処理したいパスをPATH_ADDで追加していくだけなので、ぱっと見は書きやすいように見えるのですが、パスごとにハンドラメソッドを分けられないので、ハンドラの処理が複雑化しやすくなります。
しかも注意すべき点として、Httpリクエストを処理するコントローラのスレッドは、1リクエストに対して原則1つです。
同時に複数処理する場合にはそのリクエストの分だけスレッドが作成され、それぞれに単一のインスタンスを持つ形で動作します。

つまり、コントローラのメソッドは常にリエントラントであるのが望ましく、例えば現在値を保持する変数をグローバルスコープに置くような実装は可能な限り避けるべきです。

例えば今回の例のであれば、カウントの値をリクエストで自分のアプリに対して送り、変更された値を自分のアプリからのリクエストで受けとることで、値を循環させて保持するように実装しています。

さいごに

今回はコントローラとビューでデータを相互にやり取りするシンプルな例を作成しました。シンプルではありますが、ちょっとした対話的なアプリであれば、この方法を応用するだけで実装出来てしまいます。
皆様もぜひともDrogonを使用したアプリ開発を楽しんでみてください。

この記事が参加している募集

やってみた

この記事が気に入ったらサポートをしてみませんか?