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

QT聊天项目DAY11

1. 验证码服务

1.1 用npm安装redis

npm install redis

1.2 修改config.json配置文件

1.3 新建redis.js

const config_module = require('./config')
const Redis = require("ioredis");// 创建Redis客户端实例
const RedisCli = new Redis({host: config_module.redis_host,             // Redis服务器主机名port: config_module.redis_port,             // Redis服务器端口号password: config_module.redis_passwd,       // Redis密码
});/*** 监听错误信息*/
RedisCli.on("error", function (err) {console.log("RedisCli connect error");RedisCli.quit();
});/*** 根据key获取value* @param {*} key * @returns */
async function GetRedis(key) {try {const result = await RedisCli.get(key)if (result === null) {console.log('result:', '<' + result + '>', 'This key cannot be find...')return null}console.log('Result:', '<' + result + '>', 'Get key success!...');return result} catch (error) {console.log('GetRedis error is', error);return null}
}/*** 根据key查询redis中是否存在key* @param {*} key * @returns */
async function QueryRedis(key) {try {const result = await RedisCli.exists(key)//  判断该值是否为空 如果为空返回nullif (result === 0) {console.log('result:<', '<' + result + '>', 'This key is null...');return null}console.log('Result:', '<' + result + '>', 'With this value!...');return result} catch (error) {console.log('QueryRedis error is', error);return null}
}/*** 设置key和value,并过期时间* @param {*} key * @param {*} value * @param {*} exptime * @returns */
async function SetRedisExpire(key, value, exptime) {try {// 设置键和值await RedisCli.set(key, value)// 设置过期时间(以秒为单位)await RedisCli.expire(key, exptime);return true;} catch (error) {console.log('SetRedisExpire error is', error);return false;}
}/*** 退出函数*/function Quit() {RedisCli.quit();
}
module.exports = { GetRedis, QueryRedis, Quit, SetRedisExpire, }

1.4 修改server.js

添加redis的库,获取验证码之前查询redis,没查到生成uid并且写入redis

async function GetVerifyCode(call, callback) {console.log("email is ", call.request.email)/* 先查询redis中是否有记录的邮箱对应的uuid */let query_res = await redis_module.GetRedis(const_module.code_prefix + call.request.email);         // code_**@163.comconsole.log("query_res is ", query_res);let uniqueId = query_res ? query_res : null;if (uniqueId) {uniqueId = uuidv4();                                                                            // 生成新的uuidif (uniqueId.length > 4)uniqueId = uniqueId.substring(0, 4);}/* 如果redis中没有记录,则生成新的uuid并存入redis */let bres = await redis_module.SetRedisExpire(const_module.code_prefix + call.request.email, uniqueId, 600);if (!bres) {callback(null,{email: call.request.email,error: const_module.Errors.RedisError});return;}try {console.log("uniqueId is ", uniqueId)let text_str = '您的验证码为' + uniqueId + '请三分钟内完成注册'//发送邮件let mailOptions = {from: '13083361602@163.com',to: call.request.email,subject: '=?UTF-8?B?' + Buffer.from('验证码').toString('base64') + '?=',text: text_str,};let send_res = await emailModule.SendMail(mailOptions);console.log("send res is ", send_res)callback(null, {email: call.request.email,error: const_module.Errors.Success});} catch (error) {console.log("catch error is ", error)callback(null, {email: call.request.email,error: const_module.Errors.Exception});}
}

1.5 验证是否正确发送

首先启动redis服务

.\redis-server.exe .\redis.windows.conf

启动grpc服务器

npm run serve

安装ioredis

npm install ioredis

启动QT客户端

启动C++服务器

2. 注册服务

2.1 新增QT客户端确认按钮的槽函数

/* 确认按钮点击 */
void RegisterWidget::OnConfirmButtonClicked()
{if (ui.User_Edit->text() == ""){ShowTipLabel(QString::fromLocal8Bit("用户名不能为空"), "error");return;}if (ui.Email_Edit->text() == ""){ShowTipLabel(QString::fromLocal8Bit("邮箱不能为空"), "error");return;}if (ui.PassWord_Edit->text() == ""){ShowTipLabel(QString::fromLocal8Bit("密码不能为空"), "error");return;}if (ui.Enter_Edit->text() == ""){ShowTipLabel(QString::fromLocal8Bit("确认密码不能为空"), "error");return;}if (ui.PassWord_Edit->text() != ui.Enter_Edit->text()){ShowTipLabel(QString::fromLocal8Bit("两次密码输入不一致"), "error");return;}if (ui.Verify_Edit->text() == ""){ShowTipLabel(QString::fromLocal8Bit("验证码不能为空"), "error");return;}// 发送http请求注册用户QJsonObject jsonObj;jsonObj["user"] = ui.User_Edit->text();jsonObj["email"] = ui.Email_Edit->text();jsonObj["password"] = ui.PassWord_Edit->text();jsonObj["EnterPassword"] = ui.Enter_Edit->text();jsonObj["verify_code"] = ui.Verify_Edit->text();QString urlStr = "http://" + ConfigSettings->value("GateServer/host").toString() + ":" + ConfigSettings->value("GateServer/port").toString() + "//"+ ConfigSettings->value("GateServer/ConfirmUser").toString();QUrl url(urlStr);HttpManager::Instance()->PostHttpReq(url, jsonObj,ReqID::ID_REG_USER,Modules::REGISTERMOD);
}

2.2 绑定注册逻辑完成对应的回调函数

void RegisterWidget::InitHttpHandlers()
{// 注册获取验证码回包的逻辑_handlers.insert(ReqID::ID_GET_VARIFY_CODE, [this](const QJsonObject& jsonObj){int error = jsonObj["error"].toInt();if (error != ErrorCodes::SUCCESS){ShowTipLabel(QString::fromLocal8Bit("参数错误"), "error");return;}auto email = jsonObj["email"].toString();ShowTipLabel(QString::fromLocal8Bit("验证码已发送至邮箱,请注意查找"), "normal");qDebug() << QString::fromLocal8Bit("验证码已发送至邮箱") << email;});// 注册注册用户服务器返回的数据对应的处理逻辑的回调函数_handlers.insert(ReqID::ID_REG_USER, [this](const QJsonObject& jsonObj){int error = jsonObj["error"].toInt();if (error != ErrorCodes::SUCCESS){ShowTipLabel(QString::fromLocal8Bit("注册失败"), "error");return;}auto email = jsonObj["email"].toString();ShowTipLabel(QString::fromLocal8Bit("注册成功,请登录"), "normal");qDebug() << QString::fromLocal8Bit("注册成功") << email;});
}

2.3 梳理一下注册逻辑

整个QT客户端,是由HttpConnect类来管理网络连接,比如向服务器发送请求,接收服务器发来的响应

而对响应的处理实际上是在别的类中处理的,HttpConnect将具体的处理逻辑放在了sig_http_finished 里,这里绑定的是一个回调,再次细分,如果是注册模块的请求,就调用注册模块中被绑定的回调函数,如果是登录模块就调用登录模块的回调函数,实现了面向对象思想,其实所有架构不是一开始都想好的,写的多了自然而然就想到了。

然后在注册模块中再次细分,比如获取验证码,服务器会发响应,注册确认按钮按下时,服务器又会发响应

2.4 服务器处理注册请求

enum ErrorCodes
{SUCCESS = 0,ERROR_JSON = 1001,																		// Json错误RPC_FAILED = 1002,																		// RPC通信失败ERROR_JSON_KEY_EMAIL_LACK = 1003,														// Json中缺少email字段Verify_Expired = 1004,																	// 验证码过期Verify_Not_Match = 1005,																// 验证码不匹配User_Exists = 1006,																		// 用户已存在
};#define CODE_PREFIX "code_"
// 注册用户对应的回调函数
RegisterPost("/ConfirmUser", [](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;}/* 查找redis中存储的email对应的验证码是否合理 */string verifyCode = "";bool bGetVerifyCode = RedisManage::GetInstance()->Get(CODE_PREFIX + jsonResult["email"].asString(), verifyCode);if (!bGetVerifyCode){cout << "get verify code Expired " << endl;jsonResonse["error"] = ErrorCodes::Verify_Expired;string jsonStr = jsonResonse.toStyledString();beast::ostream(connection->_response.body()) << jsonStr;return;}/* 判断验证码是否正确 */if (verifyCode != jsonResult["verifyCode"].asString()){cout << "verify code not match" << endl;jsonResonse["error"] = ErrorCodes::Verify_Not_Match;string jsonStr = jsonResonse.toStyledString();beast::ostream(connection->_response.body()) << jsonStr;return;}/* 访问Mysql检查是否已经注册过用户,如果未注册,注册用户,如果已经注册过,返回错误码 */// TODO/* 返回响应报文给客户端 */jsonResonse["error"] = 0;jsonResonse["email"] = jsonResult["email"];jsonResonse["user"] = jsonResult["user"];jsonResonse["password"] = jsonResult["password"];jsonResonse["EnterPassword"] = jsonResult["EnterPassword"];jsonResonse["verifyCode"] = jsonResult["verifyCode"];string jsonStr = jsonResonse.toStyledString();beast::ostream(connection->_response.body()) << jsonStr;							// 向 Http响应体中写入Json内容return;}else{std::cout << "connection is null" << std::endl;}});

2.5 测试注册服务

注册成功

3. Mysql注册用户

3.1 修改Mysql中的My.ini

找到Mysql的安装路径

C:\Program Files\MySQL\MySQL Server 8.0

如果没有my.ini自己定义一个

[mysqld]
# 设置3306端口
port=3306
# 设置mysql的安装目录 ---这里输入你安装的文件路径----
basedir=C:\Program Files\MySQL\MySQL Server 8.0
# 设置mysql数据库的数据的存放目录
datadir=D:\mysql\data
# 允许最大连接数
max_connections=200
# 允许连接失败的次数。
max_connect_errors=10
# 服务端使用的字符集默认为utf8
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
# 默认使用“mysql_native_password”插件认证
#mysql_native_password
default_authentication_plugin=mysql_native_password
[mysql]
# 设置mysql客户端默认字符集
default-character-set=utf8
[client]
# 设置mysql客户端连接服务端时默认使用的端口
port=3306
default-character-set=utf8

启动Mysql服务

连接mysql服务

mysql -uroot -p

如果连接mysql服务显示无法连接指定端口,可以先将my.ini删除,然后登录mysql,调用

SHOW VARIABLES LIKE 'port';

查找mysql服务安装的端口,然后修改my.ini文件

我的mysql密码:123456

3.2 安装图形界面控制Mysql交互

https://pan.baidu.com/s/10jApYUrwaI19j345dpPGNA?pwd=77m2验证码: 77m2

3.3 安装Mysql Connect库

https://pan.baidu.com/s/1XAVhPAAzZpZahsyITua2oQ?pwd=9c1w提取码:9c1w

3.4 配置环境变量

动态库无需链接

将动态库放在项目路径下动态链接

让dll自动拷贝到运行目录

xcopy $(ProjectDir)config.ini  $(SolutionDir)$(Platform)\$(Configuration)\   /y
xcopy $(ProjectDir)*.dll   $(SolutionDir)$(Platform)\$(Configuration)\   /y

4. Mysql连接池

4.1 新建MysqlDAO连接管理类

连接池

class SqlConnection
{
public:SqlConnection(sql::Connection* con, int64_t lastUseTime): _con(con), _lastUseTime(lastUseTime){}sql::Connection* _con;int64_t _lastUseTime;
};class MySqlPool
{
public:MySqlPool(const string& url, const string& user, const string& pwd, const string& schema, int poolSize): _url(url), _user(user), _pwd(pwd), _schema(schema), _poolSize(poolSize), bIsStop(false){for (int i = 0; i < _poolSize; i++){sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();sql::Connection* con = driver->connect(_url, _user, _pwd);con->setSchema(_schema);// 获取当前时间戳auto currentTime = chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count();_pool.push(new SqlConnection(con, currentTime));}_thread = thread([this](){while (!bIsStop){checkConnection();this_thread::sleep_for(chrono::seconds(10));}});_thread.detach();														// 该线程不会阻塞主线程,后台执行}void checkConnection(){lock_guard<mutex> lock(_mutex);// 获取当前时间戳auto currentTime = chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count();for (int i = 0; i < _poolSize; i++){auto con = _pool.front();_pool.pop();// 如果该连接距离上次使用时间已超过 60 秒,则执行心跳检测if (currentTime - con->_lastUseTime > 60){auto stmt = con->_con->createStatement();stmt->execute("SELECT 1");con->_lastUseTime = currentTime;_pool.push(con);con = nullptr;}}}~MySqlPool(){bIsStop = true;_cv.notify_all();while (!_pool.empty()){SqlConnection* con = _pool.front();_pool.pop();delete con;}}SqlConnection* getConnection(){unique_lock<mutex> lock(_mutex);_cv.wait(lock, [this] {return!_pool.empty();});if(bIsStop)return nullptr;SqlConnection* con = _pool.front();_pool.pop();return con;}void retunConnection(SqlConnection* con){lock_guard<mutex> lock(_mutex);if(bIsStop)return;_pool.push(con);_cv.notify_one();}private:string _url;string _user;string _pwd;string _schema;int _poolSize;queue<SqlConnection*> _pool;mutex _mutex;condition_variable _cv;atomic<bool> bIsStop = false;thread _thread;																	// 检测当前连接是否活跃,不活跃发送一条信息告诉Mysql我还活着
};

class MySqlDAO : public Singletion<MySqlDAO>
{friend class Singletion<MySqlDAO>;
public:MySqlDAO();~MySqlDAO();// 注册用户int RegUser(const string& username, const string& email, const string& password);private:MySqlPool* _pool;
};
#endif // MYSQLDAO_H

4.2 存储过程

数据库中一组预先编写好的SQL语句的集合,可以把存储过程看作数据库中的函数

SQL语言层面的代码封装与重用

示例

DELIMITER //  CREATE PROCEDURE CalculateSquare(IN num INT, OUT result INT)  
BEGIN  SET result = num * num;  
END //  DELIMITER ;

DELIMITER 用于更改命令结束符,以便在存储过程中使用 BEGIN ... END 语句。通常,我们使用 // 作为新的结束符,并在存储过程定义结束后将其改回 ;
CREATE PROCEDURE 用于创建新的存储过程。
CalculateSquare 是存储过程的名称
(IN num INT, OUT result INT) 定义了输入输出参数。在这个例子中,num 是一个输入参数,result 是一个输出参数
BEGIN ... END 之间的部分是存储过程的主体,即要执行的SQL语句

调用存储过程

调用存储过程并获取结果,需要使用CALL语句,并指定一个变量来接收输出参数的值

SET @input = 5;  
SET @output = 0;  CALL CalculateSquare(@input, @output);  SELECT @output;  -- 输出应该是 25

4.3 创建注册用户存储过程

如果处理异常会回滚事务,手动开启事务,保证后续多步操作要么都成功,要么都失败

什么是事务?

首先检查用户名是否已存在,如果存在提交事务

如果用户名没有问题,检查邮箱是否重复,如果存在,提交事务

用户名和邮箱都没有问题,开始注册用户

把新用户插到user表中

设置返回值是新用户ID,并提交事务

CREATE DEFINER=`root`@`localhost` PROCEDURE `reg_user`(IN `new_name` VARCHAR(255),IN `new_email` VARCHAR(255),IN `new_pwd` VARCHAR(255),OUT `result` INT
)
BEGIN-- 如果执行过程中遇到任何错误,回滚事务DECLARE EXIT HANDLER FOR SQLEXCEPTIONBEGIN-- 回滚事务ROLLBACK;-- 设置返回值为-1SET result = -1;END;-- 开始事务START TRANSACTION;-- 检查用户名是否已存在IF EXISTS (SELECT 1 FROM `user` WHERE `name` = new_name) THENSET result = 0;COMMIT;ELSE-- 用户名不存在,检查email是否已存在IF EXISTS (SELECT 1 FROM `user` WHERE `email` = new_email) THENSET result = 0;COMMIT;ELSE-- emial 也不存在,更新user_id 表UPDATE `user_id` SET `id` = `id` + 1;-- 获取更新后的id SELECT `id` INTO @new_id FROM `user_id`;-- 在user表中插入新纪录INSERT INTO `user` (`uid`, `name`, `email`, `pwd`) VALUES (@new_id, new_name, new_email, new_pwd);-- 设置result为新插入的uidSET result = @new_id;COMMIT;END IF;END IF;END

4.4 创建数据表

新建user表

新建user_id表

4.5 新建Mysql管理类

#ifndef MYSQLMANAGE_H
#define MYSQLMANAGE_H
#include "GlobalHead.h"
#include "Singletion.h"
#include "MysqlDAO.h"class MySqlManage : public Singletion<MySqlManage>
{friend class Singletion<MySqlManage>;
public:~MySqlManage();int RegUser(const string& name, const string& email, const string& password);private:MySqlManage();MySqlDAO* m_pDao;
};#endif // MYSQLMANAGE_H

#include "MySqlManage.h"MySqlManage::MySqlManage()
{m_pDao = new MySqlDAO();
}MySqlManage::~MySqlManage()
{}int MySqlManage::RegUser(const string& name, const string& email, const string& password)
{return m_pDao->RegUser(name, email, password);
}

5. 注册用户时向Mysql数据库查询

int uid = MySqlManage::GetInstance()->RegUser(jsonResult["user"].asString(),jsonResult["email"].asString(), jsonResult["password"].asString());
if (uid == -1 || uid == 0)
{cout << "user or email already exist\n";jsonResonse["error"] = ErrorCodes::User_Exists;string jsonStr = jsonResonse.toStyledString();beast::ostream(connection->_response.body()) << jsonStr;return;
}

6. 编译测试

服务器编译失败

链接错误,导入静态库

接着报错,说找不到库,说明附加包含目录错了

将上述库所在的目录添加进去

编译成功

启动redis服务

.\redis-server.exe .\redis.windows.conf

启动grpc服务

npm run serve

启动QT客户端

6.1 分析失败原因

链接被拒绝

导致服务器并没有监听指定的端口

6.2 注册失败

莫名其妙的调用了析构函数?

con连接是空

不再使用.json的方式解析,直接传字符串

可能是添加存储过程时没有保存,重新添加

这里是因为root@'%'这个用户不存在于数据库中

将root@'%' 修改成 `root`@`localhost`

查看存储过程发现

执行期间,遇到任何错误,才会导致返回值是-1

查看到底是哪一个sql语句出问题了

已解决

6.3 重新编译

1.解决字符串无法正确解析的问题

这里返回的是局部变量的值,局部变量是不允许用引用去接的,因为生命周期到期后得到的值就是空的

修改上述代码为

已解决

2. 重新测试

打开redis服务

启动grpc服务

启动c++服务器

启动qt客户端

注册成功

相关文章:

QT聊天项目DAY11

1. 验证码服务 1.1 用npm安装redis npm install redis 1.2 修改config.json配置文件 1.3 新建redis.js const config_module require(./config) const Redis require("ioredis");// 创建Redis客户端实例 const RedisCli new Redis({host: config_module.redis_…...

Python训练营---Day29

知识点回顾 类的装饰器装饰器思想的进一步理解&#xff1a;外部修改、动态类方法的定义&#xff1a;内部定义和外部定义 作业&#xff1a;复习类和函数的知识点&#xff0c;写下自己过去29天的学习心得&#xff0c;如对函数和类的理解&#xff0c;对python这门工具的理解等&…...

Flask-SQLAlchemy_数据库配置

1、基本概念&#xff08;SQLAlchemy与Flask-SQLAlchemy&#xff09; SQLAlchemy 是 Python 生态中最具影响力的 ORM&#xff08;对象关系映射&#xff09;库&#xff0c;其设计理念强调 “框架无关性”&#xff0c;支持在各类 Python 项目中独立使用&#xff0c;包括 Flask、D…...

世界银行数字经济指标(1990-2022年)-社科数据

世界银行数字经济指标&#xff08;1990-2022年&#xff09;-社科数据https://download.csdn.net/download/paofuluolijiang/90623839 https://download.csdn.net/download/paofuluolijiang/90623839 此数据集涵盖了1990年至2022年间全球各国的数字经济核心指标&#xff0c;数据…...

Redis进阶知识

Redis 1.事务2. 主从复制2.1 如何启动多个Redis服务器2.2 监控主从节点的状态2.3 断开主从复制关系2.4 额外注意2.5拓扑结构2.6 复制过程2.6.1 数据同步 3.哨兵选举原理注意事项 4.集群4.1 数据分片算法4.2 故障检测 5. 缓存5.1 缓存问题 6. 分布式锁 1.事务 Redis的事务只能保…...

NY337NY340美光固态颗粒NC010NC012

NY337NY340美光固态颗粒NC010NC012 在存储技术的浩瀚星空中&#xff0c;美光的NY337、NY340、NC010、NC012等固态颗粒宛如璀璨星辰&#xff0c;闪耀着独特的光芒。它们承载着先进技术与无限潜力&#xff0c;正深刻影响着存储行业的格局与发展。 一、技术架构与核心优势 美光…...

DAY26 函数定义与参数

浙大疏锦行-CSDN博客 知识点回顾&#xff1a; 1.函数的定义 2.变量作用域&#xff1a;局部变量和全局变量 3.函数的参数类型&#xff1a;位置参数、默认参数、不定参数 4.传递参数的手段&#xff1a;关键词参数 5.传递参数的顺序&#xff1a;同时出现三种参数类型时 函数的定义…...

系统安全及应用

目录 一、账号安全控制 1.基本安全措施 &#xff08;1&#xff09;系统账号清理 (2)密码安全控制 &#xff08;3&#xff09;历史命令&#xff0c;自动注销 2.用户提权和切换命令 2.1 su命令用法 2.2 sudo命令提权 2.3通过是sudo执行特权命令 二、系统引导和登录控制…...

微信小程序 地图 使用 射线法 判断目标点是否在多边形内部(可用于判断当前位置是否在某个区域内部)

目录 射线法原理简要逻辑代码 小程序代码调试基础库小程序配置地图数据地图多边形点与多边形关系 射线法 原理 使用射线法来判断&#xff0c;目标点是否在多边形内部 这里简单说下&#xff0c;具体细节可以看这篇文章 平面几何&#xff1a;判断点是否在多边形内&#xff08;…...

第三十七节:视频处理-视频读取与处理

引言:解码视觉世界的动态密码 在数字化浪潮席卷全球的今天,视频已成为信息传递的主要载体。从短视频平台的爆火到自动驾驶的视觉感知,视频处理技术正在重塑人类与数字世界的交互方式。本指南将深入探讨视频处理的核心技术,通过Python与OpenCV的实战演示,为您揭开动态影像…...

什么是 Flink Pattern

在 Apache Flink 中&#xff0c;Pattern 是 Flink CEP&#xff08;Complex Event Processing&#xff09;模块 的核心概念之一。它用于定义你希望从数据流中检测出的 事件序列模式&#xff08;Event Sequence Pattern&#xff09;。 &#x1f3af; 一、什么是 Flink Pattern&am…...

ADB基本操作和命令

1.ADB的含义 adb 命令是 Android 官方提供&#xff0c;调试 Android 系统的工具。 adb 全称为 Android Debug Bridge&#xff08;Android 调试桥&#xff09;&#xff0c;是 Android SDK 中提供的用于管理 Android 模拟器或真机的工具。 adb 是一种功能强大的命令行工具&#x…...

NSString的三种实现方式

oc里的NSString有三种实现方式&#xff0c;为_ _NSCFConstantString、__NSCFString、NSTaggedPointerString 1._ _NSCFConstantString(字面量字符串) 从字面意思上可以看出&#xff0c;_ _NSCFContantString可以理解为常量字符串&#xff0c;这种类型的字符串在编译期就确定了…...

2025年PMP 学习二十 第13章 项目相关方管理

第13章 项目相关方管理 序号过程过程组过程组1识别相关方启动2规划相关方管理规划3管理相关方参与与执行4监控相关方参与与监控 相关方管理&#xff0c;针对于团队之外的相关方的&#xff0c;核心目标是让对方为了支持项目&#xff0c;以达到项目目标。 文章目录 第13章 项目相…...

学习黑客Kerberos深入浅出:安全王国的门票系统

Kerberos深入浅出&#xff1a;安全王国的门票系统 &#x1f3ab; 作者: 海尔辛 | 发布时间: 2025-05-18 &#x1f511; 理解Kerberos&#xff1a;为什么它如此重要&#xff1f; Kerberos是现代网络环境中最广泛使用的身份验证协议之一&#xff0c;尤其在Windows Active Dire…...

蓝桥杯19681 01背包

问题描述 有 N 件物品和一个体积为 M 的背包。第 i 个物品的体积为 vi​&#xff0c;价值为 wi​。每件物品只能使用一次。 请问可以通过什么样的方式选择物品&#xff0c;使得物品总体积不超过 M 的情况下总价值最大&#xff0c;输出这个最大价值即可。 输入格式 第一行输…...

使用 Auto-Keras 进行自动化机器学习

使用 Auto-Keras 进行自动化机器学习 了解自动化机器学习以及如何使用 auto-keras 完成它。如今&#xff0c;机器学习并不是一个非常罕见的术语&#xff0c;因为像 DataCamp、Coursera、Udacity 等组织一直在努力提高他们的效率和灵活性&#xff0c;以便将机器学习的教育带给普…...

算法刷题Day9 5.18:leetcode定长滑动窗口3道题,结束定长滑动窗口,用时1h

12. 1852.每个子数组的数字种类数 1852. 每个子数组的数字种类数 - 力扣&#xff08;LeetCode&#xff09; 思想 找到nums 所有 长度为 k 的子数组中 不同 元素的数量。 返回一个数组 ans&#xff0c;其中 ans[i] 是对于每个索引 0 < i < n - k&#xff0c;nums[i..(i …...

Protect Your Digital Privacy: Obfuscate, Don’t Hide

Protect Your Digital Privacy: Obfuscate, Don’t Hide In today’s digital world, hiding completely online is nearly impossible. But you can protect yourself by deliberately obfuscating your personal information — making it harder for others to track, pro…...

Spark 的运行模式(--master) 和 部署方式(--deploy-mode)

Spark 的 运行模式&#xff08;--master&#xff09; 和 部署方式&#xff08;--deploy-mode&#xff09;&#xff0c;两者的核心区别在于 资源调度范围 和 Driver 进程的位置。 一、核心概念对比 维度--master&#xff08;运行模式&#xff09;--deploy-mode&#xff08;部署…...

从零开始实现大语言模型(十五):并行计算与分布式机器学习

1. 前言 并行计算与分布式机器学习是一种使用多机多卡加速大规模深度神经网络训练过程&#xff0c;以减少训练时间的方法。在工业界的训练大语言模型实践中&#xff0c;通常会使用并行计算与分布式机器学习方法来减少训练大语言模型所需的钟表时间。 本文介绍PyTorch中的一种…...

生产模式下react项目报错minified react error #130的问题

这天&#xff0c;线上突然出现了一个bug&#xff0c;某个页面打开空白&#xff0c;看控制台报错minified react error #130&#xff0c;在本地看却是正常的&#xff0c;百思不得其解。 后来发现是由于线上项目它的包更新过了&#xff0c;而我本地的包没有更新&#xff0c;所以我…...

本地无损放大软件-realesrgan-gui

—————【下 载 地 址】——————— 【​本章下载一】&#xff1a;https://drive.uc.cn/s/84516041df174 【​本章下载二】&#xff1a;https://pan.xunlei.com/s/VOQDybD4ruF0-m8UJrCF-HtLA1?pwdxz9e# 【百款黑科技】&#xff1a;https://ucnygalh6wle.feishu.cn/wiki/…...

Java面试深度解析:微服务与云原生技术应用场景详解

Java面试深度解析&#xff1a;微服务与云原生技术应用场景详解 面试场景 面试官&#xff1a;我们今天的面试会围绕微服务与云原生技术展开&#xff0c;结合一个在线教育平台的业务场景进行提问。希望你放松心态&#xff0c;正常发挥。 码农明哥&#xff1a;好的好的&#xf…...

短剧小程序系统开发源码上架,短剧项目市场分析

引言 随着短视频内容消费的爆发式增长&#xff0c;短剧小程序凭借其碎片化、强互动、低成本的特点&#xff0c;成为内容创业与资本布局的新风口。2024年以来&#xff0c;行业规模突破500亿元&#xff0c;预计2027年将超千亿17。本文将深度解析短剧小程序系统开发的技术优势、市…...

常见的请求头(Request Header)参数

1. Accept 作用&#xff1a;告知服务器客户端支持的响应数据格式&#xff08;如 JSON、XML、HTML&#xff09;。示例&#xff1a;Accept: application/json&#xff08;优先接收 JSON 格式数据&#xff09;。 2. Content-Type 作用&#xff1a;说明请求体的数据格式&#xff08…...

渗透测试核心技术:内网渗透与横向移动

内网渗透是红队行动的关键阶段,攻击者通过突破边界进入内网后,需快速定位域控、横向移动并维持权限。本节从内网环境搭建、信息收集、横向移动技巧到权限维持工具,系统讲解如何在内网中隐蔽行动并扩大战果。 1. 内网环境搭建与基础配置 目标: 模拟真实企业网络,构建包含…...

2025/5/18

继续研究一下大佬的RAG项目。开始我的碎碎念。 RAG可以分成两部分&#xff1a;一个是问答&#xff0c;一个是数据处理。 问答是人提问&#xff0c;然后查数据库&#xff0c;把查的东西用大模型组织成人话&#xff0c;回答人的提问。 数据处理是把当下知识库里的东西&#xf…...

使用国内源加速Qt在线安装

简介&#xff1a; 在线安装Qt时&#xff0c;会发现下载非常缓慢&#xff0c;可以用过使用国内镜像源来加速安装过程。 在线安装包的下载过程&#xff1a; 1&#xff0c;打开下载页面 https://www.qt.io/download-open-source 2&#xff0c;点击 Download the Qt online ins…...

【图像生成大模型】HunyuanVideo:大规模视频生成模型的系统性框架

HunyuanVideo&#xff1a;大规模视频生成模型的系统性框架 引言HunyuanVideo 项目概述核心技术1. 统一的图像和视频生成架构2. 多模态大语言模型&#xff08;MLLM&#xff09;文本编码器3. 3D VAE4. 提示重写&#xff08;Prompt Rewrite&#xff09; 项目运行方式与执行步骤1. …...

Java IO流(超详细!!!)

Java IO流 文章目录 Java IO流1.文件相关基础普及1.1 常用文件操作1.3 目录的操作和文件删除 2.IO流原理及流的分类2.1 字节流2.1.1 InputStream&#xff1a;字节输入流2.1.2 OutputStream 2.2 字符流2.2.1 Reader2.2.1 Writer 2.3 节点流和处理流2.3.1节点流2.3.2 处理流2.3.2…...

规则联动引擎GoRules初探

背景说明 嵌入式设备随着物联网在生活和生产中不断渗透而渐渐多起来&#xff0c;数据的采集、处理、分析在设备侧的自定义配置越来越重要。一个可通过图形化配置的数据处理过程&#xff0c;对于加速嵌入式设备的功能开发愈发重要。作为一个嵌入式软件从业者&#xff0c;笔者一…...

Android开发-翻页类视图

在Android应用中&#xff0c;翻页类视图&#xff08;Paging Views&#xff09; 是一种非常直观且用户友好的方式来展示内容。无论是用于展示图片轮播、引导页还是分页加载数据列表&#xff0c;翻页效果都能极大地提升用户体验。本文将介绍几种实现翻页效果的常见组件和方法&…...

高能数造闪耀 CIBF 2025,以创新技术引领新能源智造新征程

在全球新能源产业加速发展的关键节点&#xff0c;CIBF 2025 展会成为行业技术与成果交流的重要平台。高能数造&#xff08;西安&#xff09;技术有限公司深度参与此次盛会&#xff0c;凭借在新能源电池智能制造领域的深厚积累与创新突破&#xff0c;为行业发展注入强劲动力&…...

数据结构与算法——栈和队列

栈和队列 栈概念与结构栈的实现栈的初始化栈的销毁判断栈是否为空入栈出栈取栈顶元素栈中有效元素个数 队列概念与结构队列的实现队列结点结构队列结构初始化队列队列判空销毁队列入队列&#xff0c;队尾出队列&#xff0c;队头取队头数据取队尾数据队列有效数据个数 栈 概念与…...

新电脑软件配置三 pycharm

快捷键放大和缩小字体 按住ctrl鼠标滚轮向上 缩小同理...

浅入ES5、ES6(ES2015)、ES2023(ES14)版本对比,及使用建议---ES6就够用(个人觉得)

JavaScript&#xff08;ECMAScript&#xff09;的发展经历了多个版本&#xff0c;每个版本都引入了新特性和改进。以下仅是对三个常用版本&#xff08;ES5、ES6&#xff08;ES2015&#xff09; 和 ES2023&#xff09;的基本对比及使用建议&#xff1a; 目前常见项目中还是用ES6…...

【Odoo】Pycharm导入运行Odoo15

【Odoo】Pycharm导入运行Odoo15 前置准备1. Odoo-15项目下载解压2. PsrtgreSQL数据库 项目导入运行1. 项目导入2. 设置项目内虚拟环境3. 下载项目中依赖4. 修改配置文件odoo.conf 运行Pycharm快捷运行 前置准备 1. Odoo-15项目下载解压 将下载好的项目解压到开发目录下 2. …...

【运营商查询】批量手机号码归属地和手机运营商高速查询分类,按省份城市,按运营商移动联通电信快速分类导出Excel表格,基于WPF的实现方案

WPF手机号码归属地批量查询与分类导出方案 应用场景 ​​市场营销​​&#xff1a;企业根据手机号码归属地进行精准营销&#xff0c;按城市或省份分类制定针对性推广策略​​客户管理​​&#xff1a;快速对客户手机号码进行归属地分类&#xff0c;便于后续客户关系管理​​数…...

中级统计师-统计学基础知识-第四章 假设检验

一、假设检验的基本原理 1. 基本思想 反证法&#xff1a;假设原假设成立&#xff0c;通过样本矛盾性进行反驳小概率原理&#xff1a;设定显著性水平 α \alpha α&#xff08;通常取 0.05&#xff09;&#xff0c;若观测结果的概率 p ≤ α p \leq \alpha p≤α&#xff0c…...

等于和绝对等于的区别

1. &#xff08;等于&#xff09; 特点&#xff1a;比较时会自动进行类型转换&#xff08;隐式转换&#xff09;&#xff0c;尝试将两边的值转为相同类型后再比较。规则&#xff1a; 如果类型相同&#xff0c;直接比较值。如果类型不同&#xff0c;按以下规则转换&#xff1a; …...

家庭关系处理个人总结

首先要说到前面的是&#xff0c;每个家庭的成员背景环境经济状况不同&#xff0c;原生家庭差异&#xff0c;导致面临具体问题是不同的。就类似软件“没有银弹”的概念&#xff0c;没有一种方法可以解决每个人问题。 举个例子&#xff0c;面对婆媳矛盾 网上父辈的人 会说 百行孝…...

【Python训练营打卡】day29 @浙大疏锦行

DAY 29 复习日 知识点回顾 1. 类的装饰器 2. 装饰器思想的进一步理解&#xff1a;外部修改、动态 3. 类方法的定义&#xff1a;内部定义和外部定义 作业&#xff1a;复习类和函数的知识点&#xff0c;写下自己过去29天的学习心得&#xff0c;如对函数和类的理解&#xff0c;…...

React 19版本refs也支持清理函数了。

文章目录 前言一、refs 支持清理函数二、案例演示1.useEffect写法2.React 19改进 的ref写法 总结 前言 React 19版本发布了ref支持清理函数了&#xff0c;这样就可以达到useEffect一样的效果了。为啥需要清理函数呢&#xff0c;这是因为节约内存。 清理事件监听&#xff08;避…...

uniapp的适配方式

文章目录 前言✅ 一、核心适配方式对比&#x1f4cf; 二、rpx 单位&#xff1a;uni-app 的核心适配机制&#x1f9f1; 三、默认设计稿适配&#xff08;750宽&#xff09;&#x1f501; 四、字体 & 屏幕密度适配&#x1f6e0; 五、特殊平台适配&#xff08;底部安全区、刘海…...

Java面试场景:从音视频到AI应用的技术探讨

面试场景&#xff1a;音视频与AI应用技术的碰撞 在某互联网大厂的面试中&#xff0c;面试官王先生与求职者明哥展开了一场关于音视频技术与AI应用的对话。 第一轮提问&#xff1a;音视频场景 面试官&#xff1a;明哥&#xff0c;你能谈谈在音视频场景中&#xff0c;Spring B…...

es聚合-词条统计

es语句 ---普通结构----"tags":{"type": "keyword","index": true},GET /knowledge_test/_search {"size": 0,"aggs": {"tag_count": {"terms": {"field": "tags",&quo…...

【沉浸式求职学习day43】【Java面试题精选3】

沉浸式求职学习 1.Java中this和super的区别2.为什么返回类型不算方法重载3.方法重写时需要注意什么问题4.深克隆和浅克隆有什么区别5.如何实现深克隆6.什么是动态代理7.静态代理和动态代理的区别8.如何实现动态代理&#xff1f;9.JDK Proxy 和 CGLib 有什么区别&#xff1f;10.…...

OpenAI推出Codex — ChatGPT内置的软件工程Agents

OpenAI继续让ChatGPT对开发者更加实用。 几天前,他们增加了连接GitHub仓库的支持,可以"Deep Research"并根据你自己的代码提问。 今天,该公司在ChatGPT中推出了Codex的研究预览版,这是迄今为止最强大的AI编码Agent。 它可以编写代码、修复错误、运行测试,并在…...

Win 11开始菜单图标变成白色怎么办?

在使用windows 11的过程中&#xff0c;有时候开始菜单的某些程序图标变成白色的文件形式&#xff0c;但是程序可以正常打开&#xff0c;这个如何解决呢&#xff1f; 这通常是由于快捷方式出了问题&#xff0c;下面跟着操作步骤来解决吧。 1、右键有问题的软件&#xff0c;打开…...