This commit is contained in:
zhuzichu 2023-11-23 18:18:28 +08:00
parent 542ea0a7b9
commit 35d85aa801
8 changed files with 710 additions and 2 deletions

View File

@ -189,5 +189,6 @@
<file>qml/page/T_Clip.qml</file> <file>qml/page/T_Clip.qml</file>
<file>qml/page/T_3D.qml</file> <file>qml/page/T_3D.qml</file>
<file>qml/global/Lang.qml</file> <file>qml/global/Lang.qml</file>
<file>qml/page/T_Network.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -407,11 +407,17 @@ FluObject{
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
FluPaneItem{ FluPaneItem{
title:"Http" title:"Http(Deprecated)"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
url:"qrc:/example/qml/page/T_Http.qml" url:"qrc:/example/qml/page/T_Http.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
FluPaneItem{
title:"Network"
menuDelegate: paneItemMenu
url:"qrc:/example/qml/page/T_Network.qml"
onTap:{ navigationView.push(url) }
}
FluPaneItem{ FluPaneItem{
id:item_other id:item_other
title:"RemoteLoader" title:"RemoteLoader"

View File

@ -0,0 +1,149 @@
import QtQuick
import Qt.labs.platform
import QtQuick.Layouts
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Dialogs
import FluentUI
import "qrc:///example/qml/component"
FluContentPage{
title:"Network"
FluNetworkCallable{
id:callable
onStart: {
showLoading()
}
onFinish: {
hideLoading()
}
onError:
(status,errorString,result)=>{
console.debug(status+";"+errorString+";"+result)
}
onSuccess:
(result)=>{
text_info.text = result
}
}
Flickable{
id:layout_flick
width: 200
clip: true
anchors{
top: parent.top
topMargin: 20
bottom: parent.bottom
left: parent.left
}
ScrollBar.vertical: FluScrollBar {}
contentHeight:layout_column.height
Column{
spacing: 2
id:layout_column
width: parent.width
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "Get"
onClicked: {
FluNetwork.get("https://httpbingo.org/get")
.setTimeOut(10000)//15000
.setRetry(2)//3
.addQuery("name","孙悟空")
.addQuery("age",500)
.addQuery("address","花果山水帘洞")
.go(callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "Head"
onClicked: {
FluNetwork.head("https://httpbingo.org/head")
.addQuery("name","孙悟空")
.addQuery("age",500)
.addQuery("address","花果山水帘洞")
.go(callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "Post Body"
onClicked: {
FluNetwork.postBody("https://httpbingo.org/post")
.setBody("花果山水帘洞美猴王齐天大圣孙悟空")
.go(callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "Post JSON"
onClicked: {
FluNetwork.postJson("https://httpbingo.org/post")
.add("name","孙悟空")
.add("age",500)
.add("address","花果山水帘洞")
.go(callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "Post JSON Array"
onClicked: {
FluNetwork.postJsonArray("https://httpbingo.org/post")
.add("name","孙悟空")
.add("age",500)
.add("address","花果山水帘洞")
.go(callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "Post Form"
onClicked: {
FluNetwork.postForm("https://httpbingo.org/post")
.add("name","孙悟空")
.add("age",500)
.add("address","花果山水帘洞")
.go(callable)
}
}
}
}
FluArea{
anchors{
top: layout_flick.top
bottom: layout_flick.bottom
left: layout_flick.right
right: parent.right
leftMargin: 8
}
Flickable{
clip: true
id:scrollview
boundsBehavior:Flickable.StopAtBounds
width: parent.width
height: parent.height
contentWidth: width
contentHeight: text_info.height
ScrollBar.vertical: FluScrollBar {}
FluText{
id:text_info
width: scrollview.width
wrapMode: Text.WrapAnywhere
padding: 14
}
}
}
}

View File

@ -407,11 +407,17 @@ FluObject{
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
FluPaneItem{ FluPaneItem{
title:"Http" title:"Http(Deprecated)"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
url:"qrc:/example/qml/page/T_Http.qml" url:"qrc:/example/qml/page/T_Http.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
FluPaneItem{
title:"Network"
menuDelegate: paneItemMenu
url:"qrc:/example/qml/page/T_Network.qml"
onTap:{ navigationView.push(url) }
}
FluPaneItem{ FluPaneItem{
id:item_other id:item_other
title:"RemoteLoader" title:"RemoteLoader"

View File

@ -0,0 +1,148 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import FluentUI 1.0
import "qrc:///example/qml/component"
import "../component"
FluContentPage{
title:"Network"
FluNetworkCallable{
id:callable
onStart: {
showLoading()
}
onFinish: {
hideLoading()
}
onError:
(status,errorString,result)=>{
console.debug(status+";"+errorString+";"+result)
}
onSuccess:
(result)=>{
text_info.text = result
}
}
Flickable{
id:layout_flick
width: 200
clip: true
anchors{
top: parent.top
topMargin: 20
bottom: parent.bottom
left: parent.left
}
ScrollBar.vertical: FluScrollBar {}
contentHeight:layout_column.height
Column{
spacing: 2
id:layout_column
width: parent.width
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "Get"
onClicked: {
FluNetwork.get("https://httpbingo.org/get")
.setTimeOut(10000)//15000
.setRetry(2)//3
.addQuery("name","孙悟空")
.addQuery("age",500)
.addQuery("address","花果山水帘洞")
.go(callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "Head"
onClicked: {
FluNetwork.head("https://httpbingo.org/head")
.addQuery("name","孙悟空")
.addQuery("age",500)
.addQuery("address","花果山水帘洞")
.go(callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "Post Body"
onClicked: {
FluNetwork.postBody("https://httpbingo.org/post")
.setBody("花果山水帘洞美猴王齐天大圣孙悟空")
.go(callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "Post JSON"
onClicked: {
FluNetwork.postJson("https://httpbingo.org/post")
.add("name","孙悟空")
.add("age",500)
.add("address","花果山水帘洞")
.go(callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "Post JSON Array"
onClicked: {
FluNetwork.postJsonArray("https://httpbingo.org/post")
.add("name","孙悟空")
.add("age",500)
.add("address","花果山水帘洞")
.go(callable)
}
}
FluButton{
implicitWidth: parent.width
implicitHeight: 36
text: "Post Form"
onClicked: {
FluNetwork.postForm("https://httpbingo.org/post")
.add("name","孙悟空")
.add("age",500)
.add("address","花果山水帘洞")
.go(callable)
}
}
}
}
FluArea{
anchors{
top: layout_flick.top
bottom: layout_flick.bottom
left: layout_flick.right
right: parent.right
leftMargin: 8
}
Flickable{
clip: true
id:scrollview
boundsBehavior:Flickable.StopAtBounds
width: parent.width
height: parent.height
contentWidth: width
contentHeight: text_info.height
ScrollBar.vertical: FluScrollBar {}
FluText{
id:text_info
width: scrollview.width
wrapMode: Text.WrapAnywhere
padding: 14
}
}
}
}

288
src/FluNetwork.cpp Normal file
View File

@ -0,0 +1,288 @@
#include "FluNetwork.h"
#include <QUrlQuery>
#include <QBuffer>
#include <QHttpMultiPart>
#include <QJsonDocument>
#include <QNetworkReply>
#include <QJsonObject>
#include <QJsonArray>
NetworkCallable::NetworkCallable(QObject *parent):QObject{parent}{
}
QString NetworkParams::method2String(){
switch (_method) {
case METHOD_GET:
return "GET";
case METHOD_HEAD:
return "HEAD";
case METHOD_POST:
return "POST";
case METHOD_PUT:
return "PUT";
case METHOD_PATCH:
return "PATCH";
case METHOD_DELETE:
return "DELETE";
default:
return "";
}
}
int NetworkParams::getTimeout(){
if(_timeout != -1){
return _timeout;
}
return FluNetwork::getInstance()->timeout();
}
int NetworkParams::getRetry(){
if(_retry != -1){
return _retry;
}
return FluNetwork::getInstance()->retry();
}
NetworkParams::NetworkParams(QObject *parent)
: QObject{parent}
{
}
NetworkParams::NetworkParams(QString url,Type type,Method method,QObject *parent)
: QObject{parent}
{
this->_method = method;
this->_url = url;
this->_type = type;
}
NetworkParams* NetworkParams::add(QString key,QVariant val){
_paramMap.insert(key,val);
return this;
}
NetworkParams* NetworkParams::addHeader(QString key,QVariant val){
_headerMap.insert(key,val);
return this;
}
NetworkParams* NetworkParams::addQuery(QString key,QVariant val){
_queryMap.insert(key,val);
return this;
}
NetworkParams* NetworkParams::setBody(QString val){
_body = val;
return this;
}
NetworkParams* NetworkParams::setTimeOut(int val){
_timeout = val;
return this;
}
NetworkParams* NetworkParams::setRetry(int val){
_retry = val;
return this;
}
void NetworkParams::go(NetworkCallable* callable){
FluNetwork::getInstance()->handle(this,callable);
}
void FluNetwork::handle(NetworkParams* params,NetworkCallable* c){
std::shared_ptr<int> times = std::make_shared<int>(0);
QPointer<NetworkCallable> callable(c);
if(!callable.isNull()){
callable->start();
}
QUrl url(params->_url);
QNetworkAccessManager* manager = new QNetworkAccessManager();
QNetworkReply *reply = nullptr;
manager->setTransferTimeout(params->getTimeout());
addQueryParam(&url,params->_queryMap);
QNetworkRequest request(url);
addHeaders(&request,params->_headerMap);
connect(manager,&QNetworkAccessManager::finished,this,[this,params,request,callable,manager,times](QNetworkReply *reply){
if(reply->error() != QNetworkReply::NoError && *times < params->getRetry()) {
(*times)++;
sendRequest(manager,request,params,reply);
} else {
QString response = QString::fromUtf8(reply->readAll());
QNetworkReply::NetworkError error = reply->error();
if(error == QNetworkReply::NoError){
if(!callable.isNull()){
callable->success(response);
}
}else{
if(!callable.isNull()){
int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
callable->error(httpStatus,reply->errorString(),response);
}
}
reply->deleteLater();
manager->deleteLater();
if(!callable.isNull()){
callable->finish();
}
}
});
sendRequest(manager,request,params,reply);
}
void FluNetwork::sendRequest(QNetworkAccessManager* manager,QNetworkRequest request,NetworkParams* params,QNetworkReply*& reply){
if(reply){
reply->deleteLater();
}
QByteArray verb = params->method2String().toUtf8();
switch (params->_type) {
case NetworkParams::TYPE_FORM:{
QHttpMultiPart *multiPart = new QHttpMultiPart();
multiPart->setContentType(QHttpMultiPart::FormDataType);
for (const auto& each : params->_paramMap.toStdMap())
{
QHttpPart part;
part.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"").arg(each.first));
part.setBody(each.second.toByteArray());
multiPart->append(part);
}
reply = manager->sendCustomRequest(request,verb,multiPart);
multiPart->setParent(reply);
break;
}
case NetworkParams::TYPE_JSON:{
request.setHeader(QNetworkRequest::ContentTypeHeader, QString("application/json;charset=utf-8"));
QJsonObject json;
for (const auto& each : params->_paramMap.toStdMap())
{
json.insert(each.first,each.second.toJsonValue());
}
QByteArray data = QJsonDocument(json).toJson(QJsonDocument::Compact);
reply = manager->sendCustomRequest(request,verb,data);
break;
}
case NetworkParams::TYPE_JSONARRAY:{
request.setHeader(QNetworkRequest::ContentTypeHeader, QString("application/json;charset=utf-8"));
QJsonArray jsonArray;
for (const auto& each : params->_paramMap.toStdMap())
{
QJsonObject json;
json.insert(each.first,each.second.toJsonValue());
jsonArray.append(json);
}
QByteArray data = QJsonDocument(jsonArray).toJson(QJsonDocument::Compact);
reply = manager->sendCustomRequest(request,params->method2String().toUtf8(),data);
break;
}
case NetworkParams::TYPE_BODY:{
request.setHeader(QNetworkRequest::ContentTypeHeader, QString("text/plain;charset=utf-8"));
QByteArray data = params->_body.toUtf8();
reply = manager->sendCustomRequest(request,verb,data);
break;
}
default:
reply = manager->sendCustomRequest(request,verb);
break;
}
}
void FluNetwork::addHeaders(QNetworkRequest* request,const QMap<QString, QVariant>& headers){
QMapIterator<QString, QVariant> iter(headers);
while (iter.hasNext())
{
iter.next();
request->setRawHeader(iter.key().toUtf8(), iter.value().toString().toUtf8());
}
}
void FluNetwork::addQueryParam(QUrl* url,const QMap<QString, QVariant>& params){
QMapIterator<QString, QVariant> iter(params);
QUrlQuery urlQuery(*url);
while (iter.hasNext())
{
iter.next();
urlQuery.addQueryItem(iter.key(), iter.value().toString());
}
url->setQuery(urlQuery);
}
FluNetwork::FluNetwork(QObject *parent): QObject{parent}
{
timeout(15000);
retry(3);
}
NetworkParams* FluNetwork::get(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_NONE,NetworkParams::METHOD_GET);
}
NetworkParams* FluNetwork::head(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_NONE,NetworkParams::METHOD_HEAD);
}
NetworkParams* FluNetwork::postBody(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_BODY,NetworkParams::METHOD_POST);
}
NetworkParams* FluNetwork::putBody(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_BODY,NetworkParams::METHOD_PUT);
}
NetworkParams* FluNetwork::patchBody(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_BODY,NetworkParams::METHOD_PATCH);
}
NetworkParams* FluNetwork::deleteBody(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_BODY,NetworkParams::METHOD_DELETE);
}
NetworkParams* FluNetwork::postForm(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_FORM,NetworkParams::METHOD_POST);
}
NetworkParams* FluNetwork::putForm(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_FORM,NetworkParams::METHOD_PUT);
}
NetworkParams* FluNetwork::patchForm(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_FORM,NetworkParams::METHOD_PATCH);
}
NetworkParams* FluNetwork::deleteForm(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_FORM,NetworkParams::METHOD_DELETE);
}
NetworkParams* FluNetwork::postJson(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_JSON,NetworkParams::METHOD_POST);
}
NetworkParams* FluNetwork::putJson(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_JSON,NetworkParams::METHOD_PUT);
}
NetworkParams* FluNetwork::patchJson(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_JSON,NetworkParams::METHOD_PATCH);
}
NetworkParams* FluNetwork::deleteJson(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_JSON,NetworkParams::METHOD_DELETE);
}
NetworkParams* FluNetwork::postJsonArray(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_JSONARRAY,NetworkParams::METHOD_POST);
}
NetworkParams* FluNetwork::putJsonArray(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_JSONARRAY,NetworkParams::METHOD_PUT);
}
NetworkParams* FluNetwork::patchJsonArray(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_JSONARRAY,NetworkParams::METHOD_PATCH);
}
NetworkParams* FluNetwork::deleteJsonArray(const QString& url){
return new NetworkParams(url,NetworkParams::TYPE_JSONARRAY,NetworkParams::METHOD_DELETE);
}

105
src/FluNetwork.h Normal file
View File

@ -0,0 +1,105 @@
#ifndef FLUNETWORK_H
#define FLUNETWORK_H
#include <QObject>
#include <QtQml/qqml.h>
#include <QFile>
#include <QJsonValue>
#include <QNetworkAccessManager>
#include "stdafx.h"
#include "singleton.h"
class NetworkCallable : public QObject{
Q_OBJECT
QML_NAMED_ELEMENT(FluNetworkCallable)
public:
explicit NetworkCallable(QObject *parent = nullptr);
Q_SIGNAL void start();
Q_SIGNAL void finish();
Q_SIGNAL void error(int status,QString errorString,QString result);
Q_SIGNAL void success(QString result);
};
class NetworkParams : public QObject
{
Q_OBJECT
QML_NAMED_ELEMENT(FluNetworkParams)
public:
enum Method{
METHOD_GET,
METHOD_HEAD,
METHOD_POST,
METHOD_PUT,
METHOD_PATCH,
METHOD_DELETE
};
enum Type{
TYPE_NONE,
TYPE_FORM,
TYPE_JSON,
TYPE_JSONARRAY,
TYPE_BODY
};
explicit NetworkParams(QObject *parent = nullptr);
NetworkParams(QString url,Type type,Method method,QObject *parent = nullptr);
Q_INVOKABLE NetworkParams* addQuery(QString key,QVariant val);
Q_INVOKABLE NetworkParams* addHeader(QString key,QVariant val);
Q_INVOKABLE NetworkParams* add(QString key,QVariant val);
Q_INVOKABLE NetworkParams* setBody(QString val);
Q_INVOKABLE NetworkParams* setTimeOut(int val);
Q_INVOKABLE NetworkParams* setRetry(int val);
Q_INVOKABLE void go(NetworkCallable* result);
QString method2String();
int getTimeout();
int getRetry();
public:
Method _method;
Type _type;
QString _url;
QString _body;
QMap<QString, QVariant> _queryMap;
QMap<QString, QVariant> _headerMap;
QMap<QString, QVariant> _paramMap;
int _timeout = -1;
int _retry = -1;
};
class FluNetwork : public QObject
{
Q_OBJECT
Q_PROPERTY_AUTO(int,timeout)
Q_PROPERTY_AUTO(int,retry)
QML_NAMED_ELEMENT(FluNetwork)
QML_SINGLETON
private:
explicit FluNetwork(QObject *parent = nullptr);
public:
SINGLETONG(FluNetwork)
static FluNetwork *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return getInstance();}
Q_INVOKABLE NetworkParams* get(const QString& url);
Q_INVOKABLE NetworkParams* head(const QString& url);
Q_INVOKABLE NetworkParams* postBody(const QString& url);
Q_INVOKABLE NetworkParams* putBody(const QString& url);
Q_INVOKABLE NetworkParams* patchBody(const QString& url);
Q_INVOKABLE NetworkParams* deleteBody(const QString& url);
Q_INVOKABLE NetworkParams* postForm(const QString& url);
Q_INVOKABLE NetworkParams* putForm(const QString& url);
Q_INVOKABLE NetworkParams* patchForm(const QString& url);
Q_INVOKABLE NetworkParams* deleteForm(const QString& url);
Q_INVOKABLE NetworkParams* postJson(const QString& url);
Q_INVOKABLE NetworkParams* putJson(const QString& url);
Q_INVOKABLE NetworkParams* patchJson(const QString& url);
Q_INVOKABLE NetworkParams* deleteJson(const QString& url);
Q_INVOKABLE NetworkParams* postJsonArray(const QString& url);
Q_INVOKABLE NetworkParams* putJsonArray(const QString& url);
Q_INVOKABLE NetworkParams* patchJsonArray(const QString& url);
Q_INVOKABLE NetworkParams* deleteJsonArray(const QString& url);
void handle(NetworkParams* params,NetworkCallable* result);
private:
void sendRequest(QNetworkAccessManager* manager,QNetworkRequest request,NetworkParams* params,QNetworkReply*& reply);
void addQueryParam(QUrl* url,const QMap<QString, QVariant>& params);
void addHeaders(QNetworkRequest* request,const QMap<QString, QVariant>& headers);
};
#endif // FLUNETWORK_H

View File

@ -17,6 +17,7 @@
#include "FluViewModel.h" #include "FluViewModel.h"
#include "Screenshot.h" #include "Screenshot.h"
#include "FluRectangle.h" #include "FluRectangle.h"
#include "FluNetwork.h"
#include "QRCode.h" #include "QRCode.h"
int major = 1; int major = 1;
@ -57,6 +58,8 @@ void FluentUI::registerTypes(const char *uri){
qmlRegisterType<FluViewModel>(uri,major,minor,"FluViewModel"); qmlRegisterType<FluViewModel>(uri,major,minor,"FluViewModel");
qmlRegisterType<FluTreeModel>(uri,major,minor,"FluTreeModel"); qmlRegisterType<FluTreeModel>(uri,major,minor,"FluTreeModel");
qmlRegisterType<FluRectangle>(uri,major,minor,"FluRectangle"); qmlRegisterType<FluRectangle>(uri,major,minor,"FluRectangle");
qmlRegisterType<NetworkCallable>(uri,major,minor,"FluNetworkCallable");
qmlRegisterType<NetworkParams>(uri,major,minor,"FluNetworkParams");
qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/ColorPicker/ColorPicker.qml"),uri,major,minor,"ColorPicker"); qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/ColorPicker/ColorPicker.qml"),uri,major,minor,"ColorPicker");
qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/ColorPicker/Content/Checkerboard.qml"),uri,major,minor,"Checkerboard"); qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/ColorPicker/Content/Checkerboard.qml"),uri,major,minor,"Checkerboard");
@ -191,5 +194,7 @@ void FluentUI::initializeEngine(QQmlEngine *engine, const char *uri){
engine->rootContext()->setContextProperty("FluTextStyle",textStyle); engine->rootContext()->setContextProperty("FluTextStyle",textStyle);
FluEventBus* eventBus = FluEventBus::getInstance(); FluEventBus* eventBus = FluEventBus::getInstance();
engine->rootContext()->setContextProperty("FluEventBus",eventBus); engine->rootContext()->setContextProperty("FluEventBus",eventBus);
FluNetwork* network = FluNetwork::getInstance();
engine->rootContext()->setContextProperty("FluNetwork",network);
engine->addImportPath("qrc:/qt/qml"); engine->addImportPath("qrc:/qt/qml");
} }