数据库用户登录验证及注册功能实现

1.mysql数据库安装

(1)安装及环境配置参考链接: MySQL数据库的安装与配置.
(2)安装参考链接:Windows环境安装mysql8.0.
此处最好按照第一个连接步骤来。
安装的方式有所不同,因本人的机器无法直接使用mysql的程序自动安装,故采用免安装方式即第2个连接。但此链接没有环境变量配置的步骤,故可参考第一个连接。

2.解决navicat连接mysql的密码错误问题

链接地址: 解决Navicat for MySQL 连接 Mysql 8.0.11 出现1251- Client does not support authentication protocol 错误.

3.创建数据库、用户表、插入数据

(1)进入mysql数据库

此处能直接在cmd进入数据库,是前面环境变量配置好了的缘故,若未配置好,则无法进入。在这里插入图片描述

(2) 创建数据库dnn_learning,用户表users,及插入用户数据到用户表

注意: 此处的密码,使用了MD5加密,故在数据库中不会明文显示

mysql>  create database dnn_learning;                                                                                                                    
mysql>  use dnn_learning;                                                                                   
mysql>  create table users(                                                                    
            id int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,                              
            username varchar(64) NOT NULL UNIQUE,                                                
            password varchar(32) NOT NULL                                                             
        );                                                                                 
mysql>   insert into users values(1, 'admin', md5('admin'));  

(3)创建好的数据库如下

使用控制台查看:
在这里插入图片描述
使用数据库管理工具查看:
在这里插入图片描述

4.VS2017属性配置

(1)首先将数据库的环境变量配置好,在前面已经配置好了,这里就不用配置了
(2)配置VS的属性,调用mysql库的功能,以此来连接数据库获取数据。
第一步:打开mysql的安装目录,默认安装目录如下:C:\Program Files\MySQL\MySQL Server 8.0,确认 lib 目录和include 目录是否存在。

第二步:打开VS2019,新建一个空工程,控制台应用程序即可,注意:解决方案平台选择 X64
在这里插入图片描述
第三步:右击工程名,打开属性页
在这里插入图片描述
第四步:打开VC++目录,在包含目录中,将mysql安装文件中的include文件的路径添加到这里
在这里插入图片描述

第五步:打开VC++目录,在库目录中将mysql文件中的lib文件路径添加进来
在这里插入图片描述
第六步:在属性页的链接器中,点击“输入”,将mysql安装文件夹中lib目录下的libmysql.lib文件加到“附加依赖项”中,注意,这里直接把libmysql.lib这个依赖名加进去即可,不要加路径。
在这里插入图片描述
第七步:把mysql安装目录里的lib\libmysql.dll复制到c:\windows\system32下

5.建立MFC应用程序

(1)新建MFC应用程序,并配置好其属性后

界面搭建如下
在这里插入图片描述

(2)解决文字字体及其大小问题

参考链接: MFC下改变窗口或编辑框标题字体大小的方法.
安照上面链接操作后,运行程序初始化的过程改变了字体大小,显示如下:
在这里插入图片描述

(3)后加入的对话框如何在初始化首先显示

进入主程序的cpp文件,注意是开始建立mfc应用时就有的cpp文件,不带Dlg.cpp的cpp文件,在里面找到InitInstance()函数。
在这里插入图片描述

(4)如何在打开新对话框的同时关闭本对话框

//如果登录成功就打开主程序界面,同时关闭本窗口
	CDialog::OnCancel();			//关闭本窗口
	CDNNLearningDlg dlg;
	//dlg.user = user;		//将本窗口获得的用户传递给下一窗口,如果还需大量信息,可以声明万能指针
	dlg.DoModal();		//打开对话框

6.所有程序代码

此处有database.h与database.cpp文件,主要用来连接数据库,对数据库的查询、添加数据等操作都在这里。
而有关界面的应用程序在LoginDlg.h及LoginDlg.cpp中。

(1)database.h

#pragma once

#include <string>

using namespace std;

#define LINE 48
#define COLUMN 48 


/*在数据库中用户表的信息(对应表的信息要构建对应的结构体)
id |
username |
password |
address_id |
*/

//用户信息
typedef struct _userinfo {
	int id;				//用户id
	string username;	//用户名
	string password;	//密码
	//int address_id;		//其他表的相关id,后续可以添加,如图片的本机地址等数据表
}userinfo;


//用于从数据库中将对于的账号名称和密码对应的id和关卡id得到
bool fetch_user_info(userinfo &user);

//用于注册用户,即在数据库中插入用户表的信息,新加用户
bool insert_user(userinfo& user);

(2)database.cpp

#include "pch.h"
#include "database.h"
#include <mysql.h>
#include <stdio.h>


