Qt使用QJson进行Http请求时序列反序列对象

1. 创建工程

  • 使用CMake创建工程

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

cmake_minimum_required(VERSION 3.20 FATAL_ERROR)

project(httprequest LANGUAGES CXX)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")

set(QT_VERSION_STR_Win32 "5.15.2/msvc2019")
set(QT_VERSION_STR_Win64 "5.15.2/msvc2019_64")

if(CMAKE_HOST_WIN32)
  if(CMAKE_CL_64)
    set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "D:/Qt/${QT_VERSION_STR_Win64}")
    set(QT_QMAKE_EXECUTABLE "D:/Qt/${QT_VERSION_STR_Win64}/bin/qmake.exe")
  else()
    set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "D:/Qt/${QT_VERSION_STR_Win32}")
    set(QT_QMAKE_EXECUTABLE "D:/Qt/${QT_VERSION_STR_Win32}/bin/qmake.exe")
  endif()
endif()

set(EXPAN_MACRO OFF)
if(EXPAN_MACRO)
  if(MSVC)
    add_compile_options(/P /EP)
  endif(MSVC)
endif()

add_executable(${CMAKE_PROJECT_NAME} "")
# add_executable(${CMAKE_PROJECT_NAME} WIN32 "")

file(GLOB srcs CMAKE_CONFIGURE_DEPENDS *.cpp)
file(GLOB headers CMAKE_CONFIGURE_DEPENDS *.h)
file(GLOB forms CMAKE_CONFIGURE_DEPENDS *.ui)
file(GLOB resources CMAKE_CONFIGURE_DEPENDS *.qrc)

target_sources(${CMAKE_PROJECT_NAME} PRIVATE ${srcs} ${forms} ${resources})
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${headers})

find_package(Qt5 COMPONENTS Core Widgets Network REQUIRED)

target_link_libraries(${CMAKE_PROJECT_NAME}
	PRIVATE 
  Qt5::Core Qt5::Widgets Qt5::Network
)

引入QJson

add_subdirectory(qjson)
find_package(Qt5 COMPONENTS Core Widgets Network REQUIRED)

target_link_libraries(${CMAKE_PROJECT_NAME}
  PRIVATE 
  Qt5::Core Qt5::Widgets Qt5::Network
  qjson-qt5
)

创建相应的头、源文件

.
├── [1.7K]  CMakeLists.txt
├── [ 26K]  CMakeLists.txt.user
├── [4.0K]  build
│   ├── [ 27K]  ALL_BUILD.vcxproj
│   ├── [ 290]  ALL_BUILD.vcxproj.filters
│   ├── [ 18K]  CMakeCache.txt
│   ├── [4.0K]  CMakeFiles
│   ├── [4.0K]  Debug
│   ├── [ 10K]  INSTALL.vcxproj
│   ├── [ 532]  INSTALL.vcxproj.filters
│   ├── [ 19K]  UpgradeLog.htm
│   ├── [ 29K]  ZERO_CHECK.vcxproj
│   ├── [ 533]  ZERO_CHECK.vcxproj.filters
│   ├── [4.0K]  bin
│   ├── [1.6K]  cmake_install.cmake
│   ├── [4.0K]  httprequest.dir
│   ├── [5.9K]  httprequest.sln
│   ├── [ 57K]  httprequest.vcxproj
│   ├── [3.2K]  httprequest.vcxproj.filters
│   ├── [4.0K]  httprequest_autogen
│   ├── [4.0K]  lib
│   ├── [4.0K]  qjson
│   └── [4.0K]  win32
├── [ 102]  cncposition.cpp
├── [3.9K]  cncposition.h
├── [ 209]  main.cpp
├── [2.5K]  mainwindow.cpp
├── [ 319]  mainwindow.h
├── [1.2K]  mainwindow.ui
└── [4.0K]  qjson
    ├── [6.4K]  CMakeLists.txt
    ├── [ 26K]  COPYING.lib
    ├── [3.8K]  ChangeLog
    ├── [ 195]  QJSONConfig.cmake.in
    ├── [ 477]  QJSONConfigVersion.cmake.in
    ├── [ 390]  QJson.pc.in
    ├── [3.1K]  README.license
    ├── [3.4K]  README.md
    ├── [4.0K]  build
    ├── [ 750]  cmake_uninstall.cmake.in
    ├── [4.0K]  doc
    ├── [4.0K]  include
    ├── [4.0K]  src
    └── [4.0K]  tests

