Qt+QtWebApp開發筆記(三):http服務器動態html連接跳轉基礎交互

前言

  網頁很多時候是動態的,於是本篇文章目標實現一個簡答的動態頁面—頁靜態頁面互相跳轉,點擊可以跳轉到子頁面。

 

Demo

  在這裏插入圖片描述

下載地址

 

HTML基本頁面交換

  上一篇的“Hello World”應用程序確實輸出了簡單的純文本。但網絡的語言是HTML。因此,讓看看如何生成HTML。將輸出當前時間,並顯示列表對象中的一些數據。

創建新的請求處理

  與第一個HelloWorldController類似,創建另一個名爲ListDataController的新類。

listdatacontroller.h:

#ifndef LISTDATACONTROLLER_H
#define LISTDATACONTROLLER_H

#include <QList>
#include <QString>
#include "httprequesthandler.h"

using namespace stefanfrings;

class ListDataController: public HttpRequestHandler {
    Q_OBJECT
public:
    ListDataController(QObject* parent=0);
    void service(HttpRequest& request, HttpResponse& response);
private:
    QList<QString> list;
};

#endif // LISTDATACONTROLLER_H

listdatacontroller.cpp:

#include <QTime>
#include "listdatacontroller.h"

ListDataController::ListDataController(QObject* parent)
    : HttpRequestHandler(parent) {
    list.append("Robert");
    list.append("Lisa");
    list.append("Hannah");
    list.append("Ludwig");
    list.append("Miranda");
    list.append("Francesco");
    list.append("Kim");
    list.append("Jacko");
}

void ListDataController::service(HttpRequest &request, HttpResponse &response) {
    response.setHeader("Content-Type", "text/html; charset=UTF-8");
    response.write("<html><body>");

    response.write("The time is ");
    QString now=QTime::currentTime().toString("HH:mm:ss");
    response.write(now.toUtf8());

    response.write("<p>List of names:");
    response.write("<table border='1' cellspacing='0'>");
    for(int i=0; i<list.size(); i++) {
        QString number=QString::number(i);
        QString name=list.at(i);
        response.write("<tr><td>");
        response.write(number.toUtf8());
        response.write("</td><td>");
        response.write(name.toUtf8());
        response.write("</td></tr>");
    }
    response.write("</table>");

    response.write("</body></header>",true);
}

  構造函數用一些名稱填充列表。該服務方法輸出一個具有當前時間的HTML文檔和一個顯示列表對象內容的表。
  請注意,在編寫文檔之前設置了一個HTTP響應頭,它告訴瀏覽器使用的文件格式(請參閱Internet Media Types)和字符編碼。
  用新的控制器替換main.cpp中的控制器:

#include "listdatacontroller.h"

    new HttpListener(listenerSettings,new ListDataController(&app),&app);

  運行並測試應用程序。輸出應該是這樣的:
  在這裏插入圖片描述

請求映射器

  現在在應用程序中有兩個不同的控制器類,但一次只能使用一個。現在創建一個“RequestMapper”類,它將在兩個控制器之間切換。和以前一樣,新類再次從HttpRequestHandler繼承。

requestmapper.h:

#ifndef REQUESTMAPPER_H
#define REQUESTMAPPER_H

#include "httprequesthandler.h"

using namespace stefanfrings;

class RequestMapper : public HttpRequestHandler {
    Q_OBJECT
public:
    RequestMapper(QObject* parent=0);
    void service(HttpRequest& request, HttpResponse& response);
};

#endif // REQUESTMAPPER_H

requestmapper.cpp:

#include "requestmapper.h"
#include "helloworldcontroller.h"
#include "listdatacontroller.h"

RequestMapper::RequestMapper(QObject* parent)
    : HttpRequestHandler(parent) {
    // empty
}

void RequestMapper::service(HttpRequest& request, HttpResponse& response) {
    QByteArray path=request.getPath();
    qDebug("RequestMapper: path=%s",path.data());

    if (path=="/" || path=="/hello") {
        HelloWorldController().service(request, response);
    }
    else if (path=="/list") {
        ListDataController().service(request, response);
    }
    else {
        response.setStatus(404,"Not found");
        response.write("The URL is wrong, no such document.",true);
    }

    qDebug("RequestMapper: finished request");
}

  用新的請求映射程序替換main.cpp中的舊控制器:

