Qt 天气预报项目

参考引用

  • QT开发专题-天气预报

1. JSON 数据格式

1.1 什么是 JSON

  • JSON (JavaScript Object Notation),中文名 JS 对象表示法,因为它和 JS 中对象的写法很类似
    • 通常说的 JSON,其实就是 JSON 字符串,本质上是一种特殊格式的字符串
    • JSON 是一种轻量级的数据交换格式,客户端和服务端数据交互,基本都是 JSON 格式的
  • JSON 有以下特点
    • 便于阅读和书写
      • 除了 JSON 格式,还有一种数据传输格式 XML,相对于 XML,JSON 更加便于阅读和书写独立于编程语言
    • 网络传输的标准数据格式
    • 完全独立于编程语言
      • 几乎在所有的编程语言和开发环境中,都有解析和生成 JSON 字符串的库
    // C
    Jansson cJSON// C++
    jsonCpp、JSON for Modern C++// Java
    json-lib、org-json// Qt
    QJSONxxx
    

1.2 JSON 的两种数据格式

JSON 有两种数据格式

  • JSON 对象(被大括号包裹)
  • JSON 数组(被中括号包裹)
1.2.1 JSON 数组
  • JSON 数组格式
    [元素1, 元素2, 元素3, ... 元素n]
    
  • 类似于 c/C++ 中的数组,元素之间以逗号分隔。不同的是,JSON 数组中的元素可以是不同的数据类型
    • 包括:整型、浮点、字符串、布尔类型、JSON 数组、JSON 对象、空值
    // JSON 数组中的元素是同一类型
    [1, 2, 3, 4]
    ["Spring", "Summer", "Autumn", "Winter"]// JSON 数组中的元素是不同类型
    [1, 2.5, "hello", true, false, null]// JSON 数组的嵌套
    [[1, 2, 3, 4],["Spring", "Summer", "Autumn", "Winter"],[1, 2.5, "hello", true, false, null]
    ]// JSON 数组嵌套 JSON 对象
    [{"name": "Tom","age": 18,"gender": "male"}{"name": "Lucy","age": 20,"gender": "female"}
    ]
    
1.2.2 JSON 对象
  • JSON 对象格式
    {"key1": value1,"key2": value2,"key3": value3
    }
    
  • JSON 对象内部使用键值对的方式来组织
    • 键和值之间使用冒号分隔,多个键值之间使用逗号分隔
    • 键是字符串类型,值的类型可以是:整型、浮点、字符串、布尔类型、JSON 数组、JSON 对象、空值
    {"name": "Tom","age": 18,"gender": "male"
    }
    
  • JSON 对象中,还可以嵌套 JSON 对象和 JSON 数组
    {"name": "China","info": {"capital": "beijing","asian": true,"founded": 1949},"provinces": [{"name": "hunan","capital": "changsha"}, {"name": "hubei","capital": "wuhan"}]
    }
    

1.3 JSON 在线解析

  • JSON 本质就是一种特殊格式的字符串
    • 实际工作中,这个 JSON 字符串可能是自己手写的,也可能是来自网络接收的数据
  • 下面的一段 JSON 字符串,它可能是自己写的,也可能是服务端返回的
    • 它是压缩的格式,也就是没有换行和缩进,不方便判断格式是否正确
    • 可以通过 JSON 在线解析工具来校验这个 JSON 的格式是否正确
    {"name":"China","info":{"capital":"beijing","asian":true,"founded":1949},"provinces":
    [{"name":"hunan","capital":"changsha"},{"name":"hubei","capital": "huhan"}]}
    

在这里插入图片描述

1.4 Qt 中使用 JSON

1.4.1 JSON 相关的类

