Qt使用Post发送Json数据以及表单数据上传文件到服务器

一、简介

1.任务目标

使用Qt通过post发送Json格式数据,或者以表单形式发送数据到服务器

2.环境简介

系统:Windows 10
Qt版本:5.7

二、内容准备

1、关于Qt

1.使用Post向服务器发送数据,使用到网络编程,需要在Pro文件中加入如下语句

QT       += network

2.使用网络编程需要用到一下库文件,还有一些在本示例中用到的库文件如下

#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QHttpMultiPart>
#include <QHttpPart>
#include <QUrlQuery>

3.Qt中使用Json数据需要用到一下库文件

#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>

三、Json数据介绍

1.Json中的基础数据类型:数字 字符串 布尔值
数字:int,double,float
字符串:string
布尔值:true,false

2.Json中的常见格式如下
2.1Json对象
通常以{}形式存在,数据可以当成pair类型的数据,有key对应着value,每一组key-value用逗号隔开,为方便演示写成多行,也可在一行内写完,例子如下

{
"userid":"123456",
"username":"Tom",
"age":25,
"score":95,
"pass":true
}

或者一行写完

{
“userid”:“123456”,“username”:“Tom”,“age”:25,"score":95,"pass":true
}

2.2Json数组
与C++中数组类似,Json中通常数组格式为数组名:[数据1,数据2...]

"hobby":["足球","羽毛球"]

2.3Json对象与Json数组组合
一个Json对象能包含多个Json数组
一个Json数组可以包含多个Json对象

{
"userid":"123456",
"username":"Tom",
"age":25,
"hobby":[
         {"足球","羽毛球"},
         {"书法","绘画"},
]
"score":95,
"pass":true
}

3.Qt中的Json
在Qt中有专门对Json的处理库,在5.x版本之后支持,4.x版本不支持,头文件参看上面头文件部分
Json对象在Qt中使用QJsonObject
Json数组在Qt中使用QJsonArray
在Qt中还有QJsonDocment类,该类可以当作对QJsonObject和QJsonArray的翻译,主要用来读写Json文档

4.表单数据
在Qt中,也可上传表单格式的数据到服务器,不仅可以传数据,也可以传送文件,例如音乐文件(本例使用mp3格式,具体格式可以根据需求改变),图片文件(本例使用jpeg格式,具体格式可以根据需求改变),具体使用方式以及使用格式参考下文代码示例

四、使用方法

1.新建一个类,类名定义为PostSendData,该类主要为实现发送Json数据,表单方式发送文件与接收Json返回的数据的功能,头文件与CPP文件如下

1.PostSendData头文件

class PostSendData: public QObject
{
    Q_OBJECT
public:
    PostSendData(QObject * parent = nullptr);

public:
    PostSendData(QNetworkAccessManager* net_acess_manager, QUrl url, int request_type);

    ~PostSendData();

public:
    void SendJsonData();//发送Json数据
    void SendMusic();//发送音乐文件
    void SendImage();//发送图片文件

public:
    //解析Json数据
    void getJson(QJsonObject &jsonObj);

private slots:
    void finshedSlot(QNetworkReply* reply);//用来接收返回的Json数据

private:
    QNetworkAccessManager* m_net_manager;
    QUrl m_url;
    int m_request_type;
}

2.PostSendData.cpp

#include "postsenddata.h"
PostSendData::PostSendData(QNetworkAccessManager *net_acess_manager, QUrl url, int request_type)
    :m_net_manager(net_acess_manager),
      m_url(url),
      m_request_type(request_type)
{
    connect(m_net_manager,
            &QNetworkAccessManager::finished,
            this,
            &PostSendData::finshedSlot);
}

/*
 * 示例要发送的Json数据 *
{
"userid":"123456",
"username":"Tom",
"age":25,
"hobby":["足球","羽毛球"]
"score":95,
"pass":true
}
*/