3. 定义有动态列表的对象模型

  • cncposition.h
#ifndef CNCPOSITION_H
#define CNCPOSITION_H

#include <QObject>
#include <QVector>
#include <QList>
#include <QStringList>
#include <QVariantList>
#include <QDebug>

class CncPosition : public QObject
{
    Q_OBJECT

    // Q_PROPERTY(int code READ code WRITE setCode)
    // Q_PROPERTY(QString message READ message WRITE setMessage)

    Q_PROPERTY(QStringList axis READ axis WRITE setAxis)
    Q_PROPERTY(QStringList units READ units WRITE setUnits)
    Q_PROPERTY(QVariant absoluteCoords READ absoluteCoords WRITE setAbsoluteCoords)
    Q_PROPERTY(QVariant relativeCoords READ relativeCoords WRITE setRelativeCoords)
    Q_PROPERTY(QVariant machineCoords READ machineCoords WRITE setMachineCoords)
    Q_PROPERTY(QVariant distances READ distances WRITE setDistances)

public:
    explicit CncPosition(QObject *parent = nullptr);

    // int code() const { return _code; }
    // void setCode(int code) { _code = code; }

    // QString message() const { return _message; }
    // void setMessage(QString &message) { _message = message; }

    QStringList axis() const { return _axis; }
    void setAxis(const QStringList &axis)
    {
        // qDebug() << axis;
        _axis = axis;
    }

    QStringList units() const { return _units; }
    void setUnits(const QStringList &units)
    {
        // qDebug() << units;
        _units = units;
    }

private:
    QVariant absoluteCoords() const { return QVariant::fromValue(_absoluteCoords); }
    QVariant relativeCoords() const { return QVariant::fromValue(_relativeCoords); }
    QVariant machineCoords() const { return QVariant::fromValue(_machineCoords); }
    QVariant distances() const { return QVariant::fromValue(_distances); }

public:
    QList<double> getAbsoluteCoords() const { return _absoluteCoords; }
    void setAbsoluteCoords(const QVariant &absoluteCoords)
    {
        _absoluteCoords.clear();
        for (auto var: absoluteCoords.toList()) {
            _absoluteCoords.append(var.toDouble());
        }
    }

    QList<double> getRelativeCoords() const { return _relativeCoords; }
    void setRelativeCoords(const QVariant &relativeCoords)
    {
        _relativeCoords.clear();
        for (auto var : relativeCoords.toList()) {
            _relativeCoords.append(var.toDouble());
        }
    }

    QList<double> getMachineCoords() const {return _machineCoords;}
    void setMachineCoords(const QVariant &machineCoords)
    {
        _machineCoords.clear();
        for (auto var : machineCoords.toList()) {
            _machineCoords.append(var.toDouble());
        }
    }

    QList<double> getDistences() const {return _distances;}
    void setDistances(const QVariant &distances)
    {
        _distances.clear();
        for (auto var : distances.toList()) {
            _distances.append(var.toDouble());
        }
    }

public:
    friend QDebug operator<<(QDebug dbg, const CncPosition &p)
    {
        // dbg.nospace() << "code:" << p.code() << "message:" << p.message()
        //               << "Axis:" << p.Axis() << "Units:" << p.Units() << "AbsoluteCoords:" << p.AbsoluteCoords()
        //               << "RelativeCoords:" << p.RelativeCoords() << "MachineCoords:" << p.MachineCoords()
        //               << "Distances:" << p.Distances();

        // dbg << "code:" << p.code() << "message:" << p.message()
        dbg << "Axis:" << p.axis() << "Units:" << p.units() << "AbsoluteCoords:" << p.getAbsoluteCoords()
            << "RelativeCoords:" << p.getRelativeCoords() << "MachineCoords:" << p.getMachineCoords()
            << "Distances:" << p.getDistences();

        return dbg;
    }

signals:

private:
    // int _code;
    // QString _message;
    QStringList _axis;
    QStringList _units;
    QList<double> _absoluteCoords;
    QList<double> _relativeCoords;
    QList<double> _machineCoords;
    QList<double> _distances;
};

