当前位置: 首页 > article >正文

QT聊天项目DAY14

1. 客户端登录

1.1 初始化玩家头像

将头像的大小固定在250 * 250

void InitHeadImage();																			// 初始化头像/* 初始化头像 */
void LoginWidget::InitHeadImage()
{// 加载头像QPixmap OriginalPixmap(":/Chat/Images/head_5.jpg");OriginalPixmap = OriginalPixmap.scaled(ui.Head_Label->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);// 绘制圆形头像QPixmap RoundPixmap(ui.Head_Label->size());RoundPixmap.fill(Qt::transparent);														// 用透明色填充QPainter painter(&RoundPixmap);painter.setRenderHint(QPainter::Antialiasing);											// 抗锯齿painter.setRenderHint(QPainter::SmoothPixmapTransform);									// 平滑缩放// 使用QPainterPath设置圆角QPainterPath path;path.addRoundedRect(0, 0, ui.Head_Label->width(), ui.Head_Label->height(), 10, 10);painter.setClipPath(path);// 将原始图片绘制到圆形头像上painter.drawPixmap(0, 0, OriginalPixmap);// 设置头像ui.Head_Label->setPixmap(RoundPixmap);
}

1.2 登录界面新增err_Tip

设置成水平居中,并且最大最小高度为25

添加文本刷新Function

void ShowTipLabel(const QString& tip, const QString& State);									// 显示提示信息
void AddTipErr(TipErr err, const QString& tips);												// 添加错误提示
void DelTipErr(TipErr err);																		// 清除错误提示QMap<TipErr, QString> _TipErrs;																	// 错误提示记录
#include "Global.h"
ui.Tip_Label->clear();/* 刷新文本提示标签的样式 */
void LoginWidget::ShowTipLabel(const QString& tip, const QString& State)
{ui.Tip_Label->setText(tip);ui.Tip_Label->setProperty("state", State);repolish(ui.Tip_Label);
}/* 添加错误提示 */
void LoginWidget::AddTipErr(TipErr err, const QString& tips)
{_TipErrs[err] = tips;ShowTipLabel(tips, "error");
}/* 删除错误提示 */
void LoginWidget::DelTipErr(TipErr err)
{_TipErrs.remove(err);if (_TipErrs.isEmpty()){ui.Tip_Label->clear();return;}ShowTipLabel(_TipErrs.first(), "error");
}

1.3 添加控制密码是否可见的标签

添加标签控件,将该标签提升为clickedLabel,重定义名称为PassWord_Visible并设置固定大小为20 * 20;

为标签设置样式

/* 初始化可视化控件 */
ui.PassWord_Visible->SetState("unvisible", "unvisible_hover", "", "visible","visible_hover", "");/* 密码可见性 */
connect(ui.PassWord_Visible, &ClickedLabel::clicked, this, [this](){auto state = ui.PassWord_Visible->GetState();if (state == ClickLabelState::Normal){ui.PassWord_Edit->setEchoMode(QLineEdit::Password);}else if (state == ClickLabelState::Selected){ui.PassWord_Edit->setEchoMode(QLineEdit::Normal);}});

1.4 登陆验证

点击登录需要发送http请求到GateServer,GateServer先验证登录密码,在调用grpc请求StatusServer,获取聊天服务器ip信息和token信息反馈给客户端

1.4.1 添加登录按钮的槽函数

1. 检查用户名输入以及密码输入是否有问题

bool CheckUserValid();																			// 检查用户名是否合法
bool CheckPasswordValid();																		// 检查密码是否合法
/* 检查用户名是否合法 */
bool LoginWidget::CheckUserValid()
{if (ui.User_Edit->text().isEmpty()){AddTipErr(TipErr::TIP_USER_ERR, QString::fromLocal8Bit("用户名不能为空"));return false;}/* 一切正常则删除错误提示 */DelTipErr(TipErr::TIP_USER_ERR);return true;
}/* 检验密码是否合法 */
bool LoginWidget::CheckPasswordValid()
{QString passText = ui.PassWord_Edit->text();if (passText.length() < 6 || passText.length() > 15){AddTipErr(TipErr::TIP_PWD_ERR, QString::fromLocal8Bit("密码长度必须在6-15位之间"));return false;}/* 密码长度至少6位 可以是字母、数字、特定的特殊字符 */QRegularExpression regExp("^[a-zA-Z0-9!@#$%^&*]{6,15}$");bool match = regExp.match(passText).hasMatch();if (!match){AddTipErr(TipErr::TIP_PWD_ERR, QString::fromLocal8Bit("不能包含非法字符"));return false;}/* 一切正常则删除错误提示 */DelTipErr(TipErr::TIP_PWD_ERR);return true;
}

