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-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
属性返回最终的使用类型。