#include "requestmapper.h"

    new HttpListener(listenerSettings,new RequestMapper(&app),&app);

  請求映射器根據請求的路徑調用兩個控制器中的一個。所以

  • 當打開http://localhost:8080/或http://localhost:8080/hello,會看到“Hello World”頁面。
  • 當打開http://localhost:8080/list,獲得姓名列表。

  例如,如果試圖打開任何錯誤的URLhttp://localhost:8080/lalala,然後會收到錯誤消息“URL錯誤…”以及狀態代碼404,這是“未找到”的技術值。一些程序使用它來處理錯誤。如果沒有設置狀態代碼,那麼將使用默認的200,這意味着“成功”。請參閱維基百科中的HTTP狀態代碼列表。
如果多個併發HTTP請求同時傳入,那麼service()方法將並行執行多次。所以這個方法是多線程的。當訪問在service()方法外部聲明的變量時,必須考慮這一點。
  請求映射器是“singleton”或處於“application scope”,因爲它只有一個實例。
兩個控制器類(HelloWorldController和ListDataController)位於“請求範圍”中,這意味着每個請求都由該類的新實例處理。這會降低一些性能,但會稍微簡化編程。

一個接口對一個控制器優化效率

  一個小的修改將兩個控制器類的範圍更改爲“應用程序範圍”。(PS:這個就是每次運行的時候,不是去新new)
  在這裏插入圖片描述

new requestmapper.h

#ifndef REQUESTMAPPER_H
#define REQUESTMAPPER_H

#include "httprequesthandler.h"
#include "helloworldcontroller.h"
#include "listdatacontroller.h"

using namespace stefanfrings;

class RequestMapper : public HttpRequestHandler {
    Q_OBJECT
public:
    RequestMapper(QObject* parent=0);
    void service(HttpRequest& request, HttpResponse& response);
private:
    HelloWorldController helloWorldController;
    ListDataController listDataController;
};

#endif // REQUESTMAPPER_H

new requestmapper.cpp

#include "requestmapper.h"

RequestMapper::RequestMapper(QObject* parent)
    : HttpRequestHandler(parent) {
    // empty
}

void RequestMapper::service(HttpRequest& request, HttpResponse& response) {
    QByteArray path=request.getPath();
    qDebug("RequestMapper: path=%s",path.data());

    if (path=="/" || path=="/hello") {
        helloWorldController.service(request, response);
    }
    else if (path=="/list") {
        listDataController.service(request, response);
    }
    else {
        response.setStatus(404,"Not found");
        response.write("The URL is wrong, no such document.");
    }

    qDebug("RequestMapper: finished request");
}

  現在,每個請求都只重新使用一個HelloWorldController或ListDataController實例。在啓動期間只創建一次,因爲HttpRequestMapper也只存在一次。
  使用會話後,還可以爲每個會話創建控制器實例,並將它們存儲在會話存儲中。然後就有了一個“會話範圍”。會話將在後面進行解釋。

請求映射程序項目

  按照上面得,實際上就是剛開始出一個列表,/和/hello會出現helloworld,而/list則會返回list列表,這是直接通過url後得子網頁來切換(PS:並不是通過點擊主頁面來切換,這個後面會解說到)。

Web頁面跳轉觸發

  其實這個對於做網頁得很簡單,就是一個點擊超連接,只是跳轉到內部,使用<a>來實現的。

 

Demo增量:實戰頁面跳轉

步驟一:準備代碼模板

  準備之前的demo模板:
   在這裏插入圖片描述

步驟二:新建一個主入口的消息處理

  copy原來的helloworld改成index(PS:不管又不有index,直接網站也是跳入index.html頁面)。
  在這裏插入圖片描述
  修改完類相關信息。

步驟三:網頁代碼中入口切換

  在這裏插入圖片描述

    // 啓動http的監聽
    {
        if(!_pHttpListenerSettings)
        {
            _pHttpListenerSettings = new QSettings(httpServerPath, QSettings::IniFormat);
        }
        _pHttpListenerSettings->beginGroup("listener");
//        _pHttpListener = new HttpListener(_pHttpListenerSettings, new HelloWorldRequestHandler);
        _pHttpListener = new HttpListener(_pHttpListenerSettings, new IndexRequestHandler);
    }

步驟四:寫一個簡單html跳轉頁面

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>長沙紅胖子Qt</title>
</head>
<body>
    <p>好, 長沙紅胖子 QQ:21497936 www.hpzwl.com"</p>
    <p><a href="helloworld">Hello world!</a></p>
    <p><a href="list">list</a></p>
