在Qt中使用QtWebApp搭建HTTP服務(wù)器的詳細(xì)步驟
前言
最近在開發(fā)Qt的http服務(wù)器功能,研究比較了一番,選擇了QtWebApp方案,相對其他開源庫,比較推薦使用該方案,功能齊全,簡單易用,如果趕項(xiàng)目的話,極力推薦。
下面介紹一下Qt集成QtWebApp步驟:
一、Qt集成QtWebApp步驟:
1、下載QtWebApp源碼:KingJamesGyq/QtWebApp把源碼拉下來到本地,將httpsever目錄整個(gè)移植到自己的項(xiàng)目工程下。



2、在pro文件包含httpserver
include ($$PWD/httpserver/httpserver.pri)
這樣就完成集成源碼了,剩下的就是根據(jù)你自己的業(yè)務(wù)需求去開發(fā)了,細(xì)節(jié)可以參考Demo1和Demo2。
二、在Qt中使用QtWebApp搭建HTTP服務(wù)器
第一步 下載QtWebApp導(dǎo)入工程中
工程示例:

第二步 編寫配置文件WebApp.ini
host=192.168.255.128 ;服務(wù)ip地址 port=8080 ;端口號(hào) minThreads=4 ;4個(gè)線程始終保持運(yùn)行狀態(tài) maxThreads=100 ;并發(fā)工作線程的最大數(shù)量 cleanupInterval=60000 readTimeout=60000 maxRequestSize=16000 maxMultiPartSize=10000000
第三步 加載配置文件,創(chuàng)建HTTP偵聽器對象
main.cpp
#include "httplistener.h"
#include "httprequesthandler.h"
#include "RequestMapper.h" //自定義類請求映射器類
QSettings* listenerSettings=
new QSettings(QCoreApplication::applicationDirPath()+"/WebApp.ini",QSettings::IniFormat);
new stefanfrings::HttpListener(listenerSettings, new RequestMapper());
第四步 自定義類請求映射器類
RequestMapper.h
#ifndef REQUESTMAPPER_H
#define REQUESTMAPPER_H
#include "httprequesthandler.h"
using namespace stefanfrings;
#include "HelloController.h"
class RequestMapper:public HttpRequestHandler
{
public:
RequestMapper();
void service(HttpRequest& request, HttpResponse& response);
private:
HelloController m_helloController;
};
#endif // REQUESTMAPPER_H
RequestMapper.cpp
#include "RequestMapper.h"
#include "json.hpp"
#include <string>
using namespace std;
using namespace nlohmann;
RequestMapper::RequestMapper()
{
}
void RequestMapper::service(HttpRequest &request, HttpResponse &response)
{
QByteArray path=request.getPath();
QByteArray method = request.getMethod();
QByteArray nm = request.getParameter("nm");
qDebug() << "RequestMapper: path=" << path.data();
qDebug() << "RequestMapper: method=" << method.data();
qDebug() << "RequestMapper: nm=" << nm.data();
if ( path=="/hello") {
m_helloController.service(request,response);
}
}
第五步 自定義業(yè)務(wù)請求處理類
HelloController .h
#ifndef HELLOCONTROLLER_H
#define HELLOCONTROLLER_H
#include <QObject>
#include "httprequesthandler.h"
using namespace stefanfrings;
#include "json.hpp"
using namespace nlohmann;
#include <string>
using namespace std;
class HelloController : public QObject
{
Q_OBJECT
public:
explicit HelloController(QObject *parent = 0);
void service(HttpRequest& request, HttpResponse& response);
signals:
public slots:
};
#endif // HELLOCONTROLLER_H
HelloController.cpp
#include "HelloController.h"
HelloController::HelloController(QObject *parent) : QObject(parent)
{
}
void HelloController::service(HttpRequest &request, HttpResponse &response)
{
QByteArray body = request.getBody();
qDebug() << body;
json res;
res["code"] = 200;
res["mesage"] = "success";
string str = res.dump(4);
// response.setStatus(404);
response.write(str.c_str());
}
第六步 測試
服務(wù)運(yùn)行示例

瀏覽器發(fā)請求示例

