Qt+QtWebApp开发笔记(三):http服务器动态html连接跳转基础交互

博客园   2023-05-24 12:59:52

前言

网页很多时候是动态的,于是本篇文章目标实现一个简答的动态页面—页静态页面互相跳转,点击可以跳转到子页面。

Demo下载地址

链接:https://pan.baidu.com/s/1bbhcu1XTiaJRYGRQRG5a0g?pwd=1234

HTML基本页面交换

上一篇的“Hello World”应用程序确实输出了简单的纯文本。但网络的语言是HTML。因此,让看看如何生成HTML。将输出当前时间,并显示列表对象中的一些数据。


【资料图】

创建新的请求处理

与第一个HelloWorldController类似,创建另一个名为ListDataController的新类。

listdatacontroller.h:
#ifndef LISTDATACONTROLLER_H#define LISTDATACONTROLLER_H#include #include #include "httprequesthandler.h"using namespace stefanfrings;class ListDataController: public HttpRequestHandler {    Q_OBJECTpublic:    ListDataController(QObject* parent=0);    void service(HttpRequest& request, HttpResponse& response);private:    QList list;};#endif // LISTDATACONTROLLER_H
listdatacontroller.cpp:
#include #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("");    response.write("The time is ");    QString now=QTime::currentTime().toString("HH:mm:ss");    response.write(now.toUtf8());    response.write("

List of names:"); response.write("

"); for(int i=0; i"); } response.write("
"); response.write(number.toUtf8()); response.write(""); response.write(name.toUtf8()); response.write("
"); response.write("",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_OBJECTpublic:    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_OBJECTpublic:    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页面跳转触发

其实这个对于做网页得很简单,就是一个点击超连接,只是跳转到内部,使用来实现的。

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
                长沙红胖子Qt    

好, 长沙红胖子 QQ:21497936 www.hpzwl.com"

Hello world!

list

list.html
                长沙红胖子Qt    返回上一页    
row 1, cell 1 row 1, cell 2
row 2, cell 1 row 2, cell 2
步骤五:修改index.html的消息处理类

这里有个乱码问题,请查看“入坑一”:

void IndexRequestHandler::service(HttpRequest &request, HttpResponse &response){    QString str;    QString path = request.getPath();    LOG << path;    if(path == "/" || path == "/index")    {        str += ""               ""               ""               ""               ""               ""               "长沙红胖子Qt"               ""               ""               "    

好, 长沙红胖子 QQ:21497936 www.hpzwl.com

" "

Hello world!

" "

list

" ""; }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 = ""          ""          ""          ""          ""          ""          "长沙红胖子Qt"          ""          ""          "返回上一页"          ""          "        "          "            "          "            "          "        "          "        "          "            "          "            "          "        "          "    
row 1, cell 1row 1, cell 2
row 2, cell 1row 2, cell 2
" ""; // 返回文本(需要在浏览器上看,所以将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 #include #include //#define LOG qDebug()<<__FILE__<<__LINE__//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__//#define LOG qDebug()<<__FILE__<<__LINE__<"               ""               ""               ""               ""               "长沙红胖子Qt"               ""               ""               "    

好, 长沙红胖子 QQ:21497936 www.hpzwl.com

" "

Hello world!

" "

list

" ""; }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 #include #include //#define LOG qDebug()<<__FILE__<<__LINE__//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__//#define LOG qDebug()<<__FILE__<<__LINE__<"          ""          ""          ""          ""          "长沙红胖子Qt"          ""          ""          "返回上一页"          ""          "        "          "            "          "            "          "        "          "        "          "            "          "            "          "        "          "    
row 1, cell 1row 1, cell 2
row 2, cell 1row 2, cell 2
" ""; // 返回文本(需要在浏览器上看,所以将Qt内部编码都转成GBK输出即可,不管他本身是哪个编码)// QByteArray byteArray = _pTextCodec->fromUnicode(str); QByteArray byteArray = str.toUtf8(); response.write(byteArray);}
工程模板v1.2.0入坑入坑一:编码问题乱码问题

乱码  

原因

之前的网页没有编码,直接转换的,新建的页面有编码,标识了utf-8,所以无需转码gbk了。

解决

当表示好页面的编码未utf-8之后,则无需字符转换编码。    

最新资讯