Aplikasi dan tutorial ini didasarkan pada contoh dalam artikel Quelques cadriciels Web C++ yang diterbitkan di LinuxFr.org.
Saat ini, ada banyak bahasa dan framework menarik untuk pengembangan web sisi server. Dalam hal ini, C++ bukanlah bahasa yang paling populer, namun memiliki beberapa aset yang menarik. Memang:
Tujuan dari tutorial ini adalah untuk memberikan:
Kode sumber untuk Cutelyst disertakan di sini. Kode sumber untuk kerangka web C++ lainnya tersedia di repositori Git ini. Berbagai kerangka kerja yang digunakan dirangkum dalam lampiran. Terakhir, daftar pustaka C++ tersedia di Awesome C++.
Kami ingin mengimplementasikan aplikasi yang menampilkan gambar hewan yang disimpan di server. Formulir digunakan untuk menunjukkan awal nama hewan yang akan ditampilkan. Anda dapat menampilkan gambar dalam ukuran penuh dengan mengklik thumbnail dan Anda dapat menampilkan halaman informasi melalui link di bagian bawah halaman. Data hewan (nama dan jalur file) disimpan dalam database SQLite di server.
Di sini, pembuatan halaman HTML dilakukan di server, meskipun tren saat ini lebih menyediakan API sisi server dan menghasilkan HTML sisi klien.
Dengan cara yang sangat konvensional, seseorang dapat mengatur kode aplikasi ini menurut arsitektur tipe MVC, yaitu dengan membedakan data (model), tampilannya (view) dan manajemennya (controller).
Untuk aplikasi kami, gambar tersedia di server dan kami menggunakan database SQLite yang berisi tabel dengan nama dan jalur file hewan. File 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 ' );
...
Bagian model kemudian turun ke tipe Hewan dan fungsi getAnimals yang menanyakan database dan mengembalikan rekaman tipe Hewan yang namanya dimulai dengan awalan yang diberikan. File Hewan.hpp:
Bagian tampilan berisi dua fungsi yang mengembalikan halaman dalam format HTML: renderAbout mengembalikan halaman informasi dan renderHome mengembalikan halaman utama dengan hewan yang diminta oleh pengguna. Tampilan File.hpp:
Terakhir, bagian pengontrol mengambil peristiwa klien dan kemudian memperbarui model dan tampilan. Untuk aplikasi kita, tidak ada pemrosesan yang rumit untuk dilakukan, hanya mengambil permintaan HTTP dan memanggil fungsi sebelumnya.
C++ tampaknya tidak memiliki alat pembuatan dokumen HTML sesukses Lucid di Haskell. Pustaka CTML digunakan untuk menentukan struktur pohon dokumen dan kemudian menghasilkan kode HTML yang sesuai. Namun, sintaksisnya cukup bertele-tele dan tidak ada verifikasi tag.
Sistem ini terdiri dari penulisan templat yang dapat disesuaikan, yaitu kode HTML yang menggunakan parameter yang akan diganti dengan nilai yang ditunjukkan saat merender templat.
Kerangka kerja MVC biasanya menawarkan sistem pola tingkat lanjut, tetapi ada juga alat independen, misalnya kumis. Kumis adalah formalisme yang memiliki implementasi dalam banyak bahasa, termasuk beberapa bahasa C++. Misalnya, animal-pistache/src/View.cpp menggunakan implementasi kainjow mustache dan kode berikut ( animal-crow/src/View.cpp) implementasi framework gagak:
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 () {
...
}
Menghasilkan kode HTML secara manual juga relatif mudah, menggunakan aliran saluran C++. Namun metode ini tidak memfasilitasi penggunaan kembali kode atau verifikasi kode HTML yang dihasilkan. Contoh pembuatan manual ( animal-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 () {
...
}
Mereka memungkinkan untuk membuat kueri SQL secara eksplisit, mengirimkannya ke sistem database, dan mengambil hasilnya. Konektor SQL umumnya mudah digunakan (hanya mengetahui bahasa SQL) tetapi konektor tersebut tidak memeriksa apakah kueri sudah benar.
Banyak kerangka kerja menawarkan konektor SQL. Misalnya, cppcms (lihat animal-cppcms/src/Animal.cpp), tntnet (lihat animal-tntnet/src/Animal.cc) dan silikon (lihat animal-silicon/src/main.cpp). Ada juga konektor independen, misalnya sqlite_modern_cpp (lihat animal-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;
}
Pemetaan Relasional Objek (ORM) digunakan untuk mengubah data dari tabel di database ke kelas C++, dan sebaliknya. Hal ini memungkinkan penggunaan database dengan lebih aman karena data diperiksa oleh sistem pengetikan dan diperiksa pada waktu kompilasi karena permintaan dibuat oleh fungsi C++. Namun, ORM mendefinisikan lapisan abstraksinya sendiri yang setara dengan SQL, tetapi kurang dikenal.
Ada ORM C++ yang berbeda, misalnya wt (lihat animal-wt/src/main.cpp), sqlpp11 (lihat animal-crow/src/Animal.cpp) atau sqlite_orm (lihat animal-cpprestsdk/src/Animal.cpp):
# 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;
}
Kerangka kerja web mikro, seperti Sinatra di Ruby atau Flask di Python, bertujuan untuk menjadi sederhana dan ringan. Mereka terutama menawarkan fitur untuk menangani permintaan HTTP serta mekanisme perutean URL. Jika perlu, mereka dapat diselesaikan oleh perpustakaan lain (pembuatan HTML, akses ke database dalam SQL...).
Ada beberapa kerangka mikro C++, misalnya gagak (lihat hewan-gagak) atau silikon (lihat hewan-silikon).
Di sini, fitur C++ modern membuat kodenya ringkas dan enak dibaca.
Dalam fase pra-perawatan, Silicon menghasilkan file simbol.hh, yang mendeklarasikan simbol yang ditentukan oleh pemrogram, termasuk rute ( _about, _home, _mystatic...). Hal ini memungkinkan untuk memverifikasi secara statis bahwa rute digunakan dengan benar dalam kode. Bahasa lain menggunakan introspeksi untuk melakukan pemeriksaan semacam ini, tetapi C++ tidak memiliki fitur ini.
Kerangka kerja asinkron, seperti Node.js/Express di JavaScript, menawarkan fungsionalitas yang sama seperti kerangka mikro konvensional tetapi melalui fungsi non-pemblokiran. Jadi, jika suatu permintaan memerlukan sumber daya, aplikasi dapat beralih ke permintaan lain sambil menunggu sumber daya tersedia. Hal ini meningkatkan kinerja aplikasi secara keseluruhan tetapi memerlukan gaya pemrograman tertentu, berdasarkan janji yang terhubung ke fungsi panggilan balik pada saat itu untuk membentuk rantai pemrosesan asinkron.
Ada kerangka kerja asinkron yang berbeda di C++, misalnya cpprestsdk (lihat animal-cpprestsdk) dan pistachio (lihat animal-pistachio).
Di sini kita menemukan manajemen rute klasik (dengan nama rute dan fungsi pemrosesannya). Namun, kami sekarang memiliki operasi asinkron, melalui fungsi non-pemblokiran. Misalnya, untuk rute "statis", fungsi serveFile mengembalikan janji yang terhubung ke fungsi panggilan balik, yang menampilkan pesan log setelah janji diselesaikan.
Kerangka kerja web MVC, seperti Ruby on Rails atau Python Django adalah alat klasik yang tujuannya adalah untuk mengimplementasikan semua jenis aplikasi web. Mereka biasanya menyediakan semua fitur yang diperlukan: perutean URL, sistem templat, akses ke database, sistem otentikasi... Kerangka kerja MVC tampaknya bukan domain pilihan C++, tetapi masih ada beberapa alat menarik, termasuk cppcms dan cutelyst .
Selain fitur klasik kerangka MVC, cppcms menawarkan sistem templat yang cukup canggih dengan pewarisan tampilan dan manajemen konten. Misalnya, seseorang dapat mendefinisikan tampilan utama MasterView dan memperoleh tampilan dari AboutView dan HomeView yang mewarisi karakteristik MasterView dan melengkapinya. Terakhir, kita dapat mengaitkan konten ke tampilan ini (parameter templat), juga dengan sistem pewarisan. Dengan menggunakan contoh sebelumnya, kita dapat mendefinisikan konten MasterContent untuk tampilan MasterView, memperolehnya HomeContent untuk tampilan HomeView dan langsung menggunakan MasterContent untuk tampilan AboutView (tidak ada parameter baru di template).
Kerangka kerja MVC adalah alat yang efektif untuk mengimplementasikan aplikasi yang kompleks. Namun, mereka memerlukan banyak pelatihan dan ukurannya bisa terlalu besar untuk aplikasi kecil dan sederhana.
Kerangka kerja tntnet menawarkan sistem berbasis templat, mirip dengan PHP. Meskipun kerangka kerja ini agak bersifat anekdotal dalam ekosistem C++, pendekatannya tampaknya cukup efektif: menulis kode HTML klasik dan menambahkan bagian kode C++ jika diperlukan.
Perhatikan bahwa jenis kerangka kerja ini mungkin kurang cocok untuk pengembangan aplikasi yang kompleks (keterbacaan templat, penggunaan kembali...).
Alat-alat ini terinspirasi oleh kerangka kerja grafis desktop, seperti Qt atau gtkmm, yang didasarkan pada hierarki widget yang membentuk antarmuka dan berinteraksi melalui mekanisme slot sinyal.
Widget berbasis web ternyata tidak populer, bahkan dalam semua bahasa, meskipun potensinya tampaknya penting. Memang, mereka memungkinkan untuk mengembangkan aplikasi fullstack klien-server menggunakan perpustakaan antarmuka grafis klasik dan tanpa harus terlalu khawatir tentang arsitektur jaringan aplikasi.
Dalam C++, framework yang paling sukses dalam kategori ini tentunya adalah Wt. Wt memiliki banyak widget klasik atau lanjutan, SQL ORM, sistem otentikasi, kemampuan untuk memanipulasi HTML dan CSS, dll. Di Wt, program utamanya adalah merutekan URL ke aplikasi terkait.
Aplikasi Wt ini sesuai dengan antarmuka grafis konvensional, tetapi dengan arsitektur client-server.
Untuk aplikasi yang lebih kompleks, misalnya halaman yang menampilkan hewan, kita dapat mendefinisikan widget baru yang mengimplementasikan thumbnail, kemudian menggunakan kelas ini untuk menampilkan semua hewan yang terbaca di database.
Sekilas implementasi ini mungkin terlihat lebih panjang dan rumit dibandingkan implementasi sebelumnya. Namun, kodenya sepertinya familier bagi pengembang GUI desktop mana pun. Selain itu, implementasi ini mengelola seluruh aplikasi (fullstack), bukan bagian server saja. Misalnya, menghubungkan sinyal _myquery->textInput()
ke fungsi HomeApp::filterAnimals
melibatkan pembaruan sisi klien secara real-time, yang akan jauh lebih sulit untuk diterapkan dengan kerangka kerja sebelumnya.
Untuk mengembangkan aplikasi web back-end, C++ adalah pilihan yang sangat layak. Dengan perkembangan terkini, bahasa ini secara umum lebih sederhana dan aman untuk digunakan, tanpa mengurangi performa. Banyak pustaka C++ yang tersedia untuk pengembangan web: templat, pembuatan HTML, koneksi SQL, ORM... Kerangka kerja web juga banyak dan beragam: kerangka kerja MVC seperti RoR dan Django, kerangka kerja mikro seperti Sinatra dan Flask, kerangka kerja asinkron seperti Node.js , kerangka kerja berbasis template PHP, dan bahkan kerangka kerja fullstack berdasarkan widget. Tentu saja, semua ini terutama akan menarik minat para pengembang yang sudah mengetahui C++, karena banyak bahasa lain juga memiliki alat yang sangat menarik untuk pengembangan web.
Kerangka kerja, pustaka, dan alat berikut digunakan untuk mengimplementasikan server HTTP, pembuatan HTML, dan akses database SQL.
Proyek | Kerangka Web | Pembuat HTML | Antarmuka SQL |
---|---|---|---|
hewan-cppcms | cppcms (kerangka web) | cppcms (sistem templat) | cppcms (konektor SQL) |
hewan-cpprestsdk | cpprestsdk (kerangka jaringan asinkron) | ctml (pembuat dokumen html) | sqlite_orm (ORM) |
binatang-gagak | http: gagak (kerangka web ringan) | gagak (sistem template) | sqlpp11 (ORM) |
binatang yang paling lucu | paling lucu (kerangka web) | grantlee (sistem template) | paling lucu (konektor SQL) |
hewan-nodejs (Javascript/Node.js) | express (kerangka web ringan asinkron) | pug (pembuat dokumen) | lebih baik-sqlite3 (konektor SQL) |
binatang-pistache | pistache (kerangka web ringan asinkron) | kumis kainjow (sistem templating) | sqlite_modern_cpp (konektor SQL) |
hewan-scotty (Haskell) | scotty (kerangka web ringan) | jernih dan liat (generator dokumen) | sqlite-simple (konektor SQL) |
hewan-silikon | silikon (kerangka web ringan) | tidak ada | silikon (konektor SQL) |
hewan-tntnet | tntnet (kerangka web berbasis template) | tntnet (sistem templat) | tntnet (konektor SQL) |
hewan-wt | wt (kerangka GUI web) | wt (sistem widget + templat) | berat (ORM) |