2. 实现槽函数逻辑

enum ReqID
{ID_GET_VARIFY_CODE = 1001,			// 获取验证码ID_REG_USER		   = 1002,			// 注册用户ID_RESET_PWD       = 1003,          // 重置密码ID_LOGIN_USER      = 1004,          // 登录用户
};enum Modules
{REGISTERMOD		   = 0,				// 注册模块LOGINMOD		   = 1,				// 登录模块
};[GateServer]
host=localhost
port=8080
getVerifycode=getVarifycode
RegisterUser=RegisterUser
ResetUserPassword=ResetUserPassword
LoginUser=LoginUser/* 登录按钮点击时 */
void LoginWidget::OnLoginButtonClicked()
{if (!CheckUserValid())return;if (!CheckPasswordValid())return;QString user = ui.User_Edit->text();QString pass = ui.PassWord_Edit->text();// 发送http请求QJsonObject json;json["user"] = user;json["password"] = xorString(pass);// 创建URLQString urlStr = "http://" +ConfigSettings->value("GateServer/host").toString() + ":"+ ConfigSettings->value("GateServer/port").toString() + "//"+ ConfigSettings->value("GateServer/LoginUser").toString();QUrl url(urlStr);HttpManager::Instance()->PostHttpReq(url, json, ReqID::ID_LOGIN_USER, Modules::LOGINMOD);
}

1.4.2 处理客户端发来的响应

1. 添加对应ReqId的回调

Struct.h

#ifndef STRUCT_H
#define STRUCT_H#include <QString>/* 服务器信息 */
struct ServerInfo {QString Host;QString Port;QString Token;int Uid;
};#endif // STRUCT_H
void sig_connect_tcp(ServerInfo serverInfo);													// 连接聊天服务器void InitHttpHandlers();																		// 设置网络回包的回调函数QMap<ReqID, std::function<void(const QJsonObject&)>> _handlers;									// 不同类型的回调函数/* 网络回包的处理函数 */
void LoginWidget::InitHttpHandlers()
{// 注册获取验证码回包的逻辑_handlers.insert(ReqID::ID_LOGIN_USER, [this](const QJsonObject& jsonObj){int error = jsonObj["error"].toInt();if (error != ErrorCodes::SUCCESS){ShowTipLabel(QString::fromLocal8Bit("参数错误"), "error");return;}auto email = jsonObj["email"].toString();// 发送信号通知TcpMgr发送长链接ServerInfo serverInfo;serverInfo.Uid = jsonObj["uid"].toInt();serverInfo.Host = jsonObj["host"].toString();serverInfo.Port = jsonObj["port"].toInt();serverInfo.Token = jsonObj["token"].toString();_Uid = serverInfo.Uid;_Token = serverInfo.Token;emit sig_connect_tcp(serverInfo);ShowTipLabel(QString::fromLocal8Bit("登陆成功"), "normal");qDebug() << QString::fromLocal8Bit("登陆成功 user: ") << email;});
}

2. 实现处理服务器响应的槽函数

/* 服务器处理完登录请求回复的响应 */
void LoginWidget::slot_login_mod_finished(ReqID reqId, QString res, ErrorCodes errCode)
{if (errCode != ErrorCodes::SUCCESS) {ShowTipLabel(QString::fromLocal8Bit("网络请求错误"), "error");return;}QJsonDocument jsonDoc = QJsonDocument::fromJson(res.toUtf8());								// .json文件if (jsonDoc.isNull()){ShowTipLabel(QString::fromLocal8Bit("json 是空的"), "error");return;}// 解析json数据if (!jsonDoc.isObject()){ShowTipLabel(QString::fromLocal8Bit("json 格式不正确"), "error");return;}// 回调函数_handlers[reqId](jsonDoc.object());
}

