该文章用图例+代码方式演示了,一个线上软件基本框架(精简)。开发工具Qt+VS2015
一. 基本要素
这里会用简单的图例和完整代码(这里以Qt代码为例),说明一个线上软件基本的框架。
一个线上windows软件,一般分为几个大的部分
1 UI模块
负责处理来自业务逻辑层或者其它模块的数据展示
2 网络模块
A http、https请求 B websocket(该文章不做赘述) 封装post或get请求,处理请求返回、超时等
3 业务逻辑模块
这里主要处理的是网络模块返回数据的处理,并把结果通知UI模块
4 中间层
负责关联网络模块和业务逻辑模块
5 独立模块(守护进程、更新模块、日志收集模块…)
该文章不做赘述
这里UI模块并非纯UI,其中也有业务逻辑处理。 UI模块和业务逻辑模块 可以做成更低耦合,但是会有降低效率的代价
二. 图例部分
这里用精简代码演示了 1 从用户操作UI(调用UIMainWnd::sendAsk()) 2 发送网络请求(Network::_post(),Network::_get()) 3 到请求结果返回(Network::requestFinished()) 4 对返回数据处理(BusinessLogicManager::onAskAction()) 5 通知UI模块显示(UIMainWnd::on_ask_action())
三. 代码部分
这里使用精简Qt代码演示
1 配置文件模块
#pragma once
/*********************************************************************
*@file ConfigDef.h
*@brief 管理枚举enum、定义define、QString...
*@author
*@date
*********************************************************************/
///@ 网路请求消息结构
typedef struct _tagNetMessage
{
QString _type; // 类型
int _flag; // 标识
QString _url; // 接口Url
QString _method; // 请求方式
QByteArray _byte; // 参数
}NetMessage;
// 请求接口
/// @brief 发送聊天消息
#define API_POST_ASK_ACTION "http://www.xxxx.com/tztv/ask_action.php"
// 请求类型标识
/// @brief 消息类型(用来在发送和接收网络请求时,区分是哪种消息类型)
namespace RequestType {
#define REQUEST_TYPE_ASK_ACTION "ask_action" // 直播间发送文本消息
};
2 UI模块
// 头文件
/*********************************************************************
*@file UIMainWnd.h
*@brief 交互界面
*@author
*@date
*********************************************************************/
#pragma once
#include
class UIMainWnd : public QWidget
{
Q_OBJECT
public:
UIMainWnd(QWidget *parent = Q_NULLPTR);
~UIMainWnd();
private Q_SLOTS:
// 文本消息(网络请求返回处理)
void on_ask_action(bool, const QString&, int _error_code = 0);
private:
void initUI();
// 发送文本消息(网络请求)
void sendText(const QString&_text);
};
// 源文件
UIMainWnd::UIMainWnd(QWidget *parent)
: QWidget(parent)
{
initUI();
}
UIMainWnd::~UIMainWnd()
{
}
void UIMainWnd::initUI()
{
connect(BridgeManager::instance().businessIns(), &BusinessLogicManager::sigAskAction, this, &UIDiscuss::on_ask_action);
}
/**
* 发送文本消息
*/
void UIMainWnd::sendText(const QString&_text)
{
QByteArray data;
data.append("channel=" + DataMgr::instance().getLocalUserInfo()._user_group);
std::string str = Utils::_urlencode(_text.toStdString());
QString msg_param = QString::fromStdString(str);
data.append("&message=" + msg_param);
data.append("&client_type=client");
NetMessage msg;
msg._type = REQUEST_TYPE_ASK_ACTION;
msg._flag = rt_ask_action;
msg._url = API_POST_ASK_ACTION;
msg._method = "post";
msg._byte = data;
BridgeManager::instance().businessIns()->networkRequest(msg);
}
// 文本消息
void UIMainWnd::on_ask_action(bool bsuccess, const QString&_content, int _error_code)
{
// 处理来自业务逻辑层的消息
if (bsuccess)
{
}
else
{
}
}
2 网络模块
分为网络模块和网络管理模块,以及超时处理,cookie处理 1)网络模块和超时处理
/*********************************************************************
*@file Network.h
*@brief 网络模块封装
*@author
*@date
*********************************************************************/
#pragma once
#include
#include
#include
class Network : public QObject
{
Q_OBJECT
public:
Network(QObject *parent);
~Network();
void _get(const QUrl& _url);
void _post(const QUrl& _url, const QByteArray& _bytes);
void _setType(const QString& _type,); // 设置该请求的类型RequestType
void _setCookieJar(QNetworkCookieJar *cookieJar); //设置cookie
Q_SIGNALS:
// 网络模块->通知网络管理层
/// 网络请求返回数据
void sigReply(const QString &_type_net, const QByteArray &_byte_array);
/// 网络请求失败
void sigReplyError(const QString &_type_net, const int &_error_code, const QString &_error_string);
/// 网络请求超时
void sigTimeout(const QString& _type_net);
private Q_SLOTS:
// 对于网络请求返回的处理一般有三种情况:返回成功,返回失败,请求超时
void requestFinished(QNetworkReply* _reply); // 网络请求返回处理(返回成功、返回失败)
void on_timeout(); // 超时处理
private:
QString m_netType = tr(""); // 配置模块中RequestType
QNetworkRequest m_httpRequest;
QNetworkAccessManager m_networkAccessManager;
};
// 超时处理
class QReplyTimeout : public QObject
{
Q_OBJECT
public:
QReplyTimeout(QNetworkReply *reply, const int timeout);
signals:
void sigTimeout();
private slots:
void on_timeout();
};
#include "Network.h"
Network::Network(QObject *parent)
: QObject(parent)
{
QMetaObject::Connection connRet = QObject::connect(&m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
Q_ASSERT(connRet);
}
Network::~Network()
{
m_networkAccessManager.disconnect();
}
void Network::_setType(const QString& _type)
{
m_netType = _type;
}
void Network::_setCookieJar(QNetworkCookieJar *cookieJar)
{
m_networkAccessManager.setCookieJar(cookieJar);
}
void Network::_get(const QUrl& _url)
{
m_httpRequest.setUrl(_url);
QNetworkReply *_reply = m_networkAccessManager.get(m_httpRequest);
// 请求超时
QReplyTimeout *pTimeout = new QReplyTimeout(_reply, 5000);
connect(pTimeout, &QReplyTimeout::sigTimeout, this, &Network::on_timeout);
}
void Network::_post(const QUrl& _url, const QByteArray& _bytes)
{
QNetworkRequest _request;
_request.setUrl(_url);
QNetworkReply *_reply = m_networkAccessManager.post(_request, _bytes);
// 请求超时
QReplyTimeout *pTimeout = new QReplyTimeout(_reply, 5000);
connect(pTimeout, &QReplyTimeout::sigTimeout, this, &Network::on_timeout);
}
void Network::requestFinished(QNetworkReply* _reply)
{
if (_reply->error() == QNetworkReply::NoError)
{// request success
QByteArray _byteArray = _reply->readAll();
// 这里是日志,方便在日志文件中查看。关于日志生成的看后续文章
QString _str_error = QString("%1 : request_reply_source_data = %2").arg(m_netType).arg(QString(_byteArray));
LINFO(L"%s", _str_error.toStdWString().c_str());
emit sigReply(m_netType, _byteArray);
}
else
{// request fail
int _error_code = _reply->error();
QString _log_error = QString("%1 : request_reply_network_error_code = %2").arg(m_netType).arg(QString::number(_error_code));
LINFO(L"%s", _log_error.toStdWString().c_str());
QString _error_str = _reply->errorString();
emit sigReplyError(m_netType, _error_code, _error_str);
}
_reply->deleteLater();
}
void Network::on_timeout()
{// request timeout
QNetworkReply* _reply = (QNetworkReply*)sender();
int _error_code = _reply->error();
QString _log_error = QString("%1 : request_reply_timeout = %2").arg(m_netType).arg(QString::number(_error_code));
LINFO(L"%s", _log_error.toStdWString().c_str());
emit sigTimeout(m_netType);
}
QReplyTimeout::QReplyTimeout(QNetworkReply *reply, const int timeout)
: QObject(reply)
{
Q_ASSERT(reply);
if (reply && reply->isRunning()) { // 启动单次定时器
QTimer::singleShot(timeout, this, SLOT(on_timeout()));
}
}
void QReplyTimeout::on_timeout()
{ // 处理超时
QNetworkReply *reply = static_cast
if (reply->isRunning()) {
reply->abort();
reply->deleteLater();
emit sigTimeout();
}
}
2)网络管理模块
#pragma once
/*********************************************************************
*@file NetWorkManager.h
*@brief 网络管理层(接收来自业务层请求,把请求结果返回业务层,通过中间层关联)
*@author
*@date
*********************************************************************/
#include
class NetworkManager : public QObject
{
Q_OBJECT
public:
NetworkManager(QObject *parent);
~NetworkManager();
Q_SIGNALS:
/// @网络层->业务层(网络层通知业务层)
void sigReply(const QString& _type, const QByteArray& _byte_array);
void sigReplyError(const QString &_type_net, const int &_error_code, const QString &_error_string);
void sigTimeout(const QString& _type_net);
public Q_SLOTS:
/// @来自业务层的请求
void on_net_request_activated(NetMessage &);
};
#include "NetworkManager.h"
#include "Network.h"
#include "NetworkCookie.h"
#include
NetworkManager::NetworkManager(QObject *parent)
: QObject(parent)
{
//gu_networkManager->activeConfiguration();
}
NetworkManager::~NetworkManager()
{
}
void NetworkManager::on_net_request_activated(NetMessage &_msg)
{
Network *_network = new Network(this);
// 通知业务层
connect(_network, &Network::sigReply, [this](const QString &_type_net, const QByteArray &_byte_array) {
emit sigReply(_type_net, _byte_array);
});
connect(_network, &Network::sigReplyError, [this](const QString &_type_net, const int &_error_code, const QString &_error_string) {
emit sigReplyError(_type_net, _error_code, _error_string);
});
connect(_network, &Network::sigTimeout, [this](const QString& _type) {
emit sigTimeout(_type);
});
_network->_setType(_msg._type);
_network->_setCookieJar(&NetworkCookie::instance());
// 请求方式
if (_msg._method == "post")
{
_network->_post(_msg._url, _msg._byte);
}
else if (_msg._method == "get")
{
_network->_get(QUrl(_msg._url));
}
}
3)cookie处理
#pragma once
/*********************************************************************
*@file NetworkCookie.h
*@brief cookie
*@author
*@date
*********************************************************************/
#include
#include
#include
class NetworkCookie : public QNetworkCookieJar
{
Q_OBJECT
public:
static NetworkCookie& instance();
QList
void setCookies(const QList
private:
NetworkCookie(QObject *parent);
~NetworkCookie();
};
#include "NetworkCookie.h"
NetworkCookie::NetworkCookie(QObject *parent)
: QNetworkCookieJar(parent)
{
}
NetworkCookie::~NetworkCookie()
{
}
NetworkCookie& NetworkCookie::instance()
{
static NetworkCookie _uniqueInstance(Q_NULLPTR);
return _uniqueInstance;
}
QList
{
return allCookies();
}
void NetworkCookie::setCookies(const QList
{
if (this == NULL)
return;
this->setAllCookies(cookieList);
}
3 业务逻辑模块
#pragma once
/*********************************************************************
*@file BusinessLogicManager.h
*@brief 业务逻辑层
*@author
*@date
*********************************************************************/
#include
#include
#include
class BusinessLogicManager : public QObject
{
Q_OBJECT
public:
explicit BusinessLogicManager(QObject *parent = nullptr);
~BusinessLogicManager();
void networkRequest(NetMessage&);
Q_SIGNALS:
/// @ 业务层->网络层(UI层通过业务层发送网络请求)
void sigNetworkRequest(NetMessage&);
public Q_SLOTS:
// 网络请求返回成功消息通知
void on_comming_msg(const QString &_type, const QByteArray&);
// 网络请求返回失败消息通知
void on_comming_error(const QString &_type, const int &_error_code, const QString &_error_string);
// 网络请求超时消息通知
void on_comming_timeout(const QString &_type);
Q_SIGNALS:
void sigAskAction(bool, const QString&, int _error_code = 0);
private:
/// @发送文本消息
void onAskAction(const QString &_type, const QByteArray& _byte_array);
}
#include "BusinessLogicManager.h"
#include "NetWorkLayer\NetworkCookie.h"
BusinessLogicManager::BusinessLogicManager(QObject *parent)
: QObject(parent)
{
}
BusinessLogicManager::~BusinessLogicManager()
{
}
void BusinessLogicManager::networkRequest(NetMessage&_msg)
{
emit sigNetRequest(_msg);
}
// 【这里如果请求过多 会出现打来你给ifelse,后续会出关于优化ifelse文章】
void BusinessLogicManager::on_comming_msg(const QString &_type, const QByteArray&_byte)
{
if (_type == NET_TYPE_ASK_ACTION)
{// 网络请求成功
onAskAction(_type, _byte_array);
}
}
void BusinessLogicManager::on_comming_error(const QString &_type, const int &_error_code, const QString &_error_string)
{
if (_type == NET_TYPE_ASK_ACTION)
{// 网络请求错误通知
emit sigAskAction(false, tr("网络请求错误通知"));
}
}
void BusinessLogicManager::on_comming_timeout(const QString &_type)
{
if (_type == NET_TYPE_ASK_ACTION)
{// 超时处理
emit sigAskAction(false, tr("超时处理"));
}
}
/**
* 发送文本消息
*/
void BusinessLogicManager::onAskAction(const QString &_type, const QByteArray& _byte_array)
{
// 这里是对网络请求返回的数据进行处理,然后通知UI模块
std::string _f = Jsonc::instance().getJsonValueStringByKey(Utils::byteArray2string(_byte_array), "f");
QString f = QString::fromStdString(_f);
QString _context = tr("回复成功");
if (f == "0")
{
_context = tr("回复成功");
emit sigAskAction(true, tr(""));
}
else if (f == "2")
{
_context = tr("未登录");
emit sigReLogin();
}
else if (f == "3")
{
_context = tr("字数大于80");
emit sigAskAction(false, tr("字数大于80"));
}
else if (f == "4")
{
_context = tr("内容为空");
emit sigAskAction(false, tr("内容为空"));
}
else if (f == "5")
{
_context = tr("3秒后再发言");
emit sigAskAction(false, tr("3秒后再发言"));
}
else if (f == "6")
{
_context = tr("您已被禁言");
emit sigAskAction(false, tr("您已被禁言"));
}
else if (f == "7")
{
_context = tr("未绑定手机号");
emit sigAskAction(false, tr("未绑定手机号"));
}
}
4 中间层
#pragma once
/*********************************************************************
*@file BridgeManager.h
*@brief 中间控制层(UI、业务逻辑、网络)
*@author
*@date
*********************************************************************/
#include
#include "NetWorkLayer\NetworkManager.h"
#include "BusinessLogicLayer\BusinessLogicManager.h"
class BridgeManager : public QObject
{
Q_OBJECT
public:
static BridgeManager& instance();
// 得到网络层 和 业务逻辑层 实例
BusinessLogicManager* businessIns()const;
NetworkManager* networkIns()const;
private:
BridgeManager(QObject *parent);
~BridgeManager();
private:
NetworkManager *m_networkManager = nullptr;
BusinessLogicManager *m_businessLogicManager = nullptr;
};
#include "BridgeManager.h"
BridgeManager::BridgeManager(QObject *parent)
: QObject(parent)
{
m_businessLogicManager = new BusinessLogicManager(this);
m_networkManager = new NetworkManager(this);//这里的实例化得注意了(this 会导致NetWork崩溃)
// 业务层->网络层
connect(m_businessLogicManager, &BusinessLogicManager::sigNetworkRequest, m_networkManager, &NetworkManager::on_net_request_activated);
// 网络层->业务层
connect(m_networkManager, &NetworkManager::sigReply, m_businessLogicManager, &BusinessLogicManager::on_comming_msg);
connect(m_networkManager, &NetworkManager::sigReplyError, m_businessLogicManager, &BusinessLogicManager::on_comming_error);
connect(m_networkManager, &NetworkManager::sigTimeout, m_businessLogicManager, &BusinessLogicManager::on_comming_timeout);
}
BridgeManager::~BridgeManager()
{
}
BridgeManager& BridgeManager::instance()
{
static BridgeManager _uniqueInstance(Q_NULLPTR);
return _uniqueInstance;
}
BusinessLogicManager* BridgeManager::businessIns()const
{
return m_businessLogicManager;
}
NetworkManager* BridgeManager::networkIns()const
{
return m_networkManager;
}