#define DB_NAME  "dnn_learning"
#define DB_HOST  "127.0.0.1"
#define DB_PORT  3306
#define DB_USER  "root"
#define DB_USER_PASSWD  "password"

static int debug = 1;		//用于打印调试信息的,正是发布时可以改成0,就不会打印调试信息了

static bool connect_db(MYSQL &mysql);		//static只对当前文件有效

/*****************************************
*功能:通过用户名和密码从数据库获取用户信息
*输入:
*		user - 用户信息结构体
*返回值:
*		获取成功返回true,失败false
******************************************/
bool fetch_user_info(userinfo &user) {
	//要定义一个句柄,连接数据库都要使用
	MYSQL mysql;
	MYSQL_RES* res; //查询结果集
	MYSQL_ROW row;  //记录结构体
	char sql[256];		//一般定义256个就足够了
	bool ret = false;

	//1.连接到数据库
	if (connect_db(mysql) == false) {
		return false;
	}

	//2.根据用户名和密码获取用户信息(id,level_id)
	//select id, level_id表明只查询这两个值在条件用户名和密码的情况下
	snprintf(sql, 256, "select id from users where username='%s' and password=md5('%s');", user.username.c_str(), user.password.c_str());	//将查询语句放到sql中
	ret = mysql_query(&mysql, sql); //执行查询mysql_query,成功返回0

	if (ret) {
		//printf("数据库查询出错,%s 错误原因: %s\n", sql, mysql_error(&mysql));
		mysql_close(&mysql);			//当出错了后要关闭连接,释放资源
		return false;
	}

	//3.获取结果
	res = mysql_store_result(&mysql);		//将获取的结果放到res,获得结果集
	//记录可能有多行,允许一条一条的拿出来
	row = mysql_fetch_row(res);				//从结果集中取行,实际row是个指针变量

	if (row == NULL) {					//没有查找到记录
		mysql_free_result(res);			//一旦取到了res,就需要释放在结束连接的时候
		mysql_close(&mysql);			//当出错了后要关闭连接,
		return false;
	}

	//row保存的是字符串,在前面的select id, level_id from,说明结果中有row[0]和row[1]两个
	//下面是将字符串变成整型,并将转换成的结果打印出来
	user.id = atoi(row[0]);
	//if (debug) printf("userid: %d\n", user.id);  //打印ID

	//4.关闭连接、释放资源
	//释放结果集
	mysql_free_result(res);

	//关闭数据库
	mysql_close(&mysql);

	return true;
}

//用于插入用户信息(不需要像前面一样拿到数据库结果集,写入即可)
/*****************************************
*功能:注册用户
*输入:
*		user - 用户信息结构体(里面包含要输入到数据库中的账号密码)
*返回值:
*		获取成功返回true,失败false
******************************************/
bool insert_user(userinfo& user) {
	//要定义一个句柄,连接数据库都要使用
	MYSQL mysql;
	MYSQL_RES* res; //查询结果集
	MYSQL_ROW row;  //记录结构体
	char sql[256];		//一般定义256个就足够了
	bool ret = false;

	//1.连接到数据库
	if (connect_db(mysql) == false) {
		return false;
	}

	//2. 直接插入用户数据,mysql语句id为主键,可以自增,不用设定插入的数据insert into users values(1, 'admin', md5('admin'));
	snprintf(sql, 256, "insert into users values(NULL, '%s', md5('%s'));", user.username.c_str(), user.password.c_str());

	ret = mysql_query(&mysql, sql);

	//当出错了,可以使用此排除错误
	if (ret) {
		printf("数据库查询出错,%s 错误原因: %s\n", sql, mysql_error(&mysql));
		mysql_close(&mysql);			//当出错了后要关闭连接,释放资源
		return false;
	}

	//4.关闭连接、无需释放结果集(此处不是查询结果,而是写入数据)
	//关闭数据库
	mysql_close(&mysql);

	return true;
}


//1.连接到数据库
bool connect_db(MYSQL &mysql) {
	//1.初始化数据库句柄
	mysql_init(&mysql);

	//2.设置字符编码
	//因为右击控制台,属性gbk编码,需要显示到控制台故需要gbk编码,别的编码可能
	mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, "gbk");//(给句柄设置字符编码),在windows上基本gbk字符集

	//3.连接到数据库
	//通过网络连接服务器并通信,此函数接口mysql_real_connect
	if (mysql_real_connect(&mysql, DB_HOST, DB_USER, DB_USER_PASSWD, DB_NAME, DB_PORT, NULL, 0) == NULL) {
		printf("数据库连接出错, 错误原因: %s\n", mysql_error(&mysql));
		return false;
	}

	return true;
}

(3)LoginDlg.h

#pragma once
#include "database.h"