void PostSendData::SendJsonData()
{
    QNetworkRequest netReq;
    netReq.setUrl(this->m_url);
    netReq.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json"));//post请求设置为json,才能发送josn格式文件
    //创建一个Json对象,这个Json对象就是要发送的内容,展开成Json数据如上所示
    QJsonObject jsonObj;
    jsonObj.insert("userid","123456");
    jsonObj.insert("username","Tom");
    jsonObj.insert("age",25);
    QJsonArray arryHobby;//hobby为一个Json数组,就创建一个QJsonArray对象,用来包含hobby的内容
    arryHobby.append("足球");
    arryHobby.append("羽毛球");
    jsonObj.insert("hobby",arryHobby);//将hobby这个JsonArray加入到hobby这个JsonObject中
    jsonObj.insert("score",95);
    jsonObj.insert("pass",true);

    //创建一个QJsonDocument类对象,jsonDoc可以将Json格式数据转换之后,使用post发送
    QJsonDocument jsonDoc = QJsonDocument(jsonObj);
    QByteArray post_data = jsonDoc.toJson(QJsonDocument::Compact);
    m_net_manager->post(netReq,post_data);
}

void PostSendData::SendMusic()
{
    //打开要发送的音乐文件,这里使用了一首大小为3M的歌曲,也可以具体使用时在指定要发送的音乐文件,此处方便演示直接使用绝对路径下的音乐文件
    QString filePath = "H:/Code/QT/PostTest/bin/测试.mp3";
    QFile* file = new QFile(filePath);
    file->open(QIODevice::ReadOnly);

    //发送音乐文件时,有可能还有附加的数据内容,可以预先定义好,也可发送时再定义
    QString userid = "123456";
    QString username = "Tom";

    QNetworkRequest netReq;
    netReq.setUrl(this->m_url);

/*
 * 使用QHttpMultiPart创建一个multiPart对象,我们最后要发送的就是这multiPart对象
 * multiPart中的内容,添加使用QHttpPart创建的对象
 * QHttpPart类创建的对象,因为这里发送的有数据,也有音乐文件,所以使用from-data
*/

    QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);

    QHttpPart useridPart;
    useridPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"userid\""));
    useridPart.setBody(userid.toUtf8());

    QHttpPart usernamePart;
    usernamePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"username\""));
    usernamePart.setBody(username.toUtf8());

    QHttpPart projectidPart;
    projectidPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"projectid\""));
    projectidPart.setBody("9");
    //这里将要发送的文件放入mp3Part中
    QHttpPart mp3Part;
    mp3Part.setHeader(QNetworkRequest::ContentDispositionHeader,
                      QVariant(QString("form-data; name=\"file\";filename=\"测试.mp3\";")));
    mp3Part.setBodyDevice(file);

    //将所有想发送的内容放入multiPart中
    multiPart->append(useridPart);
    multiPart->append(usernamePart);
    multiPart->append(projectidPart);
    multiPart->append(mp3Part);
    //发送
    m_net_manager->post(netReq,multiPart);
}

void PostSendData::SendImage()
{
    //与发送音乐文件类似,不过是改成图片文件
    QString filePath = "H:/Code/QT/PostTest/bin/测试.jpeg";
    QFile* file = new QFile(filePath);
    file->open(QIODevice::ReadOnly);

    QString userid = "123456";
    QString username = "Tom";

    QNetworkRequest netReq;
    netReq.setUrl(this->m_url);

    QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);

    QHttpPart useridPart;
    useridPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"userid\""));
    useridPart.setBody(userid.toUtf8());

    QHttpPart usernamePart;
    usernamePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"username\""));
    usernamePart.setBody(username.toUtf8());

    QHttpPart projectidPart;
    projectidPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"projectid\""));
    projectidPart.setBody("9");

    QHttpPart imagePart;
    imagePart.setHeader(QNetworkRequest::ContentDispositionHeader,
                      QVariant(QString("form-data; name=\"file\";filename=\"测试.jpeg\";")));
    imagePart.setBodyDevice(file);

    multiPart->append(useridPart);
    multiPart->append(usernamePart);
    multiPart->append(projectidPart);
    multiPart->append(imagePart);

    m_net_manager->post(netReq,multiPart);
}