#endif // CNCPOSITION_H

4. 运行验证

在mainwindow这个Widget中定义了一个PushButtton和一个用于显示请求到的application/json;charset=utf-8的Content-Type, 下面时验证代码,将QNetworkAccessManager使用同步的方式取结果

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

    connect(ui->pushButton, &QPushButton::clicked, this, [=]
            {

        std::unique_ptr<QNetworkAccessManager> manager = std::make_unique<QNetworkAccessManager>(new QNetworkAccessManager());
        QUrlQuery urlQuery;
        urlQuery.addQueryItem("fcode", "CNC_POSITION");
        QUrl url("http://127.0.0.1:9001/das/services/pull?" + urlQuery.query(QUrl::FullyDecoded));
        QNetworkRequest request(url);
        request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json;charset=utf-8");

        QNetworkReply *reply = manager->get(request);
        QEventLoop eloop;
        QObject::connect(reply, &QNetworkReply::finished, &eloop, &QEventLoop::quit);
        eloop.exec(QEventLoop::ExcludeUserInputEvents);

        auto jstr = reply->readAll();

        // QString text = "{\"axis\":[\"X\",\"Y\",\"Z\",\"A\",\"U\"],\"units\":[\"mm\",\"mm\",\"mm\",\"ang\",\"mm\"],\"absoluteCoords\":[33,-768,98.7,99,0],\"relativeCoords\":[33,-768,98.7,99,0],\"machineCoords\":[33,-768,98.7,99,0],\"distances\":[0,0,0,0,0]}";

        QJson::Parser parser;
        parser.specialNumbersAllowed();
        bool ok = false;
        auto variant = parser.parse(jstr, &ok);
        // auto variant = parser.parse(text.toUtf8(), &ok);
        if (!ok)
        {
            qWarning() << parser.errorString();
            return;
        }

        // 返回值检查
        auto map = variant.toMap();
        int code = map["code"].toInt();
        if (code != 0)
        {
            qWarning() << map["message"].toString();
            return;
        }

        // 反序列化到对象实列
        CncPosition position;
        QJson::QObjectHelper::qvariant2qobject(map["data"].toMap(), &position);

        qDebug() << position;

        ui->textEdit->setText(jstr);
        reply->deleteLater(); });
}

后端返回的Json内容如下

{"code":0,"message":"成功","data":{"axis":["X","Y","Z","A","U"],"units":
["mm","mm","mm","ang","mm"],"absoluteCoords":
[33,-768,98.7,99,0],"relativeCoords":[33,-768,98.7,99,0],"machineCoords":
[33,-768,98.7,99,0],"distances":[0,0,0,0,0]}}

最终执行程序验证,通过cncpostion类中重载的<<操作符,输出结果

Axis: ("X", "Y", "Z", "A", "U") Units: ("mm", "mm", "mm", "ang", "mm") 
AbsoluteCoords: (33, -768, 98.7, 99, 0) RelativeCoords: (33, -768, 98.7, 99, 0) MachineCoords: (33, -768, 98.7, 99, 0) Distances: (0, 0, 0, 0, 0)

5. 结论

  • QJson来进行对象的序列、反序列化非常的方便,提高了程序的可读性与开发效率
  • 服务端序列化Key值使用小驼峰方式,二者之间必须明确协议,服务端能够兼容到不区分大小写的Key值,通过实际使用中发现QJson对Key值大小写敏感,否则QJson::QObjectHelper::qvariant2qobject会失败
  • 能注意到cncpostion中Q_PROPERTY的部分的操作类型必须保持一致,否则Qt Moc(Meta-Object Compiler)会出错,但是Moc并不会限制READ、WRITE部分的访问权限,猜测是做的模板生成与字符方面的处理,这样可以让需要序列、反序列部分使用QJson解析支持的QVariant, 然后公开出去的Get属性返回最终的使用类型。

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

猜你喜欢

转载自blog.csdn.net/m0_73443478/article/details/131231904
今日推荐