Это приложение и руководство основаны на примере из статьи Quelques cadriciels Web C++, опубликованной на LinuxFr.org.
В настоящее время существует множество интересных языков и фреймворков для серверной веб-разработки. В этой области C++ — не самый модный язык, но у него есть несколько интересных преимуществ. Действительно:
Цель этого руководства — предоставить:
Исходные коды Cutelyst включены здесь. Исходные коды других веб-платформ C++ доступны в этом репозитории 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 ' );
...
Затем модельная часть сводится к типу Animal и функции getAnimals, которая запрашивает базу данных и возвращает записи типа Animal, имя которых начинается с заданного префикса. Файл Animal.hpp:
Часть представления содержит две функции, возвращающие страницы в формате HTML: renderAbout возвращает информационную страницу, а renderHome возвращает главную страницу с запрошенными пользователем животными. Файл View.hpp:
Наконец, часть контроллера извлекает события клиента, а затем обновляет модель и представление. Для нашего приложения не требуется выполнять сложную обработку, достаточно просто получить HTTP-запросы и вызвать предыдущие функции.
C++, похоже, не имеет таких успешных инструментов создания HTML-документов, как Lucid в Haskell. Библиотека CTML используется для определения древовидной структуры документа и последующего создания соответствующего HTML-кода. Однако его синтаксис довольно многословен и проверка тегов не осуществляется.
Эти системы состоят из написания настраиваемых шаблонов, то есть HTML-кода, в котором используются параметры, которые будут заменены значениями, указанными при рендеринге шаблона.
Фреймворки MVC обычно предлагают расширенные системы шаблонов, но существуют и независимые инструменты, например усы. Mustache — это формализм, реализация которого реализована на многих языках, в том числе на C++. Например, Animal-pistache/src/View.cpp использует реализацию усов kainjow, а следующий код ( 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 () {
...
}
Также относительно просто генерировать HTML-код вручную, используя потоки каналов C++. Однако этот метод не облегчает повторное использование кода или проверку созданного 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 (см. животные-cppcms/src/Animal.cpp), tntnet (см. животные-tntnet/src/Animal.cc) и кремний (см. животные-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, но обязательно менее известный.
Существуют разные ORM C++, например wt (см. животные-wt/src/main.cpp), sqlpp11 (см. животные-crow/src/Animal.cpp) или sqlite_orm (см. животные-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;
}
Микровеб-фреймворки, такие как Sinatra в Ruby или Flask в Python, стремятся быть простыми и легкими. В основном они предлагают функции для обработки HTTP-запросов, а также механизм маршрутизации URL-адресов. При необходимости их можно дополнить другими библиотеками (генерация HTML, доступ к базе данных в SQL...).
Существует несколько микрофреймворков C++, например Crow (см. Animals-Crow) или Silicon (см. Animals-Silicon).
Здесь особенности современного C++ делают код лаконичным и довольно приятным для чтения.
На этапе предварительной обработки Silicon генерирует файл символов.hh, в котором объявляются символы, определенные программистом, включая маршруты ( _about, _home, _mystatic...). Это дает возможность статически проверить правильность использования маршрутов в коде. Другие языки для выполнения такого рода проверки используют интроспекцию, но в C++ такой возможности нет.
Асинхронные фреймворки, такие как Node.js/Express в JavaScript, предлагают те же функциональные возможности, что и обычные микрофреймворки, но с помощью неблокирующих функций. Таким образом, если запросу требуется ресурс, приложение может переключиться на другой запрос, ожидая доступности ресурса. Это повышает общую производительность приложения, но требует определенного стиля программирования, основанного на обещаниях, связанных с функциями обратного вызова, чтобы к тому времени сформировать цепочку асинхронной обработки.
В C++ существуют различные асинхронные фреймворки, например cpprestsdk (см. животные-cpprestsdk) и фисташка (см. животные-фисташки).
Здесь мы находим классическое управление маршрутом (с названием маршрута и функцией его обработки). Однако теперь у нас есть асинхронная работа с помощью неблокирующих функций. Например, для «статического» маршрута функция «servFile» возвращает обещание, связанное с функцией обратного вызова, которая отображает сообщение журнала после выполнения обещания.
Веб-фреймворки MVC, такие как Ruby on Rails или Python Django, — это классические инструменты, целью которых является реализация веб-приложений любого типа. Обычно они предоставляют все необходимые функции: маршрутизацию URL-адресов, систему шаблонов, доступ к базам данных, систему аутентификации... Фреймворки MVC, похоже, не являются предпочтительной областью C++, но все же есть несколько интересных инструментов, включая cppcms amd cutelyst. .
В дополнение к классическим функциям платформы MVC, cppcms предлагает довольно продвинутую систему шаблонов с наследованием представлений и управлением контентом. Например, можно определить основное представление MasterView и получать из него представления. AboutView и HomeView наследуют характеристики MasterView и дополняют их. Наконец, мы можем связать контент с этими представлениями (параметрами шаблонов), также с помощью системы наследования. Используя предыдущий пример, мы можем определить контент MasterContent для представления MasterView, вывести его из HomeContent для представления HomeView и напрямую использовать MasterContent для представления AboutView (в шаблоне нет нового параметра).
Фреймворки MVC — эффективные инструменты для реализации сложных приложений. Однако они требуют тщательного обучения и могут иметь слишком большие размеры для небольших и простых приложений.
Платформа tntnet предлагает систему на основе шаблонов, аналогичную PHP. Даже если этот фреймворк является довольно анекдотическим в экосистеме C++, он кажется довольно эффективным в своем подходе: писать классический HTML-код и добавлять разделы кода C++ там, где это необходимо.
Обратите внимание, что этот тип структуры, возможно, менее подходит для разработки сложных приложений (читаемость шаблонов, повторное использование...).
Эти инструменты созданы на основе графических фреймворков настольных компьютеров, таких как Qt или gtkmm, то есть основаны на иерархии виджетов, составляющих интерфейс и взаимодействующих через механизм сигнальных слотов.
Веб-виджеты на удивление непопулярны даже на всех языках, хотя их потенциал кажется важным. Действительно, они позволяют разрабатывать полностековое клиент-серверное приложение, используя классическую библиотеку графического интерфейса и не слишком беспокоясь о сетевой архитектуре приложения.
В C++ наиболее успешной средой в этой категории, безусловно, является Wt. Wt имеет множество классических или расширенных виджетов, SQL ORM, систему аутентификации, возможность манипулировать HTML и CSS и т. д. В Wt основная программа — маршрутизация URL-адресов в соответствующие приложения.
Эти Wt-приложения соответствуют обычным графическим интерфейсам, но имеют клиент-серверную архитектуру.
Для более сложного приложения, например страницы, отображающей животных, мы можем определить новый виджет, реализующий миниатюру, а затем использовать этот класс для отображения всех животных, считанных в базе данных.
На первый взгляд эта реализация может показаться более длинной и сложной, чем предыдущие реализации. Однако его код должен показаться знакомым любому разработчику графического интерфейса для настольных компьютеров. Кроме того, эта реализация управляет всем приложением (fullstack), а не только серверной частью. Например, подключение сигнала _myquery->textInput()
к функции HomeApp::filterAnimals
включает обновления на стороне клиента в реальном времени, что было бы гораздо сложнее реализовать с помощью предыдущих платформ.
Для разработки серверных веб-приложений C++ является очень подходящим вариантом. Благодаря последним разработкам этот язык в целом стал проще и безопаснее в использовании без ущерба для производительности. Для веб-разработки доступно множество библиотек C++: шаблоны, генерация HTML, SQL-соединение, ORM... Веб-фреймворки также многочисленны и разнообразны: фреймворки MVC, такие как RoR и Django, микрофреймворки, такие как Sinatra и Flask, асинхронные фреймворки, такие как Node.js. , фреймворки на основе шаблонов PHP и даже полнофункциональные фреймворки на основе виджетов. Конечно, все это в первую очередь заинтересует разработчиков, уже знающих C++, ведь многие другие языки также имеют очень интересные инструменты для веб-разработки.
Следующие платформы, библиотеки и инструменты используются для реализации HTTP-сервера, генерации HTML и доступа к базе данных SQL.
Проект | Веб-фреймворк | HTML-генератор | SQL-интерфейс |
---|---|---|---|
животные-cppcms | cppcms (веб-фреймворк) | cppcms (система шаблонов) | cppcms (коннектор SQL) |
животные-cpprestsdk | cpprestsdk (инфраструктура асинхронной сети) | ctml (генератор HTML-документов) | sqlite_orm (ОРМ) |
животные-вороны | http: crow (облегченный веб-фреймворк) | ворона (система шаблонов) | sqlpp11 (ОРМ) |
животные-милашки | cutelyst (веб-фреймворк) | получатель гранта (система шаблонов) | cutelyst (коннектор SQL) |
животные-nodejs (Javascript/Node.js) | экспресс (асинхронный облегченный веб-фреймворк) | мопс (генератор документов) | лучше-sqlite3 (коннектор SQL) |
животные-фисташки | фисташ (асинхронный облегченный веб-фреймворк) | усы кайнджоу (система шаблонов) | sqlite_modern_cpp (коннектор SQL) |
животные-Скотти (Haskell) | Скотти (легкий веб-фреймворк) | lucid и пластилин (генераторы документов) | sqlite-simple (коннектор SQL) |
животные-кремний | кремний (легкий веб-фреймворк) | никто | кремний (разъем SQL) |
животные-tntnet | tntnet (веб-фреймворк на основе шаблонов) | tntnet (система шаблонов) | tntnet (коннектор SQL) |
животные-вес | wt (фреймворк веб-интерфейса) | wt (система виджетов + шаблоны) | вес (ОРМ) |