Qt ⑨ Http&JSON&数据库

Qt ⑨ Http&JSON&数据库

一、Http简单通信

Qt 中 HTTP 通信主要通过 QNetworkAccessManager(请求管理)、QNetworkRequest(请求配置)、QNetworkReply(响应处理)三个核心类实现

核心流程:通过 QNetworkRequest 配置请求(URL、头信息等),由 QNetworkAccessManager 发送请求(get/post 等),返回 QNetworkReply 对象,通过其信号 / 函数处理响应数据、进度和错误。

1、QNetworkAccessManager类

类型 名称 / 函数 说明
QNetworkAccessManager 函数 get(request) 发送 HTTP GET 请求(参数为 QNetworkRequest 对象)
post(request, data) 发送 HTTP POST 请求(data 为请求体,如表单数据)
put(request, data) 发送 HTTP PUT 请求
deleteResource(request) 发送 HTTP DELETE 请求
head(request) 发送 HTTP HEAD 请求(仅获取响应头)
信号 finished(reply) 任意请求完成时触发(reply 为对应的 QNetworkReply 对象)
sslErrors(reply, errors) HTTPS 请求出现 SSL 错误时触发(需处理否则请求失败)
networkAccessibleChanged(accessible) 网络可达性变化时触发(如断网 / 联网)

2、QNetworkRequest类

类型 名称 / 函数 说明
QNetworkRequest 函数 setUrl(url) 设置请求的 URL(如 QUrl ("https://example.com"))
setHeader(header, value) 设置请求头(如 Content-Type、User-Agent,header 为 QNetworkRequest::KnownHeaders)
setRawHeader(name, value) 设置自定义请求头(name 为头字段名,如 "X-Custom-Header")
setTransferTimeout(msecs) 设置请求超时时间(毫秒)

3、QNetworkReply类

类型 名称 / 函数 说明
QNetworkReply 函数 readAll() 读取响应的全部数据(返回 QByteArray)
read(maxSize) 读取最多 maxSize 字节的响应数据
abort() 终止当前请求
error() 返回错误类型(QNetworkReply::NetworkError)
errorString() 返回错误描述字符串(如 “连接超时”)
header(header) 获取响应头(如 Content-Length、Content-Type)
信号 readyRead() 响应有新数据可读时触发(需调用 read/readAll 读取)
finished() 当前请求完成时触发(成功或失败均会触发)
downloadProgress(bytesReceived, bytesTotal) 下载进度更新时触发(bytesTotal 为总大小,-1 表示未知)
uploadProgress(bytesSent, bytesTotal) 上传进度更新时触发(适用于 POST/PUT 等带请求体的操作)
errorOccurred(error) 当前请求发生错误时触发

4、简单示例

#include "widget.h"
#include "ui_widget.h"

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

    manager = new QNetworkAccessManager(this);

    //1、网页回复数据会触发 Manager类的finished信号
    connect(manager,&QNetworkAccessManager::finished,this,
            QOverload<QNetworkReply *>::of(&Widget::netReply));
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    QString url = ui->lineEdit->text();         //获取网址

    QNetworkRequest request;                    //构造网址管理类对象
    request.setUrl(QUrl(url));                  //设置管理url网址

    //post(request,data);                       //请求远端服务器,并向服务器传输数据
    //get(request);                             //只请求远端服务器,不会向服务器传输数据
    //manager->post(request,nullptr);
    //manager->get(request);

    reply = manager->get(request);
    //2、网页回复数据会触发 Reply类 finished信号
    //connect(reply , &QNetworkReply::finished , this , &Widget::netReply);

    //3、发起请求,阻塞等待网页回复数据
    QEventLoop loop;
    //自动类型 c  获取信号与槽绑定信息
    auto c = connect(reply , &QNetworkReply::finished , this ,[&](){
        loop.exit();
    });
    //事件循环等待(阻塞),循环中可处理其他事件
    loop.exec();
    //解除信号与槽的绑定
    disconnect(c);
    QByteArray data = reply->readAll();
    qDebug() << data;
}