</body>

list.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>長沙紅胖子Qt</title>
</head>
<body>
    <a href="javascript:history.back(-1);">返回上一頁</a>
    <table border="2"> 
        <tr>
            <td>row 1, cell 1</td>
            <td>row 1, cell 2</td>
        </tr>
        <tr>
            <td>row 2, cell 1</td>
            <td>row 2, cell 2</td>
        </tr>
    </table>
</body>

步驟五:修改index.html的消息處理類

  在這裏插入圖片描述

  這裏有個亂碼問題,請查看“入坑一”:

  在這裏插入圖片描述

void IndexRequestHandler::service(HttpRequest &request, HttpResponse &response)
{

    QString str;

    QString path = request.getPath();
    LOG << path;

    if(path == "/" || path == "/index")
    {
        str += "<!DOCTYPE html>"
               "<html lang=\"en\">"
               "<head>"
               "<meta charset=\"UTF-8\">"
               "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">"
               "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
               "<title>長沙紅胖子Qt</title>"
               "</head>"
               "<body>"
               "    <p>好, 長沙紅胖子 QQ:21497936 www.hpzwl.com</p>"
               "    <p><a href=\"helloworld\">Hello world!</a></p>"
               "    <p><a href=\"list\">list</a></p>"
               "</body>";
    }else if(path == "/helloworld")
    {
        helloWorldRequestHandler.service(request, response);
        return;
    }else if(path == "/list")
    {
        listRequestHandler.service(request, response);
        return;
    }else {
        response.setStatus(404,"Not found");
        str = "The URL is wrong, no such document.";
    }

    // 返回文本(需要在瀏覽器上看,所以將Qt內部編碼都轉成GBK輸出即可,不管他本身是哪個編碼)
//    QByteArray byteArray = _pTextCodec->fromUnicode(str);
    QByteArray byteArray = str.toUtf8();
    response.write(byteArray);
}

步驟六:新建一個list.html修改消息處理類

  在這裏插入圖片描述

  修改好宏類名,然後嵌入list.html頁面:
  在這裏插入圖片描述

void ListRequestHandler::service(HttpRequest &request, HttpResponse &response)
{
    QString str;

    LOG << request.getPath();

    str = "<!DOCTYPE html>"
          "<html lang=\"en\">"
          "<head>"
          "<meta charset=\"UTF-8\">"
          "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">"
          "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
          "<title>長沙紅胖子Qt</title>"
          "</head>"
          "<body>"
          "<a href=\"javascript:history.back(-1);\">返回上一頁</a>"
          "<table border=\"2\">"
          "        <tr>"
          "            <td>row 1, cell 1</td>"
          "            <td>row 1, cell 2</td>"
          "        </tr>"
          "        <tr>"
          "            <td>row 2, cell 1</td>"
          "            <td>row 2, cell 2</td>"
          "        </tr>"
          "    </table>"
          "</body>";

    // 返回文本(需要在瀏覽器上看,所以將Qt內部編碼都轉成GBK輸出即可,不管他本身是哪個編碼)
//    QByteArray byteArray = _pTextCodec->fromUnicode(str);
    QByteArray byteArray = str.toUtf8();
    response.write(byteArray);
}
 

Demo源碼

IndexRequestHandler.h

#ifndef INDEXREQUESTHANDLER_H
#define INDEXREQUESTHANDLER_H

#include "httprequesthandler.h"

#include "HelloWorldRequestHandler.h"
#include "ListRequestHandler.h"

using namespace stefanfrings;

class IndexRequestHandler : public HttpRequestHandler
{
public:
    IndexRequestHandler(QObject *parent = 0);

public:
    void service(HttpRequest& request, HttpResponse& response);

private:
    QTextCodec *_pTextCodec;

private:
    HelloWorldRequestHandler helloWorldRequestHandler;  // hellowold消息處理
    ListRequestHandler listRequestHandler;              // list消息處理

};

#endif // INDEXREQUESTHANDLER_H

IndexRequestHandler.cpp

#include "IndexRequestHandler.h"

#include "ListRequestHandler.h"

#include <QTextCodec>

#include <QDebug>
#include <QDateTime>
//#define LOG qDebug()<<__FILE__<<__LINE__
//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__
//#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread()
//#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd")
#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")

using namespace stefanfrings;