客户端登录请求发送的模块封装完毕

2. 服务器处理登录请求

2.1 使用RAII思想来归还池式组件的连接

// RAII 归还连接
class ConnectionRAII
{
public:ConnectionRAII(function<void()> RetunConnection): m_RetunConnection(RetunConnection){}~ConnectionRAII(){m_RetunConnection();}private:function<void()> m_RetunConnection;
};

2.2 重新定义GRPC服务并编译

message.proto

syntax = "proto3";package message;service VerifyService {rpc GetVerifyCode (GetVerifyRequest) returns (GetVerifyRsponse) {}
}message GetVerifyRequest {string email = 1;
}message GetVerifyRsponse {int32 error = 1;string email = 2;string code = 3;
}message GetChatServerRequest {int32 uid = 1;
}message GetChatServerResponse {int32 error = 1;string host = 2;string port = 3;string token = 4;
}message LoginRequest {int32 uid = 1;string token = 2;
}message LoginResponse {int32 error = 1;int32 uid = 2;string token = 3;
}service StatusService {rpc GetChatServer (GetChatServerRequest) returns (GetChatServerResponse) {}rpc Login (LoginRequest) returns (LoginResponse) {}
}

编译生成新的通信文件

H:\BoostNetLib\grpc\visualpro\third_party\protobuf\Debug\protoc.exe  -I="." --grpc_out="." --plugin=protoc-gen-grpc="H:\BoostNetLib\grpc\visualpro\Debug\grpc_cpp_plugin.exe" "message.proto"

编译生成新的序列化和反序列化文件

H:\BoostNetLib\grpc\visualpro\third_party\protobuf\Debug\protoc.exe --cpp_out=. "message.proto"

2.3 创建StatusGrpcClient

#ifndef STATUSGRPCCLIENT_H
#define STATUSGRPCCLIENT_H
#include "Singletion.h"
#include "GlobalHead.h"
#include <grpcpp/grpcpp.h>
#include "message.grpc.pb.h"using grpc::Channel;
using grpc::Status;
using grpc::ClientContext;using message::GetChatServerRequest;
using message::GetChatServerResponse;
using message::StatusService;class StatusConPool
{
public:StatusConPool(int _PoolSize, string IP):PoolSize(_PoolSize), bStop(false){for (int i = 0; i < PoolSize; i++){StatusService::Stub* stub = new StatusService::Stub(grpc::CreateChannel(IP, grpc::InsecureChannelCredentials()));conPool.push(stub);}}~StatusConPool() {lock_guard<mutex> lock(mtx);bStop = true;cv.notify_all();for (int i = 0; i < PoolSize; i++){delete conPool.front();conPool.pop();}}StatusService::Stub* GetCon(){unique_lock<mutex> lock(mtx);cv.wait(lock, [this]() {return !conPool.empty() || bStop; });if(bStop)return nullptr;StatusService::Stub* stub = conPool.front();conPool.pop();return stub;}void ReturnCon(StatusService::Stub* _con){lock_guard<mutex> lock(mtx);if(bStop)return;conPool.push(_con);cv.notify_one();}private:int PoolSize;/* 锁相关 */atomic<bool> bStop;mutex mtx;condition_variable cv;/* 连接池 */queue<StatusService::Stub*> conPool;
};class StatusGrpcClient : public Singletion<StatusGrpcClient>
{friend class Singletion<StatusGrpcClient>;
public:~StatusGrpcClient() {}GetChatServerResponse GetChatServer(int uid);private:StatusGrpcClient();private:StatusConPool* conPool = nullptr;
};#endif // STATUSGRPCCLIENT_H
#include "StatusGrpcClient.h"
#include "ServerStatic.h"StatusGrpcClient::StatusGrpcClient()
{int Port = get<int>(ServerStatic::ParseConfig("StatusServer", "Port"));string Ip = "localhost:" + to_string(Port);conPool = new StatusConPool(5, Ip);
}GetChatServerResponse StatusGrpcClient::GetChatServer(int uid)
{/* 向GRPC服务端发送请求,获取聊天服务器信息 */ClientContext context;GetChatServerResponse response;GetChatServerRequest request;request.set_uid(uid);auto stub = conPool->GetCon();Status status = stub->GetChatServer(&context, request, &response);ConnectionRAII ConRAII([this,&stub](){conPool->ReturnCon(stub);});if (!status.ok())response.set_error(ErrorCodes::RPC_FAILED);return response;
}