void Widget::netReply()
{
    //读取网页回复的所有相应信息
    QByteArray data = reply->readAll();
    ui->textEdit->append(data);
}

void Widget::netReply(QNetworkReply *reply)
{
    QByteArray data = reply->readAll();
    qDebug() << data;
    //ui->textEdit->append(data);
}


alt

二、Http在Qt的应用——JSON

1、JSON的介绍

JSON(JavaScript Object Notation,JavaScript 对象表示法)是一种轻量级的文本数据交换格式,核心特点是易读、易解析、跨语言兼容,专为简化数据传输和存储设计。

1. 核心作用

  • 数据交换:作为不同系统 / 语言间的 “数据桥梁”,比如前端(JS)与后端(Java/Python)、客户端(APP)与服务器之间传递数据,避免因语言差异导致的格式不兼容。
  • 数据存储:用于存储简单配置或结构化数据(如 APP 的用户设置、小型数据集),比 XML 更简洁,比纯文本更易解析。

2. 常见使用场景

  • 前后端通信:网页 / 小程序通过 API 获取后端数据时,后端常返回 JSON 格式(如用户信息、商品列表),前端直接解析使用。
  • API 接口数据格式:绝大多数公开 API(如天气 API、支付接口)都以 JSON 返回数据(例:调用天气 API 获取 “温度、城市” 等结构化信息)。
  • 配置文件:替代复杂的 XML,用于程序配置(如前端项目的package.json、APP 的主题 / 功能开关配置)。
  • 跨平台数据传输:如移动端(Android/iOS)与服务器、不同编程语言的服务(Python 后端与 Go 服务)之间传递数据。

3. 简单格式(2 种核心结构)

JSON 语法基于 “键值对” 和 “数组”,仅支持 6 种值类型:字符串(双引号包裹)、数字、布尔(true/false)、null、对象、数组。

(1)对象结构(最常用)

{} 包裹,内部是 “键:值” 对(键必须用双引号,值按类型定义),键值对间用逗号分隔。

例子(表示一个用户信息):

{
  "name": "张三",    // 字符串值
  "age": 25,        // 数字值
  "isStudent": false,// 布尔值
  "address": {      // 嵌套对象(值为对象)
    "city": "北京",
    "street": "XX路"
  },
  "hobbies": ["篮球", "编程"] // 嵌套数组(值为数组)
}
(2)数组结构

[] 包裹,内部是多个值(值类型可混合),元素间用逗号分隔。

例子(表示多个用户列表):

[
  {"name": "张三", "age": 25},
  {"name": "李四", "age": 30},
  {"name": "王五", "age": 28}
]

Qt 中处理 JSON 数据的核心类集中在 QJson 模块,主要包括 QJsonDocumentQJsonObjectQJsonArrayQJsonValue,它们的常用函数及作用如下:

2、QJsonDocument类

​ 该类主要用来解析从Http接收的响应JSON,将接收到的JSON数据解析为QJsonDocument对象,之后再根据需求做相应的数据处理

