Chap10-ResetPassword
Chat10-ResetPassword
流程
整体流程那个和忘记密码几乎机制,qt客户端可以直接照搬代码,改一改参数,基本的框架打好了就会非常省时。
#ifndef FORGOTSCREEN_H
#define FORGOTSCREEN_H
#include <QWidget>
#include "../Properties/global.h"
class QLabel;
class QLineEdit;
class QPushButton;
class QFormLayout;
class ForgotScreen : public QWidget
{
Q_OBJECT
public:
explicit ForgotScreen(QWidget *parent = nullptr);
void setupUI();
void setupConnections();
private:
QFormLayout *formLayout;
QLabel *headerLabel;
QLabel *labelForHeader;
QLineEdit *accountEdit;
QLineEdit *emailEdit;
QLineEdit *securityCode;
QPushButton *getSecurityCode;
QLineEdit *newPasswordEdit;
QLineEdit *confirmNewPasswordEdit;
QAction *showNewPwdAction;
QAction *showConfirmPwdAction;
QPushButton *acceptBtn;
QPushButton *cancleBtn;
QHash<RequestType,std::function<void(const QJsonObject&)>> _handlers;
int countdown = 10;
QTimer *timer;
private:
// 定时改变获取按钮的文字
void do_change_get_code_btn();
// 获取验证码
void do_get_code_clicked();
void do_get_code_finished(RequestType requestType,const QString&res,ErrorCodes errorCode);
// 注册
void do_forgot_clicked();
void do_forgot_finished(RequestType requestType,const QString&res,ErrorCodes errorCode);
public:
void showTip(int code,const QString &str="忘记密码");
bool doVerify(bool includingSecurityCode=false);
void initHttpHandlers();
signals:
void goLogin();
void readyGoLogin();
};
#endif // FORGOTSCREEN_H
后端
后端需要做的就是在上层处理类中添加对于修改密码路由的回调函数,同时添加MysqlManager和MysqlDao对数据库的读写。
// LogicSystem
RegistHandlers("/resetPassword", RequestType::POST, [this](std::shared_ptr<Session> session) {
auto body_str = beast::buffers_to_string(session->_request.body().data());
std::cout << "receive userRegister request, body: " << body_str << std::endl;
session->_response.set(http::field::content_type, "text/json");
json j = json::parse(body_str);
if (j.is_null() || j.is_discarded()) {
std::cout << "无效json" << std::endl;
j["error"] = ErrorCodes::ERROR_JSON;
std::string str = j.dump(4);
beast::ostream(session->_response.body()) << str;
return true;
}
auto email = j["email"].get<std::string>();
auto password = j["password"].get<std::string>();
auto securityCode = j["securityCode"].get<std::string>();
int uid = MysqlManager::GetInstance()->TestEmail(email);
if (uid == 0 || uid == -1) {
std::cout << "邮箱不存在" << std::endl;
j["error"] = ErrorCodes::ERROR_EMAIL_NOTFOUND;
std::string str = j.dump(4);
beast::ostream(session->_response.body()) << str;
return true;
}
std::string code;
bool get_code_success = RedisManager::GetInstance()->Get(EMAIL_PREFIX + email, code);
if (!get_code_success) {
std::cout << "验证码获取失败" << std::endl;
j["error"] = ErrorCodes::ERROR_SECURITYCODE_EXPIRED;
std::string str = j.dump(4);
beast::ostream(session->_response.body()) << str;
return true;
} else if (code != securityCode) {
std::cout << "验证码错误" << std::endl;
j["error"] = ErrorCodes::ERROR_SECURITYCODE_NOTFOUND;
std::string str = j.dump(4);
beast::ostream(session->_response.body()) << str;
return true;
}
uid = MysqlManager::GetInstance()->ResetPassword(email, password);
if (uid == 0 || uid == -1) {
std::cout << "注册失败" << std::endl;
j["error"] = ErrorCodes::RPCFAILED;
std::string str = j.dump(4);
beast::ostream(session->_response.body()) << str;
return true;
}
j["success"] = true;
j["error"] = ErrorCodes::SUCCESS;
j["message"] = "密码修改成功";
std::string str = j.dump(4);
beast::ostream(session->_response.body()) << str;
return true;
});
上层调用类中先验证邮箱是否正确(TestEmail),然后再执行密码修改操作(ResetPassword).
下面是mysql层的操作
int MysqlManager::ResetPassword(const std::string& email, const std::string& password)
{
return _dao.ResetPassword(email, password);
}
int MysqlDao::ResetPassword(const std::string& email, const std::string& password)
{
auto conn = _pool->GetConnection();
try {
if (conn == nullptr) {
_pool->ReturnConnection(std::move(conn));
return false;
}
MYSQL_STMT* stmt = mysql_stmt_init(conn.get());
std::string query = "update user set password = ? where email = ?";
if (mysql_stmt_prepare(stmt, query.c_str(), query.size()) != 0) {
std::cout << mysql_error(conn.get()) << std::endl;
mysql_stmt_close(stmt);
_pool->ReturnConnection(std::move(conn));
return -1;
}
MYSQL_BIND params[2];
memset(params, 0, sizeof(params));
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)password.c_str();
params[0].buffer_length = password.size();
params[0].length = ¶ms[0].buffer_length;
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)email.c_str();
params[1].buffer_length = email.size();
params[1].length = ¶ms[1].buffer_length;
if (mysql_stmt_bind_param(stmt, params) != 0) {
std::cout << mysql_stmt_error(stmt) << std::endl;
mysql_stmt_close(stmt);
_pool->ReturnConnection(std::move(conn));
return -1;
}
if (mysql_stmt_execute(stmt) != 0) {
mysql_stmt_close(stmt);
_pool->ReturnConnection(std::move(conn));
return -1;
}
if (mysql_stmt_store_result(stmt) != 0) {
mysql_stmt_close(stmt);
_pool->ReturnConnection(std::move(conn));
return -1;
}
my_ulonglong affected_rows = mysql_stmt_affected_rows(stmt);
if (affected_rows == (my_ulonglong)-1) {
std::cerr << "Error getting affected rows" << std::endl;
mysql_stmt_close(stmt);
return false;
}
mysql_stmt_close(stmt);
_pool->ReturnConnection(std::move(conn));
return 1; // 返回1表示重置密码成功
} catch (const std::exception& e) {
if (conn != nullptr) {
_pool->ReturnConnection(std::move(conn));
}
std::cerr << "Exception: " << e.what() << std::endl;
return -1;
}
return 0;
}
感想
可以看出和注册界面几乎一模一样,就是需要新加新的处理路径,处理函数,c++同时实现起来比较麻烦而已。我们熟悉之后,对于基本的流程操作,cv可以加快进程。

浙公网安备 33010602011771号