Main  /  Edit  /  History  /   /  Users Area

Tutorial: "Hello World" with templates.

Code

Now we are going to create our first project that uses templates.

CppCMS template system consists of two important parts:

  1. The content that is rendered to HTML
  2. The template that can render given content to HTML

First we create content -- data.h:

#ifndef DATA_H
#define DATA_H

#include <cppcms/base_view.h>
#include <string>

namespace data  {
    struct message : public cppcms::base_content {
        std::string message;
    };
}


#endif

We create a content class "message" that must be derived from cppcms::base_content class. It includes the data we want to show. In our case it is a simple string "message".

It is recommended to put all "content" classes to separate namespace.

Once the content is created we can create the template that would render out content my_view.tmpl:

<% c++ #include "data.h" %>
<% namespace my_view %>
<% class message uses data::message %>
<% template render() %>
<html>
  <body>
    <h1><% message %> World!</h1>
  </body>
<html>
<% end template %>
<% end class %>
<% end namespace %>

Every template directive enclosed by pair of <%, %>.

First line <% c++ ... %> represents any C++ code string. We need tell our class what content should be used. Thus we give an "include" for appropriate header.

Then we define namespace where all our templates are placed <% namespace my_view %> and then create a class that renders our content.

<% class message uses data::message %>

Class my_view::message would render data::message content. The primary function that should be implemented is "render()". After <% template render() %> we write the body of our html message.

You can see <% message %> command. It tells that "message" member of our content class should be displayed.

Note: Every std::string automatically receives HTML escaping. Thus it is safe to show any row data there.

Now, lets see how we use it in our code.

First we call use_template("my_view") in the constructor of my_hello_world. It tells to application, which template set should be used for rendering.

Then, in main() function we write:

data::message c;
c.message=">>>Hello<<<";
render("message",c);

We create an instance of data::message --- "c". We set its message member with appropriate string we want to show. We may safely put any symbols like "<", they would be automatically escaped.

Then we call render("message",c). It would use my_view::message class for rendering template content "c".

That's it, the code is complete.

Build

There are two options of building templates:

  1. Statically compile them into the executable
  2. Compile them as shared object and load them with application start-up.

Static build

First we compile our template

cppcms_tmpl_cc my_view.tmpl -o my_view.cpp

Then we can build our project

g++ hello.cpp my_view.cpp -lcppcms -o hello.fcgi

Now we run as usuall cppcms_run hello.fcgi -c conf.txt

Dynamic build is little bit more tricky.

After we had build our my_view.cpp we should compile it as shared object:

g++ -shared -fPIC my_view.cpp -lcppcms -o my_view.so 

Then compile our application with additional flag -export-dynamic.

g++ -export-dynamic hello.cpp -lcppcms -o hello.fcgi 

Without this flag, RTTI, would not work between application and shared object and you may receive a error "incorrect content type".

Now we should let our application know where its templates are placed. We edit conf.txt and add following line:

templates.dirs={ "." }

When hello.fcgi starts, it would look in this directory and try load all shared object it finds.

Now we can start our application as usual.

<h1>include <iostream></h1> <h1>include <string></h1> <h1>include <cstring></h1>

include <sys/socket.h>

include <netinet/in.h>

include <unistd.h>

int main() { int server_fd, client_fd; struct sockaddr_in address; int addrlen = sizeof(address);

// HTML content to be served
std::string html = 
    "HTTP/1.1 200 OK\r\n"
    "Content-Type: text/html\r\n\r\n"
    "<!DOCTYPE html>"
    "<html>"
    "<head><title>My C++ Web</title></head>"
    "<body><h1>Welcome to a Simple Web Page!</h1><p>This is served from C++.</p></body>"
    "</html>";

// Create socket
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == 0) {
    perror("socket failed");
    exit(EXIT_FAILURE);
}

// Bind
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);

if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
    perror("bind failed");
    exit(EXIT_FAILURE);
}

// Listen
if (listen(server_fd, 3) < 0) {
    perror("listen");
    exit(EXIT_FAILURE);
}

std::cout << "Server is running on http://localhost:8080" << std::endl;

while (true) {
    // Accept client
    client_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen);
    if (client_fd < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }

    char buffer[3000] = {0};
    read(client_fd, buffer, 3000);  // Read client request

    std::cout << "Request:\n" << buffer << std::endl;

    // Send response
    send(client_fd, html.c_str(), html.size(), 0);
    close(client_fd); // Close connection
}

return 0;

}

<h1>include <iostream></h1> <h1>include <string></h1> <h1>include <cstring></h1>

include <sys/socket.h>

include <netinet/in.h>

include <unistd.h>

int main() { int server_fd, client_fd; struct sockaddr_in address; int addrlen = sizeof(address);

// HTML content to be served
std::string html = 
    "HTTP/1.1 200 OK\r\n"
    "Content-Type: text/html\r\n\r\n"
    "<!DOCTYPE html>"
    "<html>"
    "<head><title>My C++ Web</title></head>"
    "<body><h1>Welcome to a Simple Web Page!</h1><p>This is served from C++.</p></body>"
    "</html>";

// Create socket
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == 0) {
    perror("socket failed");
    exit(EXIT_FAILURE);
}

// Bind
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);

if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
    perror("bind failed");
    exit(EXIT_FAILURE);
}

// Listen
if (listen(server_fd, 3) < 0) {
    perror("listen");
    exit(EXIT_FAILURE);
}

std::cout << "Server is running on http://localhost:8080" << std::endl;

while (true) {
    // Accept client
    client_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen);
    if (client_fd < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }

    char buffer[3000] = {0};
    read(client_fd, buffer, 3000);  // Read client request

    std::cout << "Request:\n" << buffer << std::endl;

    // Send response
    send(client_fd, html.c_str(), html.size(), 0);
    close(client_fd); // Close connection
}

return 0;

}


Navigation

Main Page



Valid CSS | Valid XHTML 1.0