이 애플리케이션과 튜토리얼은 LinuxFr.org에 게시된 Quelques cadriciels Web C++ 기사의 예제를 기반으로 합니다.
현재 서버측 웹 개발을 위한 흥미로운 언어와 프레임워크가 많이 있습니다. 이 분야에서 C++는 가장 유행하는 언어는 아니지만 몇 가지 흥미로운 자산을 가지고 있습니다. 물론:
이 튜토리얼의 목적은 다음을 제공하는 것입니다.
Cutelyst의 소스 코드가 여기에 포함되어 있습니다. 다른 C++ 웹 프레임워크의 소스 코드는 이 Git 저장소에서 사용할 수 있습니다. 사용된 다양한 프레임워크는 부록에 요약되어 있습니다. 마지막으로 Awesome C++에서 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 유형과 데이터베이스를 쿼리하고 이름이 주어진 접두사로 시작하는 Animal 유형 레코드를 반환하는 getAnimals 함수로 내려갑니다. 파일 Animal.hpp:
보기 부분에는 HTML 형식의 페이지를 반환하는 두 가지 함수가 포함되어 있습니다. renderAbout은 정보 페이지를 반환하고 renderHome은 사용자가 요청한 동물이 포함된 기본 페이지를 반환합니다. 파일 보기.hpp:
마지막으로 컨트롤러 부분은 클라이언트의 이벤트를 검색한 다음 모델과 뷰를 업데이트합니다. 우리 애플리케이션의 경우 수행해야 할 복잡한 처리가 없으며 단지 HTTP 요청을 검색하고 이전 기능을 호출하는 것뿐입니다.
C++에는 Haskell의 Lucid만큼 성공적인 HTML 문서 생성 도구가 없는 것 같습니다. CTML 라이브러리는 문서의 트리 구조를 정의한 다음 해당 HTML 코드를 생성하는 데 사용됩니다. 그러나 구문이 매우 장황하며 태그 확인이 없습니다.
이러한 시스템은 사용자 정의 가능한 템플릿 작성, 즉 템플릿을 렌더링할 때 표시된 값으로 대체되는 매개변수가 사용되는 HTML 코드로 구성됩니다.
MVC 프레임워크는 일반적으로 고급 패턴 시스템을 제공하지만 콧수염과 같은 독립적인 도구도 있습니다. 콧수염은 C++의 여러 언어를 포함하여 다양한 언어로 구현된 형식입니다. 예를 들어, Animal-pistache/src/View.cpp는 kainjow 콧수염 구현을 사용하고 다음 코드(animal-crow/src/View.cpp)는 까마귀 프레임워크 구현을 사용합니다.
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 코드의 코드 재사용이나 확인을 용이하게 하지 않습니다. 수동 생성의 예(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 () {
...
}
이를 통해 명시적으로 SQL 쿼리를 작성하고 이를 데이터베이스 시스템으로 보내고 결과를 검색할 수 있습니다. SQL 커넥터는 일반적으로 사용하기 쉽지만(SQL 언어만 알면 됨) 쿼리가 올바른지 확인하지 않습니다.
많은 프레임워크에서 SQL 커넥터를 제공합니다. 예를 들어 cppcms(animals-cppcms/src/Animal.cpp 참조), tntnet(animal-tntnet/src/Animal.cc 참조) 및 Silicon(animal-silicon/src/main.cpp 참조)입니다. sqlite_modern_cpp와 같은 독립적인 커넥터도 있습니다(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;
}
ORM(객체 관계형 매핑)은 데이터베이스 테이블의 데이터를 C++ 클래스로 또는 그 반대로 변환하는 데 사용됩니다. 이렇게 하면 C++ 함수로 요청하기 때문에 타이핑 시스템으로 데이터를 확인하고 컴파일 타임에 확인하므로 데이터베이스를 보다 안전하게 사용할 수 있습니다. 그러나 ORM은 SQL과 동일하지만 덜 알려진 자체 추상화 계층을 정의합니다.
다양한 C++ ORM이 있습니다. 예를 들어 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;
}
Ruby의 Sinatra나 Python의 Flask와 같은 마이크로 웹 프레임워크는 단순하고 가벼운 것을 목표로 합니다. 주로 HTTP 요청과 URL 라우팅 메커니즘을 처리하는 기능을 제공합니다. 필요한 경우 다른 라이브러리(HTML 생성, SQL의 데이터베이스 액세스...)를 통해 완료할 수 있습니다.
까마귀(동물-까마귀 참조) 또는 실리콘(동물-실리콘 참조)과 같은 여러 C++ 마이크로 프레임워크가 있습니다.
여기서 최신 C++의 기능은 코드를 간결하고 읽기 쉽게 만듭니다.
전처리 단계에서 Silicon은 경로(_about, _home, _mystatic...)를 포함하여 프로그래머가 정의한 기호를 선언하는 기호.hh 파일을 생성합니다. 이를 통해 경로가 코드에서 올바르게 사용되는지 정적으로 확인할 수 있습니다. 다른 언어에서는 이러한 검사를 수행하기 위해 인트로스펙션(introspection)을 사용하지만 C++에는 이 기능이 없습니다.
JavaScript의 Node.js/Express와 같은 비동기 프레임워크는 기존 마이크로 프레임워크와 동일한 기능을 제공하지만 비차단 기능을 통해 제공됩니다. 따라서 요청에 리소스가 필요한 경우 애플리케이션은 리소스를 사용할 수 있을 때까지 기다리는 동안 다른 요청으로 전환할 수 있습니다. 이는 애플리케이션의 전반적인 성능을 향상시키지만 비동기 처리 체인을 형성하기 위해 콜백 함수에 연결된 약속을 기반으로 하는 특정 프로그래밍 스타일이 필요합니다.
C++에는 cpprestsdk(animal-cpprestsdk 참조) 및 pistachio(animal-pistachio 참조)와 같은 다양한 비동기 프레임워크가 있습니다.
여기서는 경로의 고전적인 관리(경로 이름과 처리 기능 포함)를 찾을 수 있습니다. 그러나 이제 비차단 기능을 통해 비동기 작업이 가능해졌습니다. 예를 들어, "정적" 경로의 경우serveFile 함수는 콜백 함수에 연결된 Promise를 반환합니다. 이 함수는 Promise가 해결되면 로그 메시지를 표시합니다.
Ruby on Rails 또는 Python Django와 같은 MVC 웹 프레임워크는 모든 유형의 웹 애플리케이션을 구현하는 것을 목표로 하는 고전적인 도구입니다. 일반적으로 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과 같은 데스크탑 그래픽 프레임워크, 즉 인터페이스를 구성하고 신호 슬롯 메커니즘을 통해 상호 작용하는 위젯의 계층 구조를 기반으로 하는 데스크탑 그래픽 프레임워크에서 영감을 받았습니다.
웹 기반 위젯은 놀랍게도 모든 언어에서조차 인기가 없지만 그 잠재력은 중요해 보입니다. 실제로, 전통적인 그래픽 인터페이스 라이브러리를 사용하고 애플리케이션의 네트워크 아키텍처에 대해 너무 많이 걱정할 필요 없이 클라이언트-서버 풀스택 애플리케이션을 개발할 수 있습니다.
C++에서 이 범주의 가장 성공적인 프레임워크는 확실히 Wt입니다. Wt에는 많은 클래식 또는 고급 위젯, SQL ORM, 인증 시스템, HTML 및 CSS 조작 기능 등이 있습니다. Wt에서 기본 프로그램은 URL을 해당 애플리케이션으로 라우팅하는 것입니다.
이러한 Wt 애플리케이션은 기존 그래픽 인터페이스에 해당하지만 클라이언트-서버 아키텍처를 사용합니다.
예를 들어 동물을 표시하는 페이지와 같은 보다 복잡한 애플리케이션의 경우 썸네일을 구현하는 새 위젯을 정의한 다음 이 클래스를 사용하여 데이터베이스에서 읽은 모든 동물을 표시할 수 있습니다.
언뜻 보기에 이 구현은 이전 구현보다 더 길고 복잡해 보일 수 있습니다. 그러나 해당 코드는 모든 데스크탑 GUI 개발자에게 친숙해 보일 것입니다. 또한 이 구현에서는 서버 부분만이 아닌 전체 애플리케이션(풀스택)을 관리합니다. 예를 들어 _myquery->textInput()
신호를 HomeApp::filterAnimals
함수에 연결하려면 실시간 클라이언트 측 업데이트가 필요하며, 이는 이전 프레임워크로 구현하기가 훨씬 더 어렵습니다.
백엔드 웹 애플리케이션을 개발하려면 C++가 매우 적합한 옵션입니다. 최신 개발을 통해 언어는 일반적으로 성능 저하 없이 사용하기가 더 간단하고 안전합니다. 템플릿, HTML 생성, SQL 연결, ORM 등 많은 C++ 라이브러리를 웹 개발에 사용할 수 있습니다. 웹 프레임워크도 많고 다양합니다. RoR 및 Django와 같은 MVC 프레임워크, Sinatra 및 Flask와 같은 마이크로 프레임워크, Node.js와 같은 비동기 프레임워크 , PHP 템플릿 기반 프레임워크, 심지어 위젯 기반 풀스택 프레임워크도 있습니다. 물론 이 모든 것은 이미 C++를 알고 있는 개발자의 관심을 끌 것입니다. 왜냐하면 다른 많은 언어에도 웹 개발을 위한 매우 흥미로운 도구가 있기 때문입니다.
HTTP 서버, HTML 생성 및 SQL 데이터베이스 액세스를 구현하는 데 사용되는 다음 프레임워크, 라이브러리 및 도구입니다.
프로젝트 | 웹 프레임워크 | HTML 생성기 | SQL 인터페이스 |
---|---|---|---|
동물-cppcms | cppcms(웹 프레임워크) | cppcms(템플릿 시스템) | cppcms(SQL 커넥터) |
동물-cpprestsdk | cpprestsdk(비동기 네트워킹 프레임워크) | ctml(html 문서 생성기) | sqlite_orm(ORM) |
동물 까마귀 | http: Crow(경량 웹 프레임워크) | 까마귀(템플릿 시스템) | sqlpp11(ORM) |
동물들 - 귀엽게 | Cutelyst (웹 프레임워크) | Grantlee(템플릿 시스템) | Cutelyst(SQL 커넥터) |
동물-nodejs(Javascript/Node.js) | Express(비동기 경량 웹 프레임워크) | 퍼그(문서 생성기) | better-sqlite3(SQL 커넥터) |
동물 - 피스타치 | pistache(비동기 경량 웹 프레임워크) | Kainjow 콧수염 (템플릿 시스템) | sqlite_modern_cpp(SQL 커넥터) |
동물 스코티(Haskell) | Scotty(경량 웹 프레임워크) | 루시드 및 클레이(문서 생성기) | sqlite-simple(SQL 커넥터) |
동물 실리콘 | Silicon(경량 웹 프레임워크) | 없음 | 실리콘(SQL 커넥터) |
동물-tntnet | tntnet (템플릿 기반 웹 프레임워크) | tntnet(템플릿 시스템) | tntnet(SQL 커넥터) |
동물 무게 | wt(웹 GUI 프레임워크) | wt(위젯 시스템 + 템플릿) | 중량(ORM) |