void PostSendData::getJson(QJsonObject &jsonObj)
{
    switch (this->m_request_type)
    {
    case SENDDATA:
    {
/*
 * 返回Json数据示例,code:1-成功,2-失败,3-用户识别失败
 * {"code":"1","msg":sucess,"result":true}
*/
        qDebug() << "------------------发送数据的返回---------------------";
        QString code = jsonObj.value("code").toString();
        qDebug() << "code = " << code;
        QString msg = jsonObj.value("msg").toString();
        qDebug() << "msg = " << msg;
        bool result = jsonObj.value("result").toBool();
        break;
    }
    case SENDMUSIC:
    {
/*
* 返回Json数据示例,code:1-成功,2-失败,3-用户识别失败
* {"code":"1","msg":sucess,"datas":[{"id":1,"music_name":"测试.mp3","music_id":456},]}
*/
        qDebug() << "------------------发送音乐的返回---------------------";
        QString code = jsonObj.value("code").toString();
        qDebug() << "code = " << code;
        QString msg = jsonObj.value("msg").toString();
        qDebug() << "msg = " << msg;

        //返回的Json数据中,datas是一个Json数组包含了Json对象,先把JsonObject转换成JsonValue
        //JsonValue转换成JsonArray,再去循环读出JsonArray的内容
        QJsonValue locationValue = jsonObj.value(QStringLiteral("datas"));
        QJsonArray locationValueArray = locationValue.toArray();
        for (int i = 0; i < locationValueArray.size(); i++)
        {
            QJsonValue locationArray = locationValueArray.at(i);
            QJsonObject location = locationArray.toObject();
            qDebug()<< "id = " << location["id"].toString();
            qDebug()<< "music_name = "<< location["music_name"].toString();
            qDebug()<< "music_id = " << location["music_id"].toString();
        }

        break;
    }
    case SENDIMAGE:
    {
/*
*与发送音乐的返回类似
* 返回Json数据示例,code:1-成功,2-失败,3-用户识别失败
* {"code":"1","msg":sucess,"datas":[{"id":1,"image_name":"测试.jepg","image_id":456},]}
*/
        qDebug() << "------------------发送图片的返回---------------------";
        QString code = jsonObj.value("code").toString();
        qDebug() << "code = " << code;
        QString msg = jsonObj.value("msg").toString();
        qDebug() << "msg = " << msg;
        QJsonValue locationValue = jsonObj.value(QStringLiteral("datas"));
        QJsonArray locationValueArray = locationValue.toArray();
        for (int i = 0; i < locationValueArray.size(); i++)
        {
            QJsonValue locationArray = locationValueArray.at(i);
            QJsonObject location = locationArray.toObject();
            qDebug()<< "id = " << location["id"].toString();
            qDebug()<< "music_name = "<< location["image_name"].toString();
            qDebug()<< "music_id = " << location["image_id"].toString();
        }
        break;
    }
    }
}

void PostSendData::finshedSlot(QNetworkReply *reply)
{
    QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
    if(reply->error() == QNetworkReply::NoError)
    {
        QByteArray bytes = reply->readAll();
        QJsonDocument jsonDoc = QJsonDocument::fromJson(bytes);
        QJsonObject jsonObj = jsonDoc.object();
        getJson(jsonObj);
    }
    reply->deleteLater();
}

3.在MainWindown中,我添加了三个按钮,用来发送不同的内容,MainWindown的头文件不在贴出,按钮使用界面直接转到槽clicked(),只贴出MainWindown.cpp供参考

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "postsenddata.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::on_pushButton_sendData_clicked()
{
    QNetworkAccessManager* m_netmanager_upwav = new QNetworkAccessManager(this);
    QUrl senddataUrl = QUrl("http://SendData");
    PostSendData* sendData= new PostSendData(m_netmanager_upwav,senddataUrl,0);
    //0对应PostSendData中枚举类型,用途是接受不同的返回,解析Json数据时能找到解析的case,下面的1和2类似
    sendData->SendJsonData();
}

void MainWindow::on_pushButton_sendMusic_clicked()
{
    QNetworkAccessManager* m_netmanager_sendmusic = new QNetworkAccessManager(this);
    QUrl sendmusicUrl = QUrl("http://SendMusic");
    PostSendData* sendMusic= new PostSendData(m_netmanager_sendmusic,sendmusicUrl,1);
    sendMusic->SendMusic();
}

void MainWindow::on_pushButton_sendImage_clicked()
{
    QNetworkAccessManager* m_netmanager_sendimage = new QNetworkAccessManager(this);
    QUrl sendimageUrl = QUrl("http://SendImage");
    PostSendData* sendImagec= new PostSendData(m_netmanager_sendimage,sendimageUrl,2);
    sendImagec->SendImage();
}

后记说明

参考了很多文档,基础使用文档很多,综合起来使用的还是比较少,要不就是需要收费,所以这算是一个在Qt中使用Post方式,向http发送Json数据,以及使用表单形式发送文件+数据的一个综合例程,仅供参考,如有问题请指出,一起探讨进步。关于Qt中对于Json以及网络接口的使用,参考Qt中的文档,还有许多使用方式,接口函数可以调用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容