前言

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

 

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之后,则无需字符转换编码。
  
  

Qt+QtWebApp开发笔记(三):http服务器动态html连接跳转基础交互的更多相关文章

  1. Django开发笔记三

    Django开发笔记一 Django开发笔记二 Django开发笔记三 Django开发笔记四 Django开发笔记五 Django开发笔记六 1.基于类的方式重写登录:views.py: from ...

  2. Qt+ECharts开发笔记(四):ECharts的饼图介绍、基础使用和Qt封装百分比图Demo

    前言   前一篇介绍了横向柱图图.本篇将介绍基础饼图使用,并将其封装一层Qt.  本篇的demo使用隐藏js代码的方式,实现了一个饼图的基本交互方式,并预留了Qt模块对外的基础接口.   Demo演示 ...

  3. 【大型软件开发】浅谈大型Qt软件开发(三)QtActive Server如何通过COM口传递自定义结构体?如何通过一个COM口来获得所有COM接口?

    前言 最近我们项目部的核心产品正在进行重构,然后又是年底了,除了开发工作之外项目并不紧急,加上加班时间混不够了....所以就忙里偷闲把整个项目的开发思路聊一下,以供参考. 鉴于接下来的一年我要进行这个 ...

  4. Qt+ECharts开发笔记(三):ECharts的柱状图介绍、基础使用和Qt封装Demo

    前言   上一篇成功是EChart随着Qt窗口变化而变化,本篇将开始正式介绍柱状图介绍.基础使用,并将其封装一层Qt.  本篇的demo实现了隐藏js代码的方式,实现了一个条形图的基本交互方式,即Qt ...

  5. Qt+ECharts开发笔记(二):Qt窗口动态调整大小,使ECharts跟随Qt窗口大小变换而变换大小

    前言   上一篇将ECharts嵌入Qt中,在开始ECharts使用之前,还有一个很重要的功能,就是在窗口变换大小的时候,ECharts的图表尺寸也要跟随Qt窗口变换大小而变换大小.   Demo演示 ...

  6. Qt+ECharts开发笔记(五):ECharts的动态排序柱状图介绍、基础使用和Qt封装Demo

    前言   上一篇的demo使用隐藏js代码的方式,实现了一个饼图的基本交互方式,并预留了Qt模块对外的基础接口.  本篇的demo实现了自动排序的柱状图,实现了一个自动排序柱状图的基本交互方式,即Qt ...

  7. Qt+MySql开发笔记:Qt5.9.3的msvc2017x64版本编译MySql8.0.16版本驱动并Demo连接数据库测试

    前言   mysql驱动版本msvc2015x32版本调好, mysql的mingw32版本的驱动上一个版本编译并测试好,有些三方库最低支持vs2017,所以只能使用msvc2017x64,基于Qt5 ...

  8. RBL开发笔记三

    2014-08-26 20:06:24 今天就是在开发这个EPOLL来处理网络事件 封装较为健壮的EPOLL模型来处理基本的网络IO 1) 超时这个主题先没有弄 在开发EPOLL包括select/po ...

  9. odoo开发笔记 -- 应用服务器&数据库服务器分开部署

    app+db在一台服务器: odoo.conf配置文件: db_host = False db_maxconn = 64 db_name = False db_password = 123456db_ ...

  10. 钉钉开发笔记(三)MySQL的配置

    最近在编写web的过程中,经常需要与后台工作人员互动.由于比较麻烦.没有效率. 就果断的请教了,公司的后台大牛,学习下数据库的一些简单操作,现在就把利用MySQL连接服务器, 进行可视化操作的简单步骤 ...

随机推荐

  1. 【数据结构与算法学习】散列表(Hash Table,哈希表)

    实现语言:C++ 1. 散列表 散列表,英文名称为Hash Table,又称哈希表.杂凑表等. 线性表和树表的查找是通过比较关键字的方法,查找的效率取决于关键字的比较次数. 而散列表是根据关键字直接访 ...

  2. 基于Pierre Dellacherie的俄罗斯方块-05Pierre Dellacherie算法

    基于Pierre Dellacherie的俄罗斯方块-05Pierre Dellacherie算法 Pierre Dellacherie算法感觉上像是一个遍历算法,给与各个参数不同的权重,使得更加合理 ...

  3. windows 系统下 workerman 在同一个运行窗口中开启多个 websocket 服务

    目录 开启多个 ws 服务失败 开启服务失败解决办法 同一个窗口中运行 开启多个 ws 服务失败 正常情况下,如果你想开启多个 websocket 服务的话 只要在一个文件中,输入 new Worke ...

  4. 【深入浅出 Yarn 架构与实现】5-1 Yarn 资源调度器基本框架

    资源调度器是 YARN 中最核心的组件之一,它是 ResourceManager 中的一个插拔式服务组件,负责整个集群资源的管理和分配. Yarn 默认提供了三种可用资源调度器,分别是FIFO (Fi ...

  5. Linux耳机音响独立输出

    记得之前在用Ubuntu系统的时候,耳机和音响(线缆输出和模拟耳机输出)只能单独插一个,如果两个设备同时插入主机,将会导致只能耳机输出,即使选择后置音响(线缆输出)也不会有声音.在Windows下,即 ...

  6. 基于开源的 ChatGPT Web UI 项目,快速构建属于自己的 ChatGPT 站点

    作为一个技术博主,了不起比较喜欢各种折腾,之前给大家介绍过 ChatGPT 接入微信,钉钉和知识星球(如果没看过的可以翻翻前面的文章),最近再看开源项目的时候,发现了一个 ChatGPT Web UI ...

  7. MINIO搭建单机以及集群

    MINIO简介 Minio是Apache License v2.0下发布的对象存储服务器.它与Amazon S3云存储服务兼容.它最适合存储非结构化数据,如照片,视频,日志文件,备份和容器/VM映像. ...

  8. [数据库]Oracle数据迁移至HIVE(待续)

    step1 导出csv数据,并 call sql_to_csv('select * from BE_JJZKJCQKTJ', 'OUT_PATH', 'DA.BE_JJZKJCQKTJ.csv'); ...

  9. [Maven]探究settings.xml

    1 settings.xml的配置模块 1-1 localRepository The path to the local repository maven will use to store art ...

  10. 机器学习(四):4层BP神经网络(只用numpy不调包)用于训练鸢尾花数据集|准确率96%

    题目: 设计四层BP网络,以g(x)=sigmoid(x)为激活函数, 神经网络结构为:[4,10,6, 3],其中,输入层为4个节点,第一个隐含层神经元个数为10个节点:第二个隐含层神经元个数为6个 ...