修改Config.json

{"GateServer": {"Port": 8080},"VerifyServer": {"Port": 50051},"StatusServer": {"Port" : 50052},"Redis": {"Host": "127.0.0.1","Port": 6380,"Password": "123456"},"Mysql": {"Host": "127.0.0.1","Port": 3306,"Username": "root","Password": "123456","Database": "YjjChat"}
}

2.4 处理登陆请求

/* 用户登录 */
RegisterPost("/LoginUser", [](HttpConnection* connection){if (connection){auto bodyStr = boost::beast::buffers_to_string(connection->_request.body().data());	// 获取 Http请求体中的内容cout << "receive body is \n" << bodyStr << endl;connection->_response.set(http::field::content_type, "text/json");					// 设置 Http响应头中的 content-typeJson::Value jsonResonse;															// 响应用的JsonJson::Value jsonResult;																// 请求体解析出来的JsonJson::Reader reader;																// Json解析器bool parseSuccess = reader.parse(bodyStr, jsonResult);								// 将请求体解析为Jsonif (!parseSuccess){cout << "parse json failed" << endl;jsonResonse["error"] = ErrorCodes::ERROR_JSON;									// 设置响应的错误码string jsonStr = jsonResonse.toStyledString();beast::ostream(connection->_response.body()) << jsonStr;						// 向 Http响应体中写入错误码内容return;}UserInfo userInfo;/* 访问Mysql检查密码是否匹配 */bool bUpdatePassword = MySqlManage::GetInstance()->CheckPassword(jsonResult["user"].asString(), jsonResult["password"].asString(), userInfo);if (!bUpdatePassword){cout << "update password failed\n";jsonResonse["error"] = ErrorCodes::Update_Password_Failed;string jsonStr = jsonResonse.toStyledString();beast::ostream(connection->_response.body()) << jsonStr;return;}/* 查询StatusServer匹配对应的服务器 */GetChatServerResponse response = StatusGrpcClient::GetInstance()->GetChatServer(userInfo.uid);if (response.error()){cout << "grpc get chat server failed: error is " << response.error() << endl;jsonResonse["error"] = response.error();string jsonStr = jsonResonse.toStyledString();beast::ostream(connection->_response.body()) << jsonStr;return;}/* 返回响应报文给客户端 */cout << "succeed to load userinfo uid is " << userInfo.uid << endl;jsonResonse["error"] = 0;jsonResonse["user"] = jsonResult["user"];jsonResonse["password"] = jsonResult["password"];string jsonStr = jsonResonse.toStyledString();beast::ostream(connection->_response.body()) << jsonStr;							// 向 Http响应体中写入Json内容return;}else{std::cout << "connection is null" << std::endl;}});

3. 创建状态服务器

3.1 创建属性页

视图->其他窗口->属性管理器 之前的项目怎么配置的现在怎么配置就行了

将pdb文件添加到静态库文件夹下

此时还是有,这是因为原本的redis库中Win32库与别的库冲突,重新修改了一份redis

3.2 填充服务器

3.2.1. 将这些文件全都添加到项目中

3.2.2. 创建新的StatusServiceImpl类

#ifndef STATUS_SERVICE_IMPL_H
#define STATUS_SERVICE_IMPL_H
#include <string>
#include <grpcpp/grpcpp.h>
#include "message.grpc.pb.h"
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using message::GetChatServerRequest;
using message::GetChatServerResponse;
using message::StatusService;
using namespace std;struct ChatServer
{string Host;int Port;
};class StatusServiceImpl final : public StatusService::Service
{
public:StatusServiceImpl();Status GetChatServer(ServerContext* context, const GetChatServerRequest* request,GetChatServerResponse* response) override;private:string generate_unique_string();public:std::vector<ChatServer> _servers;int ServerIndex = 0;
};
#endif // STATUS_SERVICE_IMPL_H
#include "StatusServiceImpl.h"#include "ServerStatic.h"
#include <boost/beast/http.hpp>
#include <boost/beast.hpp>
#include <boost/asio.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>StatusServiceImpl::StatusServiceImpl():ServerIndex(0)
{ChatServer server1;string Host1 = get<string>(ServerStatic::ParseConfig("ChatServer1", "Host"));int Port1 = get<int>(ServerStatic::ParseConfig("ChatServer1", "Port"));server1.Host = Host1;server1.Port = Port1;ChatServer server2;string Host2 = get<string>(ServerStatic::ParseConfig("ChatServer2", "Host"));int Port2 = get<int>(ServerStatic::ParseConfig("ChatServer2", "Port"));server2.Host = Host2;server2.Port = Port2;_servers.push_back(server1);_servers.push_back(server2);
}Status StatusServiceImpl::GetChatServer(ServerContext* context, const GetChatServerRequest* request, GetChatServerResponse* response)
{ServerIndex = (ServerIndex + 1) % _servers.size();ChatServer server = _servers[ServerIndex];response->set_host(server.Host);response->set_port(to_string(server.Port));response->set_error(ErrorCodes::SUCCESS);string token = generate_unique_string();response->set_token(token);return Status::OK;
}string StatusServiceImpl::generate_unique_string()
{// 创建UUID对象boost::uuids::uuid uuid = boost::uuids::random_generator()();// 将UUID转换为字符串std::string unique_string = to_string(uuid);return unique_string;
}

4. C++中线程的使用方法

4.1 线程创建

#include <iostream>
#include <thread>
using namespace std;void Function()
{std::cout << "This is a thread function.\n";
}class HelloFunction
{
public:void operator()(){std::cout << "Hello, world!\n";}
};int main()
{//1. 普通函数thread t1(Function);t1.join();// 2.函数对象HelloFunction hello;thread t2(hello);t2.join();// 3.lambda表达式thread t3([]() {std::cout << "Hello, lambda!\n";});t3.join();return 0;
}

4.2 等待线程完成

使用join()成员函数来等待线程完成。如果不等待,则线程可能在主线程结束后仍然运行,导致未定义行为(除非将线程分离)

4.3 分离线程

使用detach()成员函数将线程与thread对象分离,这样线程将在后台独立运行,不再收到thread对象的控制;

4.4 传递参数

线程函数可以接受参数。参数默认以值传递方式传递,如果需要传递引用必须使用ref进行包装

#include <iostream>
#include <thread>
using namespace std;void Function(int a)
{a++;std::cout << "a = " << a << "\n";
}void RefFunction(int& a, int b)
{a += b;std::cout << "a = " << a << "\n";
}int main()
{// 1.值传递int a = 10;thread t1(Function, 10);t1.join();cout << "a = " << a << "\n";// 2.引用传递thread t2(RefFunction, std::ref(a), 5);t2.join();cout << "a = " << a << "\n";return 0;
}

5. 测试

5.1 逻辑梳理

1. 客户端登录

登录按钮点击时,发送Post请求,等待服务器的响应报文

2. 服务器监听客户端发来的Http

只关注Post请求,

处理登录请求时,先拆解出用户发来的用户名和密码,将用户信息(用户名,邮件,密码,uid)读取出来,利用用户的uid向StatusServer发送请求

3. StatusServer处理请求

监听端口号并添加服务(客户端发来对应请求的回调函数)

再创建一个事件循环对象来监听Crtl + C用来优雅退出,再后台线程中进行监听

服务(返回聊天服务器的IP地址和端口号)

登陆成功

添加打印日志查看StatusServer是否监听到发来的请求

测试成功!!!

6. Git管理

在项目中建立分支将所有的项目通过分支的形式去提交,不提交Master

拉取分支,创建空项目,复制URL,按照下面操作就能得到想要的分支的项目了

相关文章:

QT聊天项目DAY14

1. 客户端登录 1.1 初始化玩家头像 将头像的大小固定在250 * 250 void InitHeadImage(); // 初始化头像/* 初始化头像 */ void LoginWidget::InitHeadImage() {// 加载头像QPixmap OriginalPixmap(":/Chat/Images/head_5.jpg");OriginalPixmap …...

架构设计技巧——架构设计模板

一份实用、高效、覆盖核心要素的架构设计模板是确保设计质量、促进团队沟通和指导实施的关键。以下是一个经过提炼的架构设计文档核心模板框架&#xff0c;结合了业界最佳实践&#xff0c;并强调灵活裁剪&#xff1a; 架构设计文档模板 (核心框架) 文档标识 项目/系统名称&a…...

交易系统开发:跨境资本的高速通道架构解密

连接纽约、香港与内陆的金融管道工程 总收益互换&#xff08;TRS&#xff09;在港美股投资中扮演着跨境资本流动的“隐形桥梁”。本文基于真实跨境券商系统开发实践&#xff0c;深入解析支持多市场、多币种、多通道的TRS平台架构设计与业务解决方案。 一、港美股TRS的核心价值&…...

【Ragflow】27.RagflowPlus(v0.4.1):小版本迭代,问题修复与功能优化

概述 RagflowPlus v0.4.0 在发布后&#xff0c;收到了积极的反馈&#xff0c;同时也包含一些问题。 本次进行一轮小版本更新&#xff0c;发布 v0.4.1 版本&#xff0c;对已知问题进行修复&#xff0c;并对部分功能进行进一步优化。 开源地址&#xff1a;https://github.com/…...

易语言是什么?易语言能做什么?

易语言&#xff08;EPL&#xff09;是什么&#xff1f;​​ ​​易语言​​&#xff08;Easy Programming Language&#xff0c;简称EPL&#xff09;是一款​​面向中文用户的编程语言​​&#xff0c;由中国人吴涛于2000年开发&#xff0c;专为降低编程门槛设计。其核心特点是…...

【Oracle】数据仓库

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 数据仓库概述1.1 为什么需要数据仓库1.2 Oracle数据仓库架构1.3 Oracle数据仓库关键技术 2. 数据仓库建模2.1 维度建模基础2.2 星形模式设计2.3 雪花模式设计2.4 缓慢变化维度&#xff08;SCD&#xff09;处…...

基于开源AI大模型AI智能名片S2B2C商城小程序源码的中等平台型社交电商运营模式研究

摘要&#xff1a;本文聚焦中等平台型社交电商&#xff0c;探讨其与传统微商及大型社交电商平台的差异&#xff0c;尤其关注产品品类管理对代理运营的影响。通过引入开源AI大模型、AI智能名片与S2B2C商城小程序源码技术&#xff0c;构建智能化运营体系。研究结果表明&#xff0c…...

typeof运算符 +unll和undefined的区别

typeof运算符 JavaScript 有三种方法&#xff0c;可以确定一个值到底是什么类型。而我们 现在需要接触到的就是typeof 数值返回number 1 typeof 123 // "number" 字符串返回string 1 typeof 123 // "string" 布尔值返回boolean 1 typeof fal…...

Vite 双引擎架构 —— Esbuild 概念篇

Vite 底层采用 双引擎架构&#xff0c;核心构建引擎是 Esbuild 和 Rollup&#xff0c;二者在开发和生产环境中分工协作&#xff0c;共同实现高性能构建。不可否认&#xff0c;作为 Vite 的双引擎之一&#xff0c;Esbuild 在很多关键的构建阶段(如依赖预编译、TS 语法转译、代码…...

Life:Internship finding

1. 前言 fishwheel writes this Blog to 记录自分自身在研二下找实习的经历。When 写这篇 Blog 的时候我的最后一搏也挂掉了&#xff0c;只能启用保底方案了。When I 打开我的邮箱时&#xff0c;发现里面有 nearly 100 多封与之相关的邮件&#xff0c;顿时感到有些心凉&#x…...

阿里云Alibaba Cloud安装Docker与Docker compose【图文教程】

个人记录 进入控制台&#xff0c;找到定时与自动化任务 进入‘安装/卸载扩展程序’ 点击‘安装扩展程序’ 选择docker社区版&#xff0c;点击下一步与确定&#xff0c;等待一会 安装成功 查询版本 查询docker sudo docker version查询docker compose sudo docker compo…...

GitHub 趋势日报 (2025年06月07日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 603 netbird 459 dify 440 cognee 352 omni-tools 337 note-gen 239 ragbits 237 …...

Java编程之组合模式

引言 在软件开发的世界里&#xff0c;我们经常会遇到需要表示"部分-整体"层次结构的场景。比如文件系统中的文件和文件夹、图形界面中的各种组件、企业组织架构中的部门和员工等。这些场景都有一个共同的特点&#xff1a;我们需要以一种统一的方式来处理单个对象和由…...

Oracle 19c RAC集群ADG搭建

1、将主库的pfile和passwdfile发送到备库 #主库一节点操作 scp -P1234 /tmp/pfile2025.ora bak_ip:/home/oracle sco -P1234 /oracle/app/oracle/product/19.0.0/db/dbs/orapw$ORACLE_SID bak_ip:/oracle/app/oracle/product/19.0.0/db/dbs 2、备库修改参数文件成standby相关…...

ADB识别手机系统弹授权框-如何处理多重弹框叠加和重叠问题

ADB识别手机系统弹授权框-如何处理多重弹框叠加和重叠问题 --蓝牙电话SDK自动部署 上一篇&#xff1a;手机App-插入USB时自动授权点击确定按钮-使系统弹出框自动消失 下一篇&#xff1a;编写中。 一、前言 我们在上一篇《手机App-插入USB时自动授权点击确定按钮-使系统弹出框…...

Kaggle-Predicting Optimal Fertilizers-(多分类+xgboost+同一特征值多样性)

Predicting Optimal Fertilizers 题意&#xff1a; 给出土壤的特性&#xff0c;预测出3种最佳的肥料 数据处理&#xff1a; 1.有数字型和类别型&#xff0c;类别不能随意换成数字&#xff0c;独热编码。cat可以直接处理category类型。 2.构造一些相关土壤特性特征 3.由于la…...

uniapp+<script setup lang=“ts“>解决有数据与暂无数据切换显示,有数据加载时暂无数据闪现(先加载空数据)问题

声明showEmpty 为false&#xff0c;在接口返回处判断有数据时设置showEmpty 为false&#xff0c;接口返回数据为空则判断showEmpty 为true &#xff08;这样就解决有数据的时候会闪现暂无数据的问题啦&#xff09; <!--* Date: 2024-02-26 03:38:52* LastEditTime: 2025-06…...

详解鸿蒙Next仓颉开发语言中的动画

大家上午好&#xff0c;今天来聊一聊仓颉开发语言中的动画开发。 仓颉中的动画通常有两种方式&#xff0c;分别是属性动画和显示动画&#xff0c;我们今天以下面的加载动画为例&#xff0c;使用显示动画和属性动画分别实现一下&#xff0c;看看他们有什么区别。 显示动画 显示…...

Redis常见使用场景解析

1. 数据库缓存 Redis 作为典型的 Key-Value 型内存数据库,数据缓存是其最广为人知的应用场景。使用 Redis 缓存数据操作简便,通常将序列化后的对象以 string 类型存储。但在实际应用中,需注意以下关键要点: Key 设计:必须确保不同对象的 Key 具有唯一性,且尽量缩短长度,…...

C语言指针与数组sizeof运算深度解析:从笔试题到内存原理

前两天跟着数组指针的教程&#xff1a; // #self 视频里的笔试题 !!!vipint b12[3][4] {0};printf("%ld \n", sizeof(b12[0]));printf("%ld \n", sizeof(*b12));printf("%ld \n", sizeof(*(b12 1)));printf("%ld \n", sizeof(*(&am…...

起重机指挥人员在工作中需要注意哪些安全事项?

起重机指挥人员在作业中承担着协调设备运行、保障作业安全的关键职责&#xff0c;其安全操作直接关系到整个起重作业的安全性。以下从作业前、作业中、作业后的全流程&#xff0c;详细说明指挥人员需注意的安全事项&#xff1a; 一、作业前的安全准备 资质与状态检查&#xff…...

JVM内存区域与溢出异常详解

当然可以。以下是结合了程序计数器和Java内存区域以及内存溢出异常的详细解释&#xff1a; JVM内存区域与内存溢出异常 Java虚拟机&#xff08;JVM&#xff09;管理着不同类型的内存区域&#xff0c;每个区域都有其特定的功能和可能导致的内存溢出异常。 程序计数器&#xff…...

ES海量数据更新及导入导出备份

一、根据查询条件更新字段 from elasticsearch import Elasticsearch import redis import json# 替换下面的用户名、密码和Elasticsearch服务器地址 username elastic password password es_host https://127.0.0.2:30674# 使用Elasticsearch实例化时传递用户名和密码 es…...

Java线程池核心原理与最佳实践

Java 线程池详解 线程池是Java并发编程的核心组件&#xff0c;它能高效管理线程生命周期&#xff0c;避免频繁创建销毁线程的开销&#xff0c;提升系统性能和资源利用率。 一、线程池核心优势 降低资源消耗&#xff1a;复用已创建的线程&#xff0c;减少线程创建销毁开销提高…...

JAVA-springboot log日志

SpringBoot从入门到精通-第8章 日志的操作 一、Spring Boot默认的日志框架 SpringBoot支持很多种日志框架&#xff0c;通常情况下&#xff0c;这些日志框架都是由一个日志抽象层和一个日志实现层搭建而成的&#xff0c;日志抽象层是为记录日志提供的一套标准且规范的框架&…...

1.springmvc基础入门(一)

1.Spring MVC概念 Spring MVC 是 Spring Framework 提供的 Web 组件&#xff0c;全称是 Spring Web MVC&#xff0c;是⽬前主流的实现 MVC 设计模式的框架&#xff0c;提供前端路由映射、视图解析等功能。 Java Web 开发者必须要掌握的技术框架。 2.Spring MVC 功能 MVC&am…...

AI 时代下语音与视频伪造的网络安全危机

引言 在人工智能技术的推动下&#xff0c;语音合成、视频生成等技术取得了突破性进展&#xff0c;Deepfake、AI 语音克隆等工具让语音和视频伪造变得愈发简单且逼真。这些技术在娱乐、影视等领域带来便利的同时&#xff0c;也被不法分子利用&#xff0c;引发了一系列网络安全问…...

模块缝合-把A模块换成B模块(没写完)

把MLP Head替换为KAN 1.在model文件下新建一个python文件 2.把 模块文件里的整个KAN代码复制到新的python文件中 3.在开头导入 from model.KAN(新建文件名&#xff09; import KAN&#xff08;新建文件中的类名&#xff09; 4.sys.path.append(r"D: Icode(Kansformer"…...

从零开始学Flink:揭开实时计算的神秘面纱

一、为什么需要Flink&#xff1f; 当你在电商平台秒杀商品时&#xff0c;1毫秒的延迟可能导致交易失败&#xff1b;当自动驾驶汽车遇到障碍物时&#xff0c;10毫秒的计算延迟可能酿成事故。这些场景揭示了一个残酷事实&#xff1a;数据的价值随时间呈指数级衰减。 传统批处理…...

一、ES6-let声明变量【解刨分析最详细】

一、块级作用域 { let Tim"Tim是靓仔&#xff01;" } console.log("Tim:",Tim) 打印结果&#xff1a;Tim未进行任何定义&#xff01; 原因&#xff1a;因为Tim定义再块级{}里面&#xff0c;它的声音Tim只服务于该块级里面。而打印结果是再块级外面&#…...