另外:其他的映射和控制器寫法:
requestmapper.h
#ifndef REQUESTMAPPER_H
#define REQUESTMAPPER_H
#include "QtWebApp/httpserver/httprequesthandler.h"
using namespace stefanfrings;
/*
The request mapper dispatches incoming HTTP requests to controller classes
depending on the requested path.
*/
class RequestMapper : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(RequestMapper)
public:
/*
Constructor.
@param parent Parent object
*/
RequestMapper(QObject* parent=0);
/*
Destructor.
*/
~RequestMapper();
/*
Dispatch incoming HTTP requests to different controllers depending on the URL.
@param request The received HTTP request
@param response Must be used to return the response
*/
void service(HttpRequest& request, HttpResponse& response);
// 攔截未授權(quán)操作
bool preHandle(HttpRequest& request, HttpResponse& response);
};
#endif // REQUESTMAPPER_H
requestmapper.cpp
#include "requestmapper.h"
#include "global.h"
#include "controller/logincontroller.h"
#include "controller/funcvercodecontroller.h"
#include "controller/sysmsgcontroller.h"
#include "controller/sysusercontroller.h"
#include "controller/commoncontroller.h"
#include "controller/sysmenucontroller.h"
#include "controller/sysdiccontroller.h"
#include "controller/sysrolecontroller.h"
#include "controller/sysdeptcontroller.h"
#include "controller/syslogcontroller.h"
#include "controller/funcmonitorcontroller.h"
#include "controller/sysusermsgcontroller.h"
#include "controller/funcsmscontroller.h"
#include "controller/funcemailcontroller.h"
#include "controller/funcloadcontroller.h"
#include "controller/funcexportcontroller.h"
#include<qthread.h>
RequestMapper::RequestMapper(QObject* parent)
:HttpRequestHandler(parent)
{
qDebug("RequestMapper: created");
qDebug()<<".................RequestMapper created......................currentThreadId():"<<QThread::currentThreadId();
}
RequestMapper::~RequestMapper()
{
qDebug("RequestMapper: deleted");
}
void RequestMapper::service(HttpRequest& request, HttpResponse& response)
{
qDebug()<<"..............RequestMapper::service..................currentThreadId():"<<QThread::currentThreadId();
QByteArray path = request.getPath().toLower();
QString tmp = QString(path);
qDebug("RequestMapper::service e");
//實(shí)現(xiàn)跨域訪問,js 調(diào)用API 提供了支持。
response.setHeader("Connection", "keep-alive");
auto origin = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "X-PINGOTHER,Content-Type,x-token,access_token");
response.setHeader("Access-Control-Max-Age", "86400");
response.setHeader("Vary", "Accept-Encoding,Origin");
response.setHeader("Keep-Alive", "timeout=2,max=99");
response.setHeader("Access-Control-Allow-Credentials", "true");
//set api header
response.setHeader("Content-Type", "application/json; charset=utf-8");
//response.setHeader("Access-Control-Allow-Origin", "*"); // also important , if not set , the html application wont run.
if (request.getMethod() == "OPTIONS")
{
response.setStatus(200,"OK");
qDebug("RequestMapper: finished request");
// Clear the log buffer
return;
}
//攔截部分,做token校驗(yàn)
if (path.startsWith("/func")
|| path.startsWith("/sys")
|| path.startsWith("/monitor/"))
{
if(!preHandle(request, response))
return;
}
if (path.startsWith("/login") || path.startsWith("/logout"))
{
LoginController().service(request, response);
}
else if (path.startsWith("/vercode"))
{
FuncVercodeController().service(request, response);
}
else if (path.startsWith("/func/message/user/"))
{
SysUserMsgController().service(request, response);
}
else if (path.startsWith("/func/message/sys/"))
{
SysMsgController().service(request, response);
}
else if (path.startsWith("/sys/user/"))
{
SysUserController().service(request, response);
}
else if (path.startsWith("/sys/menu/"))
{
SysMenuController().service(request, response);
}
else if (path.startsWith("/sys/dic/"))
{
SysDicController().service(request, response);
}
else if (path.startsWith("/sys/role/"))
{
SysRoleController().service(request, response);
}
else if (path.startsWith("/sys/dept/"))
{
SysDeptController().service(request, response);
}
else if (path.startsWith("/sys/log/"))
{
SysLogController().service(request, response);
}
else if (path.startsWith("/func/sms/"))
{
FuncSmsController().service(request, response);
}
else if (path.startsWith("/sys/email/"))
{
FuncEmailController().service(request, response);
}
else if (path.startsWith("/func/upload/"))
{
FuncLoadController().service(request, response);
}
else if (path.startsWith("/func/export/"))
{
FuncExportController().service(request, response);
}
else if (path.startsWith("/monitor"))
{
FuncMonitorController().service(request, response);
}
else if (path.startsWith("/common"))
{
CommonController().service(request, response);
}
else
{
staticFileController->service(request, response);
}
qDebug("RequestMapper: finished request");
// Clear the log buffer
if (logger)
{
// logger->clear();
}
}
// 攔截未授權(quán)操作
bool RequestMapper::preHandle(HttpRequest& request, HttpResponse& response)
{
// token校驗(yàn)不通過,返回1001
ResultJson result(1001, false, QStringLiteral("token已失效"));
QString accessToken = request.getHeader("access_token");
if(accessToken == NULL || accessToken.isEmpty())
accessToken = request.getParameter("access_token");
if(accessToken == NULL || accessToken.isEmpty())
{
result.failedMsg(QStringLiteral("找不到token"));
ResponseUtil::replyJson(response, result);
//staticFileController->service(request, response);
return false;
}
//根據(jù)token登錄
QString username = JwtUtil::getUsername(accessToken);
if(username == NULL || username.isEmpty())
{
ResponseUtil::replyJson(response, result);
//staticFileController->service(request, response);
return false;
}
//判斷token是否有效
QString token_key = username + "_token";
QString saveToken = CacheApi::instance()->get(token_key);
if(saveToken != accessToken)
{
ResponseUtil::replyJson(response, result);
//staticFileController->service(request, response);
return false;
}
//刷新token
CacheApi::instance()->insert(token_key, accessToken, JwtUtil::EXPIRED_TIME);
return true;
}
logincontroller.h
#ifndef LOGINCONTROLLER_H
#define LOGINCONTROLLER_H
#include "global.h"
#include <QMap>
using namespace stefanfrings;
class LoginController: public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(LoginController)
public:
LoginController();
void service(HttpRequest& request, HttpResponse& response);
void login(HttpRequest& request, HttpResponse& response); //登錄
void logout(HttpRequest& request, HttpResponse& response); //退出
private:
SqlHelper* m_pHelper;
typedef void (LoginController::*pServFunc)(HttpRequest& request, HttpResponse& response);
QMap<QString, pServFunc> m_mapFunc;
};
#endif // LOGINCONTROLLER_H
logincontroller.cpp
#include "logincontroller.h"
#include <QCryptographicHash>
#include <qthread.h>
LoginController::LoginController()
{
qDebug()<<"....................LoginController........................currentThreadId():"<<QThread::currentThreadId();
// m_pHelper = SqlHelper::instance();
m_pHelper = new SqlHelper();
m_pHelper->initDB("QtWebAdmin.db");
m_mapFunc.insert("/login", &LoginController::login); //登錄
m_mapFunc.insert("/logout", &LoginController::logout); //登出
}
void LoginController::service(HttpRequest& request, HttpResponse& response)
{
qDebug()<<"...................LoginController::service........................currentThreadId():"<<QThread::currentThreadId();
QByteArray path = request.getPath().toLower();
if(m_mapFunc.contains(path))
{
pServFunc func = m_mapFunc.value(path);
(this->*func)(request, response);
}
}
void LoginController::login(HttpRequest& request, HttpResponse& response)
{
qDebug()<<"..................LoginController::login...................currentThreadId():"<<QThread::currentThreadId();
ResultJson ret(0, true, QStringLiteral("登入成功"));
QString body = request.getBody();
QString username = request.getParameter("username");
QString password = request.getParameter("password");
QString vercode = request.getParameter("vercode");
QString access_token = request.getParameter("access_token");
QString codeid = request.getParameter("codeid");
HttpSession session = sessionStore->getSession(request, response, true);
if(username.isEmpty())
{
ret.failedMsg(QStringLiteral("用戶名為空"));
response.write(ret.toString().toLocal8Bit());
return;
}
if(password.isEmpty())
{
ret.failedMsg(QStringLiteral("密碼為空"));
response.write(ret.toString().toLocal8Bit());
return;
}
if(vercode.isEmpty())
{
ret.failedMsg(QStringLiteral("驗(yàn)證碼為空"));
response.write(ret.toString().toLocal8Bit());
return;
}
//
// if(!session.contains("vercode"))
// {
// ret.failedMsg(QStringLiteral("未找到驗(yàn)證碼"));
// response.write(ret.toString().toLocal8Bit());
// return;
// }
//跨域情況下,以網(wǎng)頁請求時(shí)附帶UUID,作為驗(yàn)證碼標(biāo)志
QString sessionCode = CacheApi::instance()->get(codeid + "_vercode");
if(sessionCode.isNull())
{
ret.failedMsg(QStringLiteral("未找到驗(yàn)證碼或驗(yàn)證碼已過期"));
response.write(ret.toString().toLocal8Bit());
return;
}
//QString sessionCode = session.get("vercode").toString();
if(sessionCode.toLower() != vercode.toLower())
{
ret.failedMsg(QStringLiteral("驗(yàn)證碼不匹配"));
response.write(ret.toString().toLocal8Bit());
return;
}
//................檢查密碼
SysUser loginUser;
if(!m_pHelper->selectUserByName(loginUser, username))
{
ret.failedMsg(QStringLiteral("未找到用戶或密碼不正確!"));
response.write(ret.toString().toLocal8Bit());
return;
}
SysLog log("system", SysLog::LOGIN, QStringLiteral("用戶登錄"),
username,
QString(__FILE__),
QString(__FUNCTION__),
GlobalFunc::JsonToString(request.getParameterJson()),
request.getPeerAddress().toString(),
request.getHeader("User-Agent"),
QStringLiteral("用戶成功登錄"));
QString pwdAndSalt = password + loginUser.getSalt();
QString md5Pwd = QString(QCryptographicHash::hash(pwdAndSalt.toLocal8Bit(), QCryptographicHash::Md5).toHex());
if(md5Pwd != loginUser.getPassword())
{
ret.failedMsg(QStringLiteral("密碼不正確!"));
response.write(ret.toString().toLocal8Bit());
log.setMemo(QStringLiteral("密碼不正確!"));
m_pHelper->insertEntity(&log);
return;
}
//JWT獲取,并存入緩存
QString accessToken = JwtUtil::sign(username, password);
CacheApi::instance()->insert(username + "_token", accessToken, JwtUtil::EXPIRED_TIME);
//session保存賬戶名和登錄時(shí)間
session.set("username", username);
session.set("logintime", QTime::currentTime());
//返回token
ret.setData("access_token", accessToken);
ResponseUtil::replyJson(response, ret);
m_pHelper->insertEntity(&log);
}
// /logout?access_token=?
void LoginController::logout(HttpRequest& request, HttpResponse& response)
{
QString access_token = request.getParameter("access_token");
QString username = JwtUtil::getUsername(access_token);
CacheApi::instance()->remove(username + "_token");
QJsonObject objParam = request.getParameterJson();
objParam.insert("access_token", "?");
// ResponseUtil::replyJson(response, ResultJson(0, true, QStringLiteral("操作成功")));
SysLog log("system", SysLog::LOGOUT, QStringLiteral("用戶退出"),
username,
QString(__FILE__),
QString(__FUNCTION__),
GlobalFunc::JsonToString(objParam),
request.getPeerAddress().toString(),
request.getHeader("User-Agent"),
QStringLiteral("用戶退出成功"));
m_pHelper->insertEntity(&log);
}總結(jié)
到此這篇關(guān)于在Qt中使用QtWebApp搭建HTTP服務(wù)器的文章就介紹到這了,更多相關(guān)Qt QtWebApp搭建HTTP服務(wù)器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
用C語言來實(shí)現(xiàn)一個(gè)簡單的虛擬機(jī)
這篇文章主要介紹了用C語言來實(shí)現(xiàn)一個(gè)簡單的虛擬機(jī),其中棧數(shù)組的部分非常值得學(xué)習(xí),需要的朋友可以參考下2015-07-07
C++詳細(xì)講解圖論的基礎(chǔ)與圖的儲(chǔ)存
圖論〔Graph?Theory〕是數(shù)學(xué)的一個(gè)分支。它以圖為研究對象。圖論中的圖是由若干給定的點(diǎn)及連接兩點(diǎn)的線所構(gòu)成的圖形,這種圖形通常用來描述某些事物之間的某種特定關(guān)系,用點(diǎn)代表事物,用連接兩點(diǎn)的線表示相應(yīng)兩個(gè)事物間具有這種關(guān)系2022-05-05