类型 函数 / 方法 说明
QJsonDocument 函数 fromJson(const QByteArray &data) 从 JSON 格式的字节数组(data)解析出 QJsonDocument 对象(解析失败时 isValid() 返回 false
toJson(Format format = Indented) 将文档转换为 JSON 字符串(Indented 为缩进格式,Compact 为紧凑格式)
object() 获取文档中包含的 QJsonObject(若文档是对象类型)
array() 获取文档中包含的 QJsonArray(若文档是数组类型)
setObject(const QJsonObject &obj) 设置文档内容为 QJsonObject
setArray(const QJsonArray &arr) 设置文档内容为 QJsonArray
isValid() 判断文档是否有效(解析成功)

3、QJsonObject类

​ 由JSON数据所组成的对象类,按照键值来组成对象的成员和成员的值

类型 函数 / 方法 说明
QJsonObject 函数 contains(const QString &key) 判断是否包含指定键(key
value(const QString &key) 获取指定键对应的 QJsonValue(键不存在时返回 QJsonValue::Null
insert(const QString &key, const QJsonValue &value) 插入 / 修改键值对(key 为键,value 为值)
remove(const QString &key) 删除指定键值对
keys() 返回所有键的列表(QStringList
isEmpty() 判断对象是否为空(无键值对)

4、QJsonArray

​ 从字面意思就能理解,这是Json数据的数组,数组内可以包含由JSON数据组成的多个JSON对象

类型 函数 / 方法 说明
QJsonArray 函数 size() 返回数组元素个数
append(const QJsonValue &value) 在数组末尾添加元素(valueQJsonValue 类型)
at(int i) 获取索引 i 处的元素(QJsonValue
replace(int i, const QJsonValue &value) 替换索引 i 处的元素
removeAt(int i) 删除索引 i 处的元素
isEmpty() 判断数组是否为空

5、QJsonValue

​ 该类是将QJsonObject对象中的各个成员提取出来,并转换为C语言的基础类型,方便数据处理等操作

类型 函数 / 方法 说明
QJsonValue 函数 type() 返回值类型(Null/Bool/Double/String/Object/Array
toBool(bool defaultValue = false) 转换为布尔值(类型不匹配时返回默认值)
toInt(int defaultValue = 0) 转换为整数(类型不匹配时返回默认值)
toString(const QString &defaultValue = QString()) 转换为字符串(类型不匹配时返回默认值)
toObject() 转换为 QJsonObject(类型不匹配时返回空对象)
toArray() 转换为 QJsonArray(类型不匹配时返回空数组)
isNull() 判断是否为 null

三、基于某天气API的JSON使用示例

1、API的JSON通信格式

参数名 必选 类型 说明 备注(示例)
appid string 用户appid 注册开发账号
appsecret string 用户appsecret
adcode string 国家统计局城市ID 如:130200000000 请参考 全国统计用区划代码表
cityid string 城市ID 请参考 城市ID列表
city string 城市名称 不要带市和区; 如: 青岛、铁西
province string 所在省 如果您担心city重名可传此参数, 不要带省和市; 如: 山东、上海
ip string IP地址 查询IP所在城市天气
lng String 经度 如: 119.545023 (免费使用,无需额外开通)
lat String 纬度 如: 36.044254
point String 坐标体系 默认百度坐标, 如使用高德坐标, 请传参: gaode
hours Int 小时天气 默认隐藏, 如需显示, 请传参: 1
aqi Int AQI六因子 默认隐藏, 如需显示, 请传参: 1
callback string jsonp参数 如: jQuery.Callbacks
vue string 跨域参数 如果您使用的是react、vue、angular请填写值: 1

2、源代码

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    manager = new QNetworkAccessManager(this);
    connect(manager , &QNetworkAccessManager::finished , this , &Widget::recvData);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    QString url = QString("http://gfeljm.tianqiapi.com/free/v2030?city=%1&cityid=&adcode=&appid=97396659&appsecret=9mFRUOLP&lng=&lat=&aqi=&hours=1")
                      .arg(ui->lineEdit->text());

    QNetworkRequest request;
    request.setUrl(url);

    manager->get(request);
}


void Widget::recvData(QNetworkReply *reply)
{
    QByteArray data = reply->readAll();
    //qDebug() << data;
    //fromJson : 将Json文本字符串转换为文档类型      object() : 将json文档转为JsonObject对象
    QJsonObject root = QJsonDocument::fromJson(data).object();
    //json数组
    QJsonArray arr = root.value("hours").toArray();
    //城市天气
    ui->textEdit->append("城市: " + root.value("city").toString());
    ui->textEdit->append("时间: " + root.value("date").toString() + " : " + root.value("update_time").toString() + " : " + root.value("week").toString());
    ui->textEdit->append("天气: " + root.value("wea_day").toString());
    ui->textEdit->append("24小时天气情况: ");

    //遍历json数组
    foreach (QJsonValue val, arr) {
        QJsonObject obj = val.toObject();
        ui->textEdit->append(QString("时间: %1    天气: %2    温度: %3")
                                 .arg(obj.value("hours").toString())
                                 .arg(obj.value("wea").toString())
                                 .arg(obj.value("tem").toString())
                             );
        ui->textEdit->append(QString("空气: %1    风向: %2    风速: %3")
                                 .arg(obj.value("aqi").toString())
                                 .arg(obj.value("win").toString())
                                 .arg(obj.value("win_speed").toString())
                             );
        ui->textEdit->append("========================");
    }
}


3、运行结果

alt

四、Qt中数据库的使用

1、示例代码

#include "widget.h"
#include "ui_widget.h"

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

    //获取支持驱动集合
    //QStringList list = QSqlDatabase::drivers();
    //qDebug() << list;

    //1、添加数据库(参数1 : 数据库类型名 参数2 : 数据库连接名)
    db = QSqlDatabase::addDatabase("QSQLITE");

    // //2、设置远程数据库服务器地址、端口、用户名、密码
    // db.setHostName("192.168.6.39");       //主机
    // db.setPort(3306);                     //端口号
    // db.setUserName("root");               //用户名
    // db.setPassword("123456");             //密码

    //3、设置数据库文件名
    db.setDatabaseName("./test.db");
    if(!db.isOpen())
    {
        //4、打开数据库
        if(!db.open())
        {
            QMessageBox::critical(this,"错误",QString("数据库打开失败:"+db.lastError().text()));
            //关闭程序
            exit(-1);
        }
    }
    //5、数据库表的创建
    QString sql = "create table if not exists user("
                  "name string,"
                  "sex string,"
                  "number string unique,"
                  "age int)";
    //6、构造query
    QSqlQuery query;
    //query.prepare(sql);
    //7、执行sql语句
    if(!query.exec(sql))
    {
        QMessageBox::critical(this,"错误",QString("创建表失败:"+db.lastError().text()));
    }
}

Widget::~Widget()
{
    delete ui;
}

//新增
void Widget::on_btn_add_clicked()
{
    QString sql = QString("insert into user values('%1','%2','%3',%4);")
                      .arg(ui->lineEdit_name->text())
                      .arg(ui->lineEdit_gender->text())
                      .arg(ui->lineEdit_id->text())
                      .arg(ui->lineEdit_age->text().toInt());
    QSqlQuery query;
    if(!query.exec(sql)){
        QMessageBox::critical(this,"错误",QString("操作失败:"+db.lastError().text()));
        return;
    }
    QMessageBox::information(this,"信息","插入成功");
}


//查询
void Widget::on_btn_selete_clicked()
{
    QString sql = "select count(*) from user;";
    QSqlQuery query;
    if(!query.exec(sql)){
        QMessageBox::critical(this,"错误",QString("操作失败:"+db.lastError().text()));
        return;
    }
    //record() : 获取本条记录 count() : 获取字段个数
    //qDebug() << query.record().count();

    //行数
    query.next();
    int rows = query.record().value(0).toInt();
    qDebug() << rows;

    sql = "select * from user;";
    if(!query.exec(sql)){
        QMessageBox::critical(this,"错误",QString("操作失败:"+db.lastError().text()));
        return;
    }
    //列数
    int cols = query.record().count();

    ui->tableWidget->setRowCount(rows);
    ui->tableWidget->setColumnCount(cols);

    //表头设置
    QStringList list;
    for(int i = 0 ; i < cols ; i++)
    {
        list.append(query.record().fieldName(i));
    }
    ui->tableWidget->setHorizontalHeaderLabels(list);


    //query.next()  表示下一条记录
    //.value("xxx")表示获取xxx字段的数据
    for(int i = 0 ; i < rows ; i++)
    {
        query.next();
        for(int j = 0 ; j < cols ; j++)
        {
            QTableWidgetItem *item = new QTableWidgetItem(query.record().value(j).toString());
            ui->tableWidget->setItem(i,j,item);
        }
    }
}
//右键菜单  (上下文事务处理)
// void Widget::contextMenuEvent(QContextMenuEvent *e)
// {
//     //QMenu *menu = new QMenu();
// }


运行结果

alt

全部评论

相关推荐

03-16 11:07
南开大学 Java
牛马人的牛马人生:快手卡实习经历的
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务