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

1. 创建工程

  • 使用CMake创建工程

    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-8Content-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值,通过实际使用中发现QJsonKey值大小写敏感,否则QJson::QObjectHelper::qvariant2qobject会失败

  • 能注意到cncpostionQ_PROPERTY的部分的操作类型必须保持一致,否则Qt Moc(Meta-Object Compiler)会出错,但是Moc并不会限制READ、WRITE部分的访问权限,猜测是做的模板生成与字符方面的处理,这样可以让需要序列、反序列部分使用QJson解析支持的QVariant, 然后公开出去的Get属性返回最终的使用类型。

posted @   非法关键字  阅读(58)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
点击右上角即可分享
微信分享提示