Creating a Book Store using C++ Server Pages

Tuturials

This is the first part in a series of tutorials. I'm going to explain how I've written
a book store, which is included in the sources of this project. You can see how
the book store look like right now. Here is a PHP version of the store, on which
the C++ Server Pages version is based.

The whole store is written with separation of logic and presentation. Servlets, which are doing the logic, retrieve the data from the database, process them and put then into the attributes of the request. C++ Server Pages - doing the presentation - just take the prepared values from request's attributes and display the accordingly.

First off lets start with the most simple page. That would be the Search page.
At first sight you might think it's a static page. But you would be wrong. You see, categories are defined in the database. So the first check box is generated dynamically.

Let's start with the logic. You can view the whole source of the Search.sxx servlet here. Let me explain the file part by part.

Just after the includes there's the declaration of the Search servlet class:

class Search : public HttpServlet {
protected:
    typedef std::vector<Category> categories_t;
    categories_t fetch_categories();
public:
    void doGet(HttpServletRequest& request, HttpServletResponse &response);
};

Let's have a look a the definition of the doGet(...) method:

void Search::doGet(HttpServletRequest& request, HttpServletResponse &response) {
    request.setAttribute("categories", categories_t());
    try{
        request.setAttribute("categories", fetch_categories());
    }catch(const exception& ex) {
        request.setAttribute<string>("error",ex.what());
    }
    request.getRequestDispatcher("SearchView.csp")->forward(request,response);
}

As you see the only responsibility of the doGet(...) method is to set attributes of the request and then redirect processing to the the proper view. It needs to retrieve all the categories from the database and put them in the "categories" attribute.
First, the "categories" attribute is initialized with an empty std::vector, so that the view does not need
to handle the lack of presence of the attribute. Then the attribute is overwritten with the std::vector of categories fetched from the DB. If there were any exceptions, the "error" attribute is set with an according message.
The last thing the servlet needs to do is to pass the control flow to the view. This is done using the RequestDispather class.
This is the typical behaviour of all the servlets in the store.

Now, let's take a look on how the categories are fetched from the database:

Search::categories_t Search::fetch_categories() {
    shared_ptr<MYSQL_RES> result = mysql.query("SELECT * FROM store_categories");
    MYSQL_ROW row;
    categories_t categories;
    while( (row = mysql_fetch_row(result.get())) ) {
        Category category;
        category.id=lexical_cast<long>(mysql.get(row,0));
        category.name=mysql.get(row,1);
        categories.push_back(category);
    }
    return categories;
}

As you see, this method uses the global mysql object to communicate with the database. The retrieves all the rows
from a table. Every row is converted into a Category object. All the Category object are put in a std::vector and returned by the method.
We'll look into the inner workings of the database communication in the next part of this tutorial series

Creating a Book Store using C++ Server Pages. Part II

Tuturials

In this part I'll write about database access.
The utility class I've written as a part of the book store is called Mysql and is declared in mysql.h.
It's really a very simple class. In the constructor of the class, a database connection is opened. It is later closed by the destructor.

Lets look at the Mysql::query(...) method. The first purpose of the method is to wrap MYSQL_RES pointer in boost::shared_ptr<...> so that I don't need to worry about calling mysql_free_result. The second is to throw exception when an error occurs during execution of the query.

Now, the interesting part. As you might have noticed the Mysql object instance is
created as a global variable. It's like a singleton. This way one instance of the Mysql object is created per process. And the processed are created automatically by Apache (by the prefork MPM module to be exact). Apache creates processed to serve request if the load is high and kills them when it is idle.
This way we get database connection pooling without any effort. As a bonus we get no
multithreaded programming: no mutexes, semaphores and stuff.

So when I want to use the database in a servlet, I just use the global mysql object.

原文地址:https://www.cnblogs.com/huqingyu/p/687106.html