// LoginDlg 对话框

class LoginDlg : public CDialogEx
{
	DECLARE_DYNAMIC(LoginDlg)

public:
	LoginDlg(CWnd* pParent = nullptr);   // 标准构造函数
	virtual ~LoginDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_LOGIN_DIALOG };
#endif

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnBnClickedBtnRegister();
	afx_msg void OnBnClickedBtnLogin();
	// 登录界面的账号
	CEdit m_userName;
	// 登录界面的密码
	CEdit m_passWord;
	userinfo user;
	virtual BOOL OnInitDialog();
	//用来专门改变字体大小的类CFont,与static配合使用
	static CFont one1;
	// //标题名称
	CStatic m_staticT1;
};

(4)LoginDlg.cpp

// LoginDlg.cpp: 实现文件
//

#include "pch.h"
#include "DNN_Learning.h"
#include "LoginDlg.h"
#include "afxdialogex.h"
#include "DNN_LearningDlg.h"

CFont LoginDlg::one1;

// LoginDlg 对话框

IMPLEMENT_DYNAMIC(LoginDlg, CDialogEx)

LoginDlg::LoginDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_LOGIN_DIALOG, pParent)
{

}

LoginDlg::~LoginDlg()
{
}

void LoginDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT_UserName, m_userName);
	DDX_Control(pDX, IDC_EDIT_PassWord, m_passWord);
	DDX_Control(pDX, IDC_STATIC_T1, m_staticT1);
}


BEGIN_MESSAGE_MAP(LoginDlg, CDialogEx)
	ON_BN_CLICKED(IDC_BTN_Register, &LoginDlg::OnBnClickedBtnRegister)
	ON_BN_CLICKED(IDC_BTN_Login, &LoginDlg::OnBnClickedBtnLogin)
END_MESSAGE_MAP()


// LoginDlg 消息处理程序

BOOL LoginDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// TODO:  在此添加额外的初始化
	//设置static字体类型及大小
	one1.CreatePointFont(200, _T("宋体"));  //字体和大小根据自己的需要自行改变
	m_staticT1.SetFont(&one1);             //将字体和想要改变的框体变量进行关联

	return TRUE;  // return TRUE unless you set the focus to a control
				  // 异常: OCX 属性页应返回 FALSE
}

//注册
void LoginDlg::OnBnClickedBtnRegister()
{
	// TODO: 在此添加控件通知处理程序代码
	CString userName, passWord;
	m_userName.GetWindowTextW(userName);
	m_passWord.GetWindowTextW(passWord);

	//判断输入是否为空
	if (userName.IsEmpty() || passWord.IsEmpty()) {
		AfxMessageBox(_T("账号或者密码为空,请输入!"));
		return;
	}

	//判断账号密码是否已经存在,若存在,无需再次注册
	//将CString转换成string类型,后续判断时会使用
	//userinfo user;		//窗口类变量,表名当前用户的身份
	user.username = CW2A(userName.GetString());
	user.password = CW2A(passWord.GetString());

	//调用database.h中的函数判断,用户密码是否匹配,为真,证明登录成功
	bool ret = false;
	ret = fetch_user_info(user);

	if (ret == true) {
		AfxMessageBox(_T("账号及密码已经存在,无需再次注册!"));
		return;
	}

	//进行用户的注册操作
	insert_user(user);
}

//登录
void LoginDlg::OnBnClickedBtnLogin()
{
	// TODO: 在此添加控件通知处理程序代码
	CString userName,passWord;
	m_userName.GetWindowTextW(userName);
	m_passWord.GetWindowTextW(passWord);

	//判断输入是否为空
	if (userName.IsEmpty() || passWord.IsEmpty()) {
		AfxMessageBox(_T("账号或者密码为空,请输入!"));
		return;
	}

	//判断账号密码是否正确
	//将CString转换成string类型,后续判断时会使用
	//userinfo user;		//窗口类变量,表名当前用户的身份
	user.username = CW2A(userName.GetString());
	user.password = CW2A(passWord.GetString());

	//调用database.h中的函数判断,用户密码是否匹配,为真,证明登录成功
	bool ret = false;
	ret = fetch_user_info(user);

	if (ret == false) {
		//当返回是可以给个重试的机会
		AfxMessageBox(_T("账号或者密码错误,请重新输入或者再次注册!"));
		return;
	}

	//如果登录成功就打开主程序界面,同时关闭本窗口
	CDialog::OnCancel();			//关闭本窗口
	CDNNLearningDlg dlg;
	//dlg.user = user;		//将本窗口获得的用户传递给下一窗口,如果还需大量信息,可以声明万能指针
	dlg.DoModal();			//打开新的窗口
}

  • 0
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吾名招财

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值