(1)QJsonObject

  • QJsonObject 封装了 JSON 中的对象,可以存储多个键值对
    • 其中,键为字符串类型,值为 QJsonValue 类型
  • 创建一个 QJsonObject 对象
    QJsonObject::QJsonObject();
    
  • 将键值对添加到 QJsonObject 对象中
    QJsonObject::iterator insert(const QString &key, const QJsonValue &value);
    
  • 获取 QJsonObject 对象中键值对的个数
    int QJsonObject::count() const;
    int QJsonObject::size() const;
    int QJsonObject::length() const;
    
  • 通过 key 得到 value
    QJsonValue QJsonObject::value(const QString &key) const;
    QJsonValue QJsonObject::operator[](const QString &key) const;
    
  • 检查 key 是否存在
    iterator QJsonObject::find(const QString &key);
    bool QJsonObject::contains(const QString &key) const;
    
  • 遍历 key
    QStringList QJsonObject::keys() const;
    

(2)QJsonArray

  • QJsonArray 封装了 Json 中的数组,数组中元素类型统一为 QJsonValue 类型
  • 创建一个 QJsonArray
    QJsonArray::QJsonArray();
    
  • 添加数组元素
    // 添加到头部和尾部
    void QJsonArray::append(const QJsonValue &value);
    void QJsonArray::prepend(const QJsonValue &value);// 插入到 i 的位置之前
    void QJsonArray::insert(int i, const QJsonValue &value);// 添加到头部和尾部
    void QJsonArray::push_back(const QJsonValue &value);
    void QJsonArray::push_front(const QJsonValue &value);
    
  • 获取 QJsonArray 中元素个数
    int QJsonArray::count() const;
    int QJsonArray::size() const;
    
  • 获取元素的值
    // 获取头部和尾部
    QJsonValue QJsonArray::first() const;
    QJsonValue QJsonArray::last() const;// 获取指定位置
    QJsonValue QJsonArray::at(int i) const;
    QJsonValueRef QJsonArray::operator[](int i);
    
  • 删除元素
    // 删除头部和尾部
    void QJsonArray::pop_back();
    void QJsonArray::pop_front();void QJsonArray::removeFirst();
    void QJsonArray::removeLast();// 删除指定位置
    void QJsonArray::removeAt(int i);
    QJsonValue QJsonArray::takeAt(int i);
    

(3)QJsonValue

  • 封装了 JSON 支持的六种数据类型

    QJsonValue::Bool      // 布尔类型
    QJsonValue::Double    // 浮点(含整型)类型
    QJsonValue::String    // 字符串类型
    QJsonValue::Array     // Json 数组类型
    QJsonValue::Object    // Json 对象类型
    QJsonValue::Null      // 空值类型
    
  • 可以通过以下方式构造 QJsonValue 对象

    // 字符串
    QJsonValue(const char *s);
    QJsonValue(QLatin1String s);
    QJsonValue(const QString &s);// 整型 and 浮点型
    QJsonValue(qint64 v);
    QJsonValue(int v);
    QJsonValue(double v);// 布尔类型
    QJsonValue(bool b);// Json 对象
    QJsonValue(const QJsonObject &o);// Json 数组
    QJsonValue(const QJsonArray &a);// 空值类型
    QJsonValue(QJsonValue::Type type = Null);
    
  • 判断一个 QJsonValue 对象内部封装数据类型

    // 是否是字符串类型
    bool isString() const;// 是否是浮点类型(整形也是通过该函数判断)
    bool isDouble const;// 是否是布尔类型
    bool isBool() const;// 是否是Json对象
    bool isObject() const;// 是否是 Json 数组
    bool isArray() const;// 是否是未定义类型(无法识别的类型)
    bool isUndefined() const;// 是否是空值类型
    bool isNull() const;
    
  • 数据类型之间的转换 API 函数

    // 转换为字符串类型
    QString toString() const;
    QString toString(const QString &defaultValue) const;// 转换为浮点类型
    double toDouble(double defaultValue = 0) const;// 转换为整形
    int toInt(int defaultValue = 0) const;// 转换为布尔类型
    bool toBool(bool defaultValue = false) const;// 转换为 Json 对象
    QJsonObject toObject() const;
    QJsonObject toObject(const QJsonObject &defaultValue) const;// 转换为 Json 数组
    QJsonArray toArray() const;
    QJsonArray toArray(const QJsonArray &defaultValue) const;
    

