このアプリケーションとチュートリアルは、LinuxFr.org で公開されている Quelques cadriciels Web C++ 記事の例に基づいています。
現在、サーバーサイド Web 開発には興味深い言語やフレームワークが数多くあります。この分野では、C++ は最もファッショナブルな言語ではありませんが、興味深い資産がいくつかあります。確かに:
このチュートリアルの目的は、以下を提供することです。
Cutelyst のソースコードはここに含まれています。他の C++ Web フレームワークのソース コードは、この Git リポジトリで入手できます。使用されたさまざまなフレームワークについては、付録にまとめられています。最後に、C++ ライブラリのリストは Awesome C++ で入手できます。
サーバーに保存されている動物の画像を表示するアプリケーションを実装したいと考えています。フォームは、表示する動物の名前の先頭を示すために使用されます。サムネイルをクリックすると画像をフルサイズで表示でき、ページ下部のリンクから情報ページを表示できます。動物データ (名前とファイル パス) はサーバー上の SQLite データベースに保存されます。
ここでは、HTML ページの生成はサーバー上で実行されますが、現在の傾向としてはサーバー側 API を提供し、クライアント側 HTML を生成することになっています。
非常に従来の方法では、MVC タイプのアーキテクチャに従って、つまりデータ (モデル)、その表示 (ビュー)、およびその管理 (コントローラー) を区別することによって、このアプリケーションのコードを編成できます。
私たちのアプリケーションでは、画像はサーバー上で利用可能であり、動物の名前とファイル パスを含むテーブルを含む SQLite データベースを使用します。ファイルanimals.sql
:
CREATE TABLE animals (
id INTEGER PRIMARY KEY ,
name TEXT ,
image TEXT
);
INSERT INTO animals (name, image) VALUES ( ' dolphin ' , ' dolphin-marine-mammals-water-sea-64219.jpg ' );
INSERT INTO animals (name, image) VALUES ( ' dog ' , ' night-garden-yellow-animal.jpg ' );
INSERT INTO animals (name, image) VALUES ( ' owl ' , ' owl.jpg ' );
...
次に、モデル部分は動物タイプと、データベースにクエリを実行し、名前が指定されたプレフィックスで始まる動物タイプのレコードを返す関数 getAnimals になります。ファイルAnimal.hpp:
ビュー部分には、HTML 形式でページを返す 2 つの関数が含まれています。renderAbout は情報ページを返し、renderHome はユーザーが要求した動物を含むメイン ページを返します。ファイルビュー.hpp:
最後に、コントローラー部分はクライアントのイベントを取得し、モデルとビューを更新します。このアプリケーションの場合、実行する複雑な処理はなく、HTTP リクエストを取得して前述の関数を呼び出すだけです。
C++ には、Haskell の Lucid ほど成功した HTML ドキュメント生成ツールがないようです。 CTML ライブラリは、ドキュメントのツリー構造を定義し、対応する HTML コードを生成するために使用されます。ただし、その構文は非常に冗長であり、タグの検証はありません。
これらのシステムは、カスタマイズ可能なテンプレート、つまり、テンプレートのレンダリング時に指定された値に置き換えられるパラメーターが使用される HTML コードの作成で構成されます。
MVC フレームワークは通常、高度なパターン システムを提供しますが、mustache などの独立したツールもあります。 Mustache は、C++ での実装を含む、多くの言語で実装されている形式主義です。たとえば、animal-pistache/src/View.cpp は kainjow のMustache 実装を使用し、次のコード (animals-crow/src/View.cpp) は crow フレームワークの実装を使用します。
const string css = ...
string renderHome ( const string & myquery, const vector<Animal> & animals) {
// create the template
const string homeTmpl = R"(
<html>
<head>
<style>
{{mycss}}
</style>
</head>
<body>
<h1>Animals (Crow)</h1>
<form>
<p> <input type="text" name="myquery" value="{{myquery}}"> </p>
</form>
{{#animals}}
<a href="static/{{image}}">
<div class="divCss">
<p> {{name}} </p>
<img class="imgCss" src="static/{{image}}" />
</div>
</a>
{{/animals}}
<p style="clear: both"><a href="/about">About</a></p>
</body>
</html>
)" ;
// create a context containing the data to use in the template
crow::mustache::context ctx;
ctx[ " mycss " ] = css;
ctx[ " myquery " ] = myquery;
for ( unsigned i= 0 ; i<animals. size (); i++) {
ctx[ " animals " ][i][ " name " ] = animals[i]. name ;
ctx[ " animals " ][i][ " image " ] = animals[i]. image ;
}
// render the template using the context
return crow::mustache::template_t (homeTmpl). render (ctx);
}
string renderAbout () {
...
}
C++ チャネル ストリームを使用して、HTML コードを手動で生成することも比較的簡単です。ただし、この方法では、コードの再利用や、生成された HTML コードの検証は容易になりません。手動生成の例 (animals-silicon/src/main.cpp):
string renderHome ( const string & myquery, const vector<Animal> & animals) {
// create a string stream
ostringstream oss;
// generate some HTML code, in the stream
oss << R"(
<html>
<head>
<link rel="stylesheet" type="text/css" href="mystatic/style.css">
</head>
<body>
<h1>Animals (Silicon)</h1>
<form>
<p> <input type="text" name="myquery" value=" )" << myquery << R"( "> </p>
</form>
)" ;
for ( const Animal & a : animals) {
oss << R"(
<a href="mystatic/ )" << a. image << R"( ">
<div class="divCss">
<p> )" << a. name << R"( </p>
<img class="imgCss" src="mystatic/ )" << a. image << R"( " />
</div>
</a> )" ;
}
oss << R"(
<p style="clear: both"><a href="/about">About</a></p>
</body>
</html>
)" ;
// return the resulting string
return oss. str ();
}
string renderAbout () {
...
}
これにより、SQL クエリを明示的に構築し、データベース システムに送信して結果を取得することが可能になります。 SQL コネクタは一般に使いやすいですが (SQL 言語を知っていれば十分です)、クエリが正しいかどうかはチェックしません。
多くのフレームワークが SQL コネクタを提供しています。たとえば、cppcms (animals-cppcms/src/Animal.cpp を参照)、tntnet (animals-tntnet/src/Animal.cc を参照)、およびシリコン (animals-silicon/src/main.cpp を参照) です。 sqlite_modern_cpp などの独立したコネクタもあります (animals-pistache/src/Animal.cpp を参照)。
# include " Animal.hpp "
# include < sqlite_modern_cpp.h >
using namespace sqlite ;
using namespace std ;
vector<Animal> getAnimals ( const string & myquery) {
vector<Animal> animals;
try {
// open database
database db ( " animals.db " );
// query database and process results
db << " SELECT name,image FROM animals WHERE name LIKE ?||'%' "
<< myquery
>> [&](string name, string image) { animals. push_back ({name, image}); };
}
catch ( exception & e) {
cerr << e. what () << endl;
}
return animals;
}
オブジェクト リレーショナル マッピング (ORM) は、データベース内のテーブルから C++ クラスへのデータの変換、またはその逆の変換に使用されます。これにより、リクエストは C++ 関数によって行われるため、データは型指定システムによってチェックされ、コンパイル時にチェックされるため、データベースをより安全に使用できるようになります。ただし、ORM は SQL と同等の独自の抽象化レイヤーを定義しますが、必然的にあまり知られていません。
たとえば、wt (animals-wt/src/main.cpp を参照)、sqlpp11 (animals-crow/src/Animal.cpp を参照)、または sqlite_orm (animals-cpprestsdk/src/Animal.cpp を参照) など、さまざまな C++ ORM があります。
# include " Animal.hpp "
# include < sqlite_orm/sqlite_orm.h >
using namespace std ;
using namespace sqlite_orm ;
vector<Animal> getAnimals ( const string & myquery) {
vector<Animal> animals;
// open database and map the "animals" table to the "Animal" datatype
auto storage = make_storage (
" animals.db " ,
make_table ( " animals " ,
make_column ( " name " , &Animal::name),
make_column ( " image " , &Animal::image)));
// query database
auto results = storage. get_all <Animal>( where ( like (&Animal::name, myquery+ " % " )));
// process results
for ( auto & animal : results)
animals. push_back (animal);
return animals;
}
Ruby の Sinatra や Python の Flask などのマイクロ Web フレームワークは、シンプルで軽量であることを目指しています。これらは主に、HTTP リクエストと URL ルーティング メカニズムを処理する機能を提供します。必要に応じて、他のライブラリ (HTML 生成、SQL でのデータベースへのアクセスなど) によってこれらを完了することができます。
C++ マイクロフレームワークはいくつかあります。たとえば、crow (動物 - カラスを参照) やシリコン (動物 - シリコンを参照) です。
ここでは、最新の C++ の機能によりコードが簡潔になり、読みやすくなりました。
前処理フェーズでは、Silicon は、ルート (_about、_home、_mystatic...) を含む、プログラマによって定義されたシンボルを宣言するファイルSymbols.hh を生成します。これにより、コード内でルートが正しく使用されていることを静的に検証できます。他の言語ではイントロスペクションを使用してこの種のチェックを実行しますが、C++ にはこの機能がありません。
JavaScript の Node.js/Express などの非同期フレームワークは、ノンブロッキング関数を介して従来のマイクロフレームワークと同じ機能を提供します。したがって、リクエストにリソースが必要な場合、アプリケーションはリソースが利用可能になるまで待機している間に別のリクエストに切り替えることができます。これにより、アプリケーションの全体的なパフォーマンスが向上しますが、非同期処理のチェーンを形成するまでにコールバック関数に接続された Promise に基づく特定のプログラミング スタイルが必要になります。
C++ には、cpprestsdk (animals-cpprestsdk を参照) や pistachio (animals-pistachio を参照) など、さまざまな非同期フレームワークがあります。
ここでは、ルートの古典的な管理 (ルートの名前とその処理関数を使用) を示します。ただし、ノンブロッキング関数による非同期操作が可能になりました。たとえば、「静的」ルートの場合、関数serveFileはコールバック関数に接続されたPromiseを返し、Promiseが解決されるとログメッセージが表示されます。
Ruby on Rails や Python Django などの MVC Web フレームワークは、あらゆる種類の Web アプリケーションを実装することを目的とした古典的なツールです。これらは通常、URL ルーティング、テンプレート システム、データベースへのアクセス、認証システムなど、必要な機能をすべて提供します。MVC フレームワークは C++ の好ましい領域ではないようですが、cppcms amd Cutelyst などの興味深いツールがまだいくつかあります。 。
MVC フレームワークの古典的な機能に加えて、cppcms はビューの継承とコンテンツ管理を備えたかなり高度なテンプレート システムを提供します。たとえば、メイン ビュー MasterView を定義し、そこからビューを派生させることができます。AboutView と HomeView は MasterView の特性を継承し、それらを補完します。最後に、コンテンツをこれらのビュー (テンプレートのパラメーター) に関連付け、継承システムにも関連付けることができます。前の例を使用すると、ビュー MasterView のコンテンツ MasterContent を定義し、ビュー HomeView の HomeContent を派生し、ビュー AboutView に MasterContent を直接使用できます (テンプレートに新しいパラメーターはありません)。
MVC フレームワークは、複雑なアプリケーションを実装するための効果的なツールです。ただし、多くのトレーニングが必要であり、小規模で単純なアプリケーションにはサイズが大きすぎる可能性があります。
tntnet フレームワークは、PHP と同様のテンプレートベースのシステムを提供します。このフレームワークは C++ エコシステムではかなり逸話的なものですが、古典的な HTML コードを記述し、必要に応じて C++ コードのセクションを追加するというアプローチではかなり効果的であるように見えます。
このタイプのフレームワークは、おそらく複雑なアプリケーションの開発にはあまり適していないことに注意してください (テンプレートの可読性、再利用など)。
これらのツールは、Qt や gtkmm などのデスクトップ グラフィカル フレームワークからインスピレーションを得ており、インターフェイスを構成し、シグナル スロット メカニズムを介して対話するウィジェットの階層に基づいています。
Web ベースのウィジェットは、その可能性は重要であるように見えますが、すべての言語であっても驚くほど人気がありません。実際、アプリケーションのネットワーク アーキテクチャについてあまり心配することなく、従来のグラフィカル インターフェイス ライブラリを使用してクライアント/サーバーのフルスタック アプリケーションを開発できます。
C++ では、このカテゴリで最も成功したフレームワークは間違いなく Wt. Wt には、多くの古典的または高度なウィジェット、SQL ORM、認証システム、HTML および CSS を操作する機能などが備わっています。Wt の主なプログラムは、URL を対応するアプリケーションにルーティングすることです。
これらの Wt アプリケーションは従来のグラフィカル インターフェイスに対応しますが、クライアント/サーバー アーキテクチャを備えています。
より複雑なアプリケーションの場合、たとえば動物を表示するページなど、サムネイルを実装する新しいウィジェットを定義し、このクラスを使用してデータベースに読み取られたすべての動物を表示できます。
一見すると、この実装は以前の実装より長くて複雑に見えるかもしれません。ただし、そのコードはデスクトップ GUI 開発者にとって馴染みのあるものであるはずです。さらに、この実装はサーバー部分だけではなく、アプリケーション全体 (フルスタック) を管理します。たとえば、シグナル_myquery->textInput()
をHomeApp::filterAnimals
関数に接続するには、リアルタイムのクライアント側更新が必要ですが、以前のフレームワークでは実装がはるかに困難でした。
バックエンド Web アプリケーションを開発するには、C++ が非常に現実的な選択肢です。最新の開発により、この言語は一般に、パフォーマンスを損なうことなく、よりシンプルかつ安全に使用できるようになりました。テンプレート、HTML 生成、SQL 接続、ORM など、多くの C++ ライブラリが Web 開発に利用できます。Web フレームワークも数多くあり、多様です。RoR や Django などの MVC フレームワーク、Sinatra や Flask などのマイクロフレームワーク、Node.js などの非同期フレームワークなどです。 、PHP テンプレート ベースのフレームワーク、さらにはウィジェット ベースのフルスタック フレームワークもあります。もちろん、他の多くの言語にも Web 開発用の非常に興味深いツールがあるため、これらすべては主に C++ を既に知っている開発者に興味を持ってもらえるでしょう。
次のフレームワーク、ライブラリ、およびツールは、HTTP サーバー、HTML 生成、および SQL データベース アクセスの実装に使用されます。
プロジェクト | ウェブフレームワーク | HTMLジェネレーター | SQLインターフェース |
---|---|---|---|
動物-cppcms | cppcms (Web フレームワーク) | cppcms (テンプレート システム) | cppcms (SQL コネクタ) |
動物-cpprestsdk | cpprestsdk (非同期ネットワーキング フレームワーク) | ctml (HTMLドキュメントジェネレータ) | sqlite_orm (ORM) |
動物-カラス | http: crow (軽量 Web フレームワーク) | crow (テンプレートシステム) | sqlpp11 (ORM) |
動物-最もかわいい | Cutelyst (Web フレームワーク) | Grantlee (テンプレート システム) | Cutelyst (SQL コネクタ) |
動物-nodejs (JavaScript/Node.js) | Express (非同期軽量 Web フレームワーク) | pug (ドキュメントジェネレーター) | better-sqlite3 (SQL コネクタ) |
動物-ピスターシュ | pistache (非同期軽量 Web フレームワーク) | kainjow 口ひげ (テンプレート システム) | sqlite_modern_cpp (SQL コネクタ) |
動物-スコッティ (Haskell) | scotty (軽量 Web フレームワーク) | Lucid と Clay (ドキュメント ジェネレーター) | sqlite-simple (SQL コネクタ) |
動物-シリコン | シリコン (軽量 Web フレームワーク) | なし | シリコン (SQL コネクタ) |
動物-tntnet | tntnet (テンプレートベースの Web フレームワーク) | tntnet (テンプレートシステム) | tntnet (SQL コネクタ) |
動物-体重 | wt (Web GUI フレームワーク) | wt (ウィジェット システム + テンプレート) | 重量 (ORM) |