1. 程式人生 > >C++寫動態網站之HelloWorld!

C++寫動態網站之HelloWorld!

更復雜的程式碼可參考本部落格BBS的實現

簡單的說,動態網站就是可以動態變更的網站,動態變化的內容通常來自後端資料庫,如下省略萬字(動態網站

一個個動態的網頁彙集成了一個動態網站,動態網頁在一定的模板上由後端區域性替換,使得使用者看到的內容是隨需而變,這裡我們忽略掉資料庫處理部分,直接實現網頁內容的變化,從而瞭解伺服器端的工作原理,對於你瞭解整個動態網站的工作過程很有幫助。

注意:以下過程全都在Windows 7 64上使用Visual C++ 2008 Express編譯使用,如使用不同的環境或工具,請高手自行搞定微笑

靜態頁


動態頁



開始使用

IDE

在Visual C++ Express 2008下開啟專案方案,

fetch_platform\build\vc2008\fetch_platform.sln,按如下圖所示配置


網站埠

網站程式的入口在檔案HTTPFormServer.cpp,下面是網站的埠,通常為80埠,為了避免可能的埠衝突,這裡使用8020,網站程式執行起來可以使用,

當然如果你電腦上的80埠沒有被其他程式佔用,可以簡單的使用進行訪問

            unsigned short port = 8020;
			if (args.size() > 0) // change default port
				port = (unsigned short) NumberParser::parse(args[0]);


後端

新增服務類

新增一個頭檔案DemoService.h

#ifndef DEMO_SERVICE_H
#define DEMO_SERVICE_H

#include "shared_service.h"

class DemoService : public SharedService
{
public:
    void handle(Poco::Net::HTTPServerRequest& req, Poco::Net::HTTPServerResponse& resp,
        Poco::URI& uri, const std::string& fileName);

public:
    static const std::string SERVICE_PREFIX; // 用於URL分發
    
private:
};

#endif // DEMO_SERVICE_H

實現檔案DemoService.cpp
#include "demo_service.h"

const std::string DemoService::SERVICE_PREFIX        = "/demo/";

// 凡是位址列顯示如下的都會進入下面這個方法
// http://domain/demo/***
//
void DemoService::handle(Poco::Net::HTTPServerRequest& req, Poco::Net::HTTPServerResponse& resp, 
    Poco::URI & uri, const std::string& fileName)
{
    // 分類處理demo下不同的請求,然後return
    //
    // 否則,如果沒有特別的處理,將直接呼叫父類的handle方法
    
    // 作為示例,這裡沒有對DemoService進行擴充,感興趣可以下載BBS的原始碼
    // 因此這裡直接交由父類處理
    //
    SharedService::handle(req, resp, uri, fileName);
}

WebServer是如何將瀏覽器的請求轉發到DemoService的

答案就在ServiceDispatcher類,具體如下

    // demo service
    if (startsWith(fileName, DemoService::SERVICE_PREFIX))
    {
        DemoService demo;
        demo.handle(req, resp, uri, fileName);
        return;
    }


新增標籤類

標籤類負責動態替換模板裡的內容,這裡的標籤最重要的部分就是標籤名,必須保證唯一性

標籤類必須與.jsp前端網頁配合使用才能實現動態顯示網頁的效果

標頭檔案

#ifndef DEMO_TAG_H
#define DEMO_TAG_H

#include "Poco/Net/base_tag.h"

class DemoTag : public Poco::Net::BaseTag
    /// Generates the number of the last hit shown on this page.
{
public:
    DemoTag();
    ~DemoTag();

#ifndef USING_STENCIL_SERIALIZE
    virtual void printEndTag(Poco::Net::PageRequest* req, Poco::Net::PageResponse* resp);
        /// Called when the parser reaches the end tag.
        ///  
        /// @param request The page request.
        /// @param response The page response.
        /// @throws Exception If there was an exception.
#endif
};

#endif // DEMO_TAG_H
實現部分
#include "demo_tag.h"


DemoTag::DemoTag()
{
#if !defined(_DEBUG) || defined(USING_STENCIL_SERIALIZE)
	_type = DEMO_TAG;
#endif
}

DemoTag::~DemoTag()
{
}

#ifndef USING_STENCIL_SERIALIZE
void DemoTag::printEndTag(Poco::Net::PageRequest* req, Poco::Net::PageResponse* resp)
{
    std::string type = getParameter("type");

    // 這裡根據不同的type返回不同的字串給瀏覽器
    // 實現動態網頁的效果
    if (type == "chinese")
    {
        resp->print("你好,世界!");
    }
    else
        resp->print("Hello World!");
}
#endif

必須將該標籤類進行註冊後,WebServer才會認識

見BaseTagManager類

void BaseTagManager::registerAllTags()
{
	BaseTagFactory& tagFactory = BaseTagFactory::defaultFactory();
	tagFactory.registerTagClass("demo",                 new Instantiator<DemoTag, BaseTag>);
    
/*
 * The following will be used to create new object while loading from file
 */
#if !defined(_DEBUG) || defined(USING_STENCIL_SERIALIZE)

	tagFactory.registerTagClass(DEMO_TAG,             new Instantiator<DemoTag, BaseTag>);

#endif // NDEBUG || USING_SERIALIZE_TAG
}

至此當有來自瀏覽器的請求時,WebServer就可以實現動態輸出網頁了

前端

新建jsp檔案

前端的資源全部放在root資料夾下,WebServer操作網頁的根目錄就在此。

在root資料夾下,我們新建一個demo的資料夾,再新建一個.jsp的檔案,jsp副檔名用來告訴WebServer當前請求的是一個動態網頁

當然你也可以使用任意其他的副檔名,如果想使用其他的副檔名,你需要修改SharedService::handle方法的如下部分

    if (file.exists() && file.isFile())
    {
        if (endsWith(newFileName, std::string(".jsp"))) // 以jsp結尾的檔案表示動態網頁
        {
#ifdef _DEBUG
            Poco::Net::Executer* root = _parser.parse(FETCH_WWWROOT, Path(newFileName).toString());
#else

新增標籤

在後端程式碼部分,我們已經新增過標籤處理類,這裡需要新增前端部分,只有這兩邊對應起來,一個真正的動態網頁才能正常工作

index.jsp

<fetch:demo/>
<br>
<fetch:demo type="chinese"/>

標籤說明

<fetch:demo/>,fetch沒有實際作用但不能省略,可用來搜尋標籤,關鍵部分在於demo,這個是與後端的

tagFactory.registerTagClass("demo",                 new Instantiator<DemoTag, BaseTag>);
想對應的,如果你想自己新建個別的標籤,完全參照demo這個做即可

<br>,是個標準HTML標籤,表示換行

<fetch:demo type="chinese"/>,跟第一行比,多了type="chinese",這裡你也可以改成其他的,但形式必須保證一致,比如你可以改成value="english",那麼對應後端的DemoTag部分中的

std::string type = getParameter("type");
則需要改成
std::string value = getParameter("value");

小結

雖然連圖加上程式碼佔據了不少篇幅,實際上只需要如下3個步驟即可實現一個簡單的動態網站

  1. 新增Service類,並在ServiceDispatcher中根據檔名分發
  2. 新增Tag類,並在BaseTagManager中註冊
  3. 新增jsp網頁,注意與Tag類配合

如果你有精力,也可以研究一下其他程式碼,不過大部分時間你幾乎不用關心或改變它們