(3)QJsonDocument

  • 它封装了一个完整的 JSON 文档

    • 它可以从 UTF-8 编码的基于文本的表示,以及 Qt 本身的二进制格式读取和写入该文档
    • QJsonObject 和 QJsonArray 不能直接转换为字符类型,需通过 QJsonDocument 来完成二者的转换
  • QJsonObject/QJsonArray ==> 字符串

    // 1. 创建 QJsonDocument 对象
    // 以 QJsonObject 或 QJsonArray 为参数来创建 QJsonDocument 对象
    QJsonDocument::QJsonDocument(const QJsonObject &object);
    QJsonDocument::QJsonDocument(const QJsonArray &array);// 2. 将 QJsonDocument 对象中的数据进行序列化
    // 通过调用 toXXX() 方法就可得到文本格式或者二进制格式的 Json 字符串
    QByteArray QJsonDocument::toBinaryData() const;         // 二进制格式的 json 字符串
    QByteArray QJsonDocument::toJson(JsonFormat format = Indented) const;  // 文本格式// 3. 使用得到的字符串进行数据传输,或者保存到文件
    
  • 字符串 ==> QJsonObject/QJsonArray

    • 通常,通过网络接收或者读取磁盘文件,会得到一个 JSON 格式的字符审,之后可以按照如下步骤,解析出 JSON 字符串中的一个个字段
    // 1. 将 JSON 字符串转换为 QJsonDocument 对象
    [static] QJsonDocument QJsonDocument::fromBinaryData(const QByteArray &data,DataValidation validation = Validate);
    [static] QJsonDocument QJsonDocument::fromJson(const QByteArray &json, QJsonParseError *error = Q_NULLPTR);// 2. 将文档对象转换为 json 数组 / 对象
    // 2.1 判断文档对象中存储的数据是 JSON 数组还是 JSON 对象
    bool QJsonDocument::isArray() const;
    bool QJsonDocument::isObject() const;// 2.2 转换为 JSON 数组或 JSON 对象
    QJsonObject QJsonDocument::object() const;
    QJsonArray QJsonDocument::array() const;// 3. 调用 QJsonArray / QJsonObject 类提供的 API 获取存储在其中的数据
    
1.4.2 构建 JSON 字符串
  • 在网络传输时,通常是传输的 JSON 字符串,传输之前,首先要生成 JSON 字符串
    • 接下来使用 Qt 提供的工具类,来生成如下格式的 JSON 字符串
    {"name": "China","info": {"capital": "beijing","asian": true,"founded": 1949},"provinces": [{"name": "hunan","capital": "changsha"}, {"name": "hubei","capital": "wuhan"}]
    }
    
  • 代码实现
    #include <QCoreApplication>#include <QJsonObject>
    #include <QJsonArray>
    #include <QJsonDocument>#include <QFile>
    #include <QByteArray>
    #include <QDebug>
    #include <QString>void writeJson() {QJsonObject rootObj;// 1. 插入 name 字段rootObj.insert("name", "China");// 2. 插入 info 字段QJsonObject infoObj;infoObj.insert("capital", "beijing");infoObj.insert("asian", true);infoObj.insert("founded", 1949);rootObj.insert("info", infoObj);// 3. 插入 provinces 字段QJsonArray provinceArray;QJsonObject hunanObj;hunanObj.insert("name", "hunan");hunanObj.insert("capital", "changsha");QJsonObject hubeiObj;hubeiObj.insert("name", "hubei");hubeiObj.insert("capital", "wuhan");provinceArray.append(hunanObj);provinceArray.append(hubeiObj);rootObj.insert("provinces", provinceArray);// 4. 将 QJsonObject 对象 rootObj 转换为 Json 字符串QJsonDocument doc(rootObj);QByteArray json = doc.toJson();// 5.1 打印输出qDebug() << QString(json).toUtf8().data();// 5.2 将 json 字符串写入文件QFile file("d:\\china.json");file.open(QFile::WriteOnly);file.write(json);file.close();
    }int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);writeJson();return a.exec();
    }
    
1.4.3 解析 JSON 字符串
  • 通常接收网络数据的格式是JSON 格式,在接收完毕之后,需要解析出其中的每一个字段,根据各个字段的值做相应的显示或者其他处理
