QT:基于QT实现Boost搜索引擎客户端

发布于:2024-05-08 ⋅ 阅读:(32) ⋅ 点赞:(0)

写在前面

关于服务器

本项目使用的是一个仿mudou库one-thread-one-loop式并发服务器的组件,关于该组件的细节内容在下面的链接中:

仿mudou库one-thread-one-loop式并发服务器

自主实现Boost搜索引擎

开源仓库和项目上线

本项目已开源到下面链接下的仓库当中

search-engine-online

并且项目已经部署在了Linux服务器上,具体访问方式可以点击下面链接进行访问:

81.70.160.28:8081

其他文档说明

针对于日志的信息,我采用了之前写的一份利用可变参数实现日志的代码,具体链接如下

C++:可变参数实现日志系统

这是一篇使用QT框架来实现一个配套与Boost搜索引擎的客户端的制作文档

登录界面

主体设计思路

首先设计一个简单的登陆界面

并且给对应的按钮提供对应的槽函数,如果验证成功了,就直接跳转到一个主页面

验证登录

下面是对于验证登录的逻辑,由于是连接到数据库的,所以这里需要用到网络通信,一个大体的思路就是把账号和密码提取出来,然后通过网络传输过去,在后端进行分析,再返回来,这里直接使用QT框架现成的Http部分

void Login::on_pushButton_login_clicked()
{
    // 点击登录后先验证账号和密码
    // 把账号和密码提取出来
    const QString& username = ui->lineEdit_account->text();
    const QString& password = ui->lineEdit_passwd->text();
    sender(username, password);
}

void Login::sender(const QString &username, const QString &password)
{
    // 1. 获取到输入框中的 URL, 构造 QUrl 对象
    QUrl url(serverurl);

    // 2. 构造 HTTP 请求对象,并设置请求头
    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

    // 创建 JSON 文档并填充数据
    QJsonObject jsonObject;
    jsonObject["username"] = username;
    jsonObject["password"] = password;

    // 将 JSON 文档转换为 QByteArray
    QJsonDocument jsonDoc(jsonObject);
    QByteArray postData = jsonDoc.toJson();

    // 3. 发送 POST 请求(这次包含JSON数据主体)
    QNetworkReply* response = manager->post(request, postData);

    // 4. 通过信号槽来处理响应
    connect(response, &QNetworkReply::finished, this, [=]() {
        if (response->error() == QNetworkReply::NoError)
        {
            // 响应正确
            QString html(response->readAll());
            qDebug() << "Response:" << html;
            // 验证正确后跳转到对应界面
            QMessageBox box(QMessageBox::Information, "提示", "登录成功", QMessageBox::Ok, this);
            int ret = box.exec();
            if(ret == QMessageBox::Ok)
            {
                this->close();
                this->sig_mainwindow();
            }
        }
        else
        {
            // 响应出错
            QString error = response->errorString();
            qDebug() << "Error:" << error;
            qDebug() << "账号或密码错误";
            int ret = QMessageBox::information(this, "提示", "账号或密码输入错误, 是否重新登录", QMessageBox::Yes | QMessageBox::No);
            if(ret == QMessageBox::Yes)
                ui->lineEdit_passwd->clear();
            else
                this->close();
        }
        response->deleteLater();
    });
}

至于验证登录的逻辑,这里不显示,因为这是后端已经完成的部分

注册功能

void Login::on_pushButton_register_clicked()
{
    this->sig_register();
}

注册界面

这个界面也没什么好说的,和登录界面的逻辑基本一样,只是调用服务端的API即可

#include "register.h"
#include "ui_register.h"
#include <QMessageBox>
#include <QGridLayout>
#include <QString>
#include <QMessageBox>
#include <QJsonObject>
#include <QDebug>
#include <QJsonDocument>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>

const QString& serverreq = "http://62.234.180.244:8081/register";

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

    // 设置一下标题和图标
    this->setWindowTitle("注册");
    this->setWindowIcon(QIcon(QPixmap(":/imag/register.png")));

    // 实例化对象
    manager = new QNetworkAccessManager(this);
}

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

void Register::jump()
{
    this->show();
}

void Register::on_pushButton_register_clicked()
{
    // 点击注册后先验证账号和密码
    // 把账号和密码提取出来
    const QString& username = ui->lineEdit_account->text();
    const QString& password = ui->lineEdit_passwd->text();
    sender(username, password);
}

void Register::sender(const QString &username, const QString &password)
{
    // 1. 获取到输入框中的 URL, 构造 QUrl 对象
    QUrl url(serverreq);

    // 2. 构造 HTTP 请求对象,并设置请求头
    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

    // 创建 JSON 文档并填充数据
    QJsonObject jsonObject;
    jsonObject["username"] = username;
    jsonObject["password"] = password;

    // 将 JSON 文档转换为 QByteArray
    QJsonDocument jsonDoc(jsonObject);
    QByteArray postData = jsonDoc.toJson();

    // 3. 发送 POST 请求(这次包含JSON数据主体)
    QNetworkReply* response = manager->post(request, postData);

    // 4. 通过信号槽来处理响应
    connect(response, &QNetworkReply::finished, this, [=]() {
        if (response->error() == QNetworkReply::NoError)
        {
            // 响应正确
            QString html(response->readAll());
            qDebug() << "Response:" << html;
            // 验证正确后跳转到对应界面
            QMessageBox box(QMessageBox::Information, "提示", "注册成功", QMessageBox::Ok, this);
            int ret = box.exec();
            if(ret == QMessageBox::Ok)
            {
                this->close();
            }
        }
        else
        {
            // 响应出错
            QString error = response->errorString();
            qDebug() << "Error:" << error;
            qDebug() << "用户名重复!";
            int ret = QMessageBox::information(this, "提示", "用户名重复!是否重新注册", QMessageBox::Yes | QMessageBox::No);
            if(ret == QMessageBox::Yes)
                ui->lineEdit_passwd->clear();
            else
                this->close();
        }
        response->deleteLater();
    });
}