IndexRequestHandler::IndexRequestHandler(QObject *parent)
    : HttpRequestHandler(parent)
{
    // 返回文本(需要在瀏覽器上看,所以將Qt內部編碼都轉成GBK輸出即可,不管他本身是哪個編碼)
    // WINDOWS: GBK  GB2312
    // LINUX  : urf-8
//    _pTextCodec = QTextCodec::codecForName("utf-8");
    _pTextCodec = QTextCodec::codecForName("GBK");
}

void IndexRequestHandler::service(HttpRequest &request, HttpResponse &response)
{

    QString str;

    QString path = request.getPath();
    LOG << path;

    if(path == "/" || path == "/index")
    {
        str += "<!DOCTYPE html>"
               "<html lang=\"en\">"
               "<head>"
               "<meta charset=\"UTF-8\">"
               "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">"
               "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
               "<title>長沙紅胖子Qt</title>"
               "</head>"
               "<body>"
               "    <p>好, 長沙紅胖子 QQ:21497936 www.hpzwl.com</p>"
               "    <p><a href=\"helloworld\">Hello world!</a></p>"
               "    <p><a href=\"list\">list</a></p>"
               "</body>";
    }else if(path == "/helloworld")
    {
        helloWorldRequestHandler.service(request, response);
        return;
    }else if(path == "/list")
    {
        listRequestHandler.service(request, response);
        return;
    }else {
        response.setStatus(404,"Not found");
        str = "The URL is wrong, no such document.";
    }

    // 返回文本(需要在瀏覽器上看,所以將Qt內部編碼都轉成GBK輸出即可,不管他本身是哪個編碼)
//    QByteArray byteArray = _pTextCodec->fromUnicode(str);
    QByteArray byteArray = str.toUtf8();
    response.write(byteArray);
}

ListRequestHandler.h

#ifndef LISTREQUESTHANDLER_H
#define LISTREQUESTHANDLER_H

#include "httprequesthandler.h"

using namespace stefanfrings;

class ListRequestHandler : public HttpRequestHandler
{
public:
    ListRequestHandler(QObject *parent = 0);

public:
    void service(HttpRequest& request, HttpResponse& response);

private:
    QTextCodec *_pTextCodec;
};

#endif // LISTREQUESTHANDLER_H

ListRequestHandler.cpp

#include "ListRequestHandler.h"

#include <QTextCodec>

#include <QDebug>
#include <QDateTime>
//#define LOG qDebug()<<__FILE__<<__LINE__
//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__
//#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread()
//#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd")
#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")

using namespace stefanfrings;

ListRequestHandler::ListRequestHandler(QObject *parent)
    : HttpRequestHandler(parent)
{
    // 返回文本(需要在瀏覽器上看,所以將Qt內部編碼都轉成GBK輸出即可,不管他本身是哪個編碼)
    // WINDOWS: GBK  GB2312
    // LINUX  : urf-8
//    _pTextCodec = QTextCodec::codecForName("utf-8");
    _pTextCodec = QTextCodec::codecForName("GBK");
}

void ListRequestHandler::service(HttpRequest &request, HttpResponse &response)
{
    QString str;

    LOG << request.getPath();

    str = "<!DOCTYPE html>"
          "<html lang=\"en\">"
          "<head>"
          "<meta charset=\"UTF-8\">"
          "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">"
          "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
          "<title>長沙紅胖子Qt</title>"
          "</head>"
          "<body>"
          "<a href=\"javascript:history.back(-1);\">返回上一頁</a>"
          "<table border=\"2\">"
          "        <tr>"
          "            <td>row 1, cell 1</td>"
          "            <td>row 1, cell 2</td>"
          "        </tr>"
          "        <tr>"
          "            <td>row 2, cell 1</td>"
          "            <td>row 2, cell 2</td>"
          "        </tr>"
          "    </table>"
          "</body>";

    // 返回文本(需要在瀏覽器上看,所以將Qt內部編碼都轉成GBK輸出即可,不管他本身是哪個編碼)
//    QByteArray byteArray = _pTextCodec->fromUnicode(str);
    QByteArray byteArray = str.toUtf8();
    response.write(byteArray);
}
 

工程模板v1.2.0

  在這裏插入圖片描述

 

入坑

入坑一:編碼問題亂碼

問題

   亂碼
  在這裏插入圖片描述

原因

  之前的網頁沒有編碼,直接轉換的,新建的頁面有編碼,標識了utf-8,所以無需轉碼gbk了。

解決

  當表示好頁面的編碼未utf-8之後,則無需字符轉換編碼。
  在這裏插入圖片描述
  在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章