#include <QCoreApplication>#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonValue>#include <QFile>
#include <QByteArray>
#include <QDebug>
#include <QString>
#include <QStringList>void fromJson() {// 1. 读取文件QFile file("d:\\china.json");file.open(QFile::ReadOnly);QByteArray json = file.readAll();file.close();QJsonDocument doc = QJsonDocument::fromJson(json);if (!doc.isObject()) {qDebug() << "Not an object!";return;}// 2. 开始解析QJsonObject obj = doc.object();QStringList keys = obj.keys();for (int i = 0; i < keys.size(); i++) {// 获取 key-value 对QString key = keys[i];QJsonValue value = obj.value(key);if (value.isBool()) {qDebug() << key << ":" << value.toBool();} else if (value.isString()) {qDebug() << key << ":" << value.toString();} else if (value.isDouble()) {qDebug() << key << ":" << value.toInt();} else if (value.isObject()) {qDebug() << key << ":";QJsonObject infoObj = value.toObject();QString capital = infoObj["capital"].toString();bool asian = infoObj["asian"].toBool();int founded = infoObj["founded"].toInt();qDebug() << " " << "capital" << capital;qDebug() << " " << "asian" << asian;qDebug() << " " << "founded" << founded;} else if (value.isArray()) {qDebug() << key;QJsonArray provinceArray = value.toArray();for (int i = 0; i < provinceArray.size(); i++) {QJsonObject provinceObj = provinceArray[i].toObject();QString name = provinceObj["name"].toString();QString capital = provinceObj["capital"].toString();qDebug() << " " << "name" << ":" << name << ", capital" << ":" << capital;}}}
}int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);fromJson();return a.exec();
}
  • 控制台输出
    "info" :capital "beijing"asian truefounded 1949
    "name" : "China"
    "provinces"name : "hunan" , capital : "changsha"name : "hubei" , capital : "wuhan"
    

2. HTTP 通信

2.1 HTTP 概述

HTTP:超文本传输协议 (HyperText Transfer Protocol),HTTP 是浏览器端 web 通信的基础

2.1.1 两种架构
  • B/S 架构:Browser/server,浏览器/服务器架构
    • B:浏览器,比如 Firefox、Internet Explorer、Google Chrome、Safari、Opera 等
    • S:服务器,比如 Apache、nginx 等
  • C/S 架构:client/server,客户端/服务器架构
    • B/S 架构相对于 C/S 架构,客户机上无需安装任何软件,使用浏览器即可访问服务器,因此,越来越多的 C/S 架构正被 B/S 架构所替代
2.1.2 基于请求响应的模式
  • HTTP 协议永远都是客户端发起请求,服务器做出响应
    • 也就是说,请求必定是先从客户端发起的,服务器端在没有接收到请求之前不会发送任何响应
    • 这就无法实现这样一种场景:服务端主动推送消息给客户端
2.1.3 无状态
  • 当浏览器第一次发送请求给服务器时,服务器做出了响应

  • 当浏览器第二次发送请求给服务器时,服务器同样可以做出响应,但服务器并不知道第二次的请求和第一次来自同一个浏览器

    • 也就是说,服务器不会记住你是谁,所以是无状态的
  • 而如果要使 HTTP 协议有状态,就可以使浏览器访问服务器时,加入 cookie,这样,只要你在请求时有了这个 cookie,服务器就能够通过 cookie 知道,你就是之前那个浏览器,这样,HTTP 协议就有状态了

2.1.4 请求保文

请求报文由四部分组成

  • 请求行 + 请求头(请求首部字段) + 空行 + 实体
  • 请求行

    • 请求方法:比如 GET、POST
    • 资源对象 (URL)
    • 协议名称和版本号 (HTTP/1.1)
      在这里插入图片描述
  • 请求头(请求首部字段)

    • 请求头用于告诉服务器该请求的一些信息,起到传递额外信息的目的
      在这里插入图片描述
  • 空行

    • 空行是为了区分请求头和请求实体
  • 请求实体

    • 请求实体即真正所需要传输的数据
2.1.5 响应保文