主体界面

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QGridLayout>
#include <QString>
#include <QMessageBox>
#include <QJsonObject>
#include <QDebug>
#include <QJsonDocument>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QUrlQuery>
#include <QJsonArray>

const QString& server_search = "http://62.234.180.244:8081/s";
const QString& server_hotwords = "http://62.234.180.244:8081/hotwords";

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

    // 设置一下标题和图标
    this->setWindowTitle("查找");
    this->setWindowIcon(QIcon(QPixmap(":/imag/search.png")));

    // 实例化对象
    manager = new QNetworkAccessManager(this);
}

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

void MainWindow::jump()
{
    this->show();
}

void MainWindow::on_pushButton_clicked()
{
    // 当点击搜索按钮时,要传递一个/s请求
    // 0. 获取到用户要搜索的关键字
    const QString& user_search = ui->lineEdit_search->text();
    // 1. 获取到输⼊框中的 URL, 构造 QUrl 对象
    QUrl url(server_search);
    // 2. 将用户搜索的关键字作为查询参数添加到URL中,构造 HTTP 请求对象
    QUrlQuery query;
    query.addQueryItem("word", user_search);
    url.setQuery(query);
    QNetworkRequest request(url);
    // 3. 发送 GET 请求
    QNetworkReply* response = manager->get(request);
    // 4. 通过信号槽来处理响应
    connect(response, &QNetworkReply::finished, this, [=]()
    {
        if (response->error() == QNetworkReply::NoError)
        {
            QString html(response->readAll());
            displaySearchResults(html);
        }
        else
        {
            ui->plainTextEdit->setPlainText(response->errorString());
        }
        response->deleteLater();
    });
    // 点击搜索的时候也把热词统计显示出来
    handle_hotwords();
}

void MainWindow::on_pushButton_2_clicked()
{
    handle_hotwords();
}

void MainWindow::handle_hotwords()
{
    // 当点击搜索按钮时,要传递一个/s请求
    // 1. 获取到输⼊框中的 URL, 构造 QUrl 对象
    QUrl url(server_hotwords);
    // 2. 将用户搜索的关键字作为查询参数添加到URL中,构造 HTTP 请求对象
    QNetworkRequest request(url);
    // 3. 发送 GET 请求
    QNetworkReply* response = manager->get(request);
    // 4. 通过信号槽来处理响应
    connect(response, &QNetworkReply::finished, this, [=]()
    {
        if (response->error() == QNetworkReply::NoError)
        {
            QString html(response->readAll());
            displayHotWords(html);
        }
        else
        {
            ui->plainTextEdit_2->setPlainText(response->errorString());
        }
        response->deleteLater();
    });
}

void MainWindow::displaySearchResults(const QString &jsonData)
{
    QJsonDocument doc = QJsonDocument::fromJson(jsonData.toUtf8());
    if (!doc.isArray())
    {
        ui->plainTextEdit->setPlainText("解析结果错误,不是有效的JSON数组");
        return;
    }

    QStringList formattedResults;
    const QJsonArray results = doc.array();
    for (const QJsonValue &result : results)
    {
        if (result.isObject())
        {
            const QJsonObject obj = result.toObject();
            QString title = obj["title"].toString();
            QString desc = obj["desc"].toString();
            QString url = obj["url"].toString();
            QString line = QString("%1\n%2\n%3\n").arg(title, desc, url);
            formattedResults.append(line);
            // formattedResults.append("\n");
        }
    }

    ui->plainTextEdit->setPlainText(formattedResults.join("\n"));
}

void MainWindow::displayHotWords(const QString &jsonData)
{
    QJsonDocument doc = QJsonDocument::fromJson(jsonData.toUtf8());
    if (!doc.isObject())
    {
        ui->plainTextEdit_2->setPlainText("解析结果错误,不是有效的JSON对象");
        return;
    }

    QJsonObject jsonObj = doc.object();
    if (!jsonObj.contains("hotWords") || !jsonObj["hotWords"].isArray())
    {
        ui->plainTextEdit_2->setPlainText("未找到或'hotWords'不是数组");
        return;
    }

    const QJsonArray hotWordsArray = jsonObj["hotWords"].toArray();
    QStringList formattedHotWords;

    for (const QJsonValue &wordObj : hotWordsArray)
    {
        if (wordObj.isObject())
        {
            QJsonObject word = wordObj.toObject();
            int count = word["count"].toInt();
            QString wordStr = word["word"].toString();
            QString line = QString("%1 :%2次\n").arg(wordStr, QString::number(count));
            formattedHotWords.append(line);
        }
    }

    // 添加分隔符或自定义样式后,设置到plainTextEdit中
    ui->plainTextEdit_2->setPlainText(formattedHotWords.join("\n"));
}

main函数中绑定槽函数

#include "mainwindow.h"
#include "login.h"
#include "register.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Login log;
    log.show();
    MainWindow mainwindow;
    Register registerPage; // 创建Register类的实例

    // 建立两个槽,一个跳转到mainwindow,一个跳转到register
    QObject::connect(&log, &Login::sig_mainwindow, &mainwindow, &MainWindow::jump);
    QObject::connect(&log, &Login::sig_register, &registerPage, &Register::jump); // 修正接收对象为registerPage实例

    return a.exec();
}