该文章用图例+代码方式演示了,一个线上软件基本框架(精简)。开发工具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(parent());

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 getCookies();

void setCookies(const QList& cookieList);

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 NetworkCookie::getCookies()

{

return allCookies();

}

void NetworkCookie::setCookies(const QList& cookieList)

{

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;

}