响应报文同样是由四部分组成

  • 状态行 + 响应头(响应报文首部) + 空行 + 消息体
  • 状态行

    • HTTP 版本
    • 状态码 (表示相应的结果)
    • 原因短语 (解释)
      在这里插入图片描述
  • 响应头(响应报文首部)

    • 和请求报文首部一样,响应报文首部同样是为了传递额外信息
      在这里插入图片描述
  • 空行

    • 同样是为了区别响应实体和响应首部
  • 响应实体

    • 真正存储响应信息的部分
2.1.6 请求方式
  • HTTP 常用的请求方式有很多中,最常用的是 GET 和 POST
  • 二者最主要的区别就是
    • GET 请求的参数位于 URL 中,会显示在地址栏上
    • POST 请求的参数位于 request body 请求体中

因此,GET 请求的安全性不如 POST 请求,并且 GET 请求的参数有长度限制,而 POST 没有

2.2 调试利器 Postman

  • HTTP 包含客户端和服务端,试想下面的两种情况(Postman 使用场景
    • 服务端开发完毕,而客户端还未完成开发,此时服务端开发人员能否对自己写的服务端程序进行测试呢?
    • 客户端开发人员访问服务端出错,比如无法访问服务端,有没有第三方的测试工具做进一步验证呢?
  • Postman 是一个接口测试工具,主要是用来模拟各种 HTTP 请求 (比如 GET 请求、POST 请求等),在做接口测试的时候,Postman 相当于客户端,它可模拟用户发起的各类 HTTP 请求,将请求数据发送至服务端,并获取对应的响应结果
2.2.1 安装
  • Postman 下载
2.2.2 发送请求
  • 这里以获取北京的天气为例
    • 获取北京天气的 URL 为:http://t.weather.itboy.net/api/weather/city/101010100
    • 其中,101010100 是北京的城市编码,是 9 位的

在这里插入图片描述

2.3 Qt 实现 HTTP 请求

2.3.1 创建 “网络访问管理” 对象
  • 首先需要创建一个 QNetworkAccessManager 对象,这是 Qt 中进行 HTTP 请求的开端
    mNetAccessManager = new QNetworkAccessManager(this);
    
2.3.2 关联信号槽
  • 在发送 HTTP 请求之前,先关联信号槽
    // 获取到数据之后
    connect(mNetAccessManager, &QNetworkAccessManager::finished, this, &MainWindow::onReplied);
    
2.3.3 发送请求
  • 根据请求的地址构建出一个 Qurl 对象,然后直接调用 QNetworkAccessManager 的 get 方法,即可发送一个 GET 请求
    Qurl ur1("http://t.weather.itboy.net/api/weather/city/101010100");
    mNetAccessManager->get(QNetworkRequest(url));
    
2.3.4 接收数据
  • 由于上面绑定了信号槽,服务器返回数据后,自动调用自定义的槽函数 onReplied
    • 如下是 onReplied 函数的标准写法,QNetworkReply 中封装了服务器返回的所有数据,包括响应头、响应的状态码、响应体等
    void MainWindow::onReplied(QNetworkReply *reply) {// 响应的状态码为200,表示请求成功int status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();qDebug() << "operation:" << reply->operation();          // 请求方式qDebug() << "status code:" << status_code;             // 状态码qDebug() << "url:" << reply->url();                    // urlqDebug() << "raw header:" << reply->rawHeaderList();   // headerif (reply->error() != QNetworkReply::NoError || status_code != 200) {QMessageBox::warning(this, "提示", "请求数据失败!", QMessageBox::OK);} else {// 获取响应信息QByteArray reply_data = reply->readAll();QByteArray byteArray = QString(reply_data).toUtf8();qDebug() << "read all:" << byteArray.data();// parseJson()}reply->deleteLater();
    }
    

3. 详细代码实现

  • WeatherForecast

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/231462.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3D场景建模工具

在线工具推荐&#xff1a; 三维数字孪生场景工具 - GLTF/GLB在线编辑器 - Three.js AI自动纹理化开发 - YOLO 虚幻合成数据生成器 - 3D模型在线转换 - 3D模型预览图生成服务 1. 什么是3D场景建模&#xff1f; 3D场景建模是一种通过计算机图形学技术&#xff0c;将现实世…

Day13 qt 高级控件,自定义控件,事件,绘图,定时器

高级控件 QListWidget 列表展示控件 效果 添加数据 ui->listWidget->addItem("A"); QStringList list; list << "B" << "C" << "D"; ui->listWidget->addItems(list); 设置item点击 void Widget::on_l…

Java后端开发——SpringMVC商品管理程序

Java后端开发——SpringMVC商品管理程序 今日目标 Spring MVC框架介绍掌握SpringMVC的核心类的原理及配置掌握SpringMVC的常用注解掌握SpringMVC的增删改查编程 Spring MVC框架介绍 Spring MVC&#xff08;Model-View-Controller&#xff09;是一个基于Java的开源框架&#x…

详解原生Spring当中的额外功能开发MethodBeforeAdvice与MethodInterceptor接口!

&#x1f609;&#x1f609; 学习交流群&#xff1a; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 &#x1f96d;&#x1f96d;3&#xff1a;QQ群&#xff1a;583783…

linux 磁盘扩容初始化挂载 笔记

目录 说明环境信息前提条件 操作步骤 说明 linux 系统磁盘扩容步骤 环境信息 系统信息&#xff1a;Linux version 4.19.90-23.8.v2101.ky10.aarch64cpu信息&#xff1a;Kunpeng-920 、aarch64、64-bit、HiSilicon 前提条件 有未初始化的用户磁盘操作系统可以支持当前磁盘的…

如何快速生成项目目录结构树?

经常在网上看到下面这种由一个项目&#xff0c;生成一个结构树&#xff0c;你知道它是怎么生成的吗&#xff1f; 这就是利用本文要介绍的一个工具——Treer&#xff0c;treer就是一款专门用来快速生成目录结构树的命令行工具。 第一步&#xff1a;安装treer 在终端执行全局…

前端编码规范

文章目录 一、背景二、内容1、注释规范&#xff08;1&#xff09;文件注释&#xff08;2&#xff09;函数注释&#xff08;3&#xff09;单行注释&#xff08;3&#xff09;多行注释 2、命名规范&#xff08;1&#xff09;项目命名&#xff08;2&#xff09;目录命名&#xff0…

[ffmpeg] aac 音频编码

aac 介绍 aac 简单说就是音频的一种压缩编码器&#xff0c;相同音质下压缩比 mp3好&#xff0c;目前比较常用。 aac 编码支持的格式 aac 支持的 sample_fmts: 8 aac 支持的 samplerates: 96000 88200 64000 48000 44100 32000 24000 22050 16000 12000 11025 8000 7350 通…

uniapp开发小程序使用axios进行网络请求 uniapp 小程序调试

前言 本篇最好放到项目的【README.md】文件中,方便每次发布的时候检查纠错,毕竟好记性不如烂笔头。而且其他开发者帮忙修改bug、发布新版本的时候,只需要根据这个事项就能实现整个流程的提审发布,提高效率。 1、微信小程序配置 1.1、检查APPID是否正确 测试:wx--------…

Day45力扣打卡

打卡记录 无矛盾的最佳球队&#xff08;线性DP&#xff09; class Solution:def bestTeamScore(self, scores: List[int], ages: List[int]) -> int:n len(scores) nums sorted(zip(scores, ages))f sorted(scores)for i in range(n):for j in range(0, i):if nu…

jdk动态代理和CGLIBE代理

静态代理&#xff1a;由程序员创建或特定工具自动生成源代码&#xff0c;再对其编译。在程序运行前&#xff0c;代理类的.class文件就已经存在了。 动态代理&#xff1a;在程序运行时&#xff0c;运用反射机制动态创建而成。 使用jdk的反射机制&#xff0c;创建对象的能力&…

【Vulnhub靶机】lampiao--DirtyCow

文章目录 漏洞介绍简介原因类型版本危害 信息收集主机扫描端口扫描 漏洞探测漏洞利用权限提升nc文件传输编译 参考 靶机地址&#xff1a;lampiao 下载地址&#xff1a;Lampio: 1 漏洞介绍 简介 脏牛&#xff08;Dirty Cow&#xff09;是Linux内核的一个提权漏洞&#xff0c;…