C++基于MFC课程设计——在线聊天室与图书资源共享

学习公社


开发语言:C++
使用工具:Visual Studio2019,MySQL,navicat
开发者:xxlzdf
csdn源码及项目所用库下载:xxlzdf-学习公社源码及表结构


一、系统使用展示

在这里插入图片描述


二、系统主要结构

1.系统功能介绍

1.基本注册登录,用户注册后登陆,忘记密码修改密码等;
2.聊天室功能:使用udp协议广播发送接收信息;
3.搜索资源功能:搜索服务器相应类别的所有资源;
4.上传/下载功能:上传资源到服务器、从服务器下载资源到本地;
5.查看用户信息功能:查看个人信息,并签到获得积分。


2.数据库表的设计

用户表

在这里插入图片描述

资源表

在这里插入图片描述


3.MySQL数据库与vs连接

在之前的博客C++基于MFC——课程管理系统中有详细介绍传送门


三、主要源代码及分析:

头文件
在这里插入图片描述

源文件
在这里插入图片描述

对话框文件
在这里插入图片描述


VS和MySQL的连接

连接MySQL所需成员变量在头文件中定义初始化

MYSQL* conn;
MYSQL_RES* res;
MYSQL_ROW row;
const char* server = "localhost";
const char* user = "root";
const char* password = "123";  
const char* database = "system";

本地搭建FTP服务器

本项目资源共享部分服务器端基于FTP服务器,链接为本地搭建FTP服务器的教程Windows下搭建FTP服务器


1.用户登录界面

用户登录

在这里插入图片描述

功能:用户的注册、登录和修改密码主页面
分析:获取控件Edit中输入的字符串,并对空白输入进行处理。
登录用到用户表,通过输入的用户名搜索用户名和密码是否匹配,匹配则登陆成功。
另外设置了匿名登录功能,供游客直接登录使用,方便可以下载项目直接进行程序的测试。

void CsystemDlg::OnBnClickedOk()
{
	// TODO: 在此添加控件通知处理程序代码
	CString name, pass;
	GetDlgItemText(IDC_EDIT_NAME, name);
	GetDlgItemText(IDC_EDIT_PASS, pass);
	if (!name.GetLength())
	{
		MessageBox(L"用户名不能为空!", L"提示");
		return;
	}
	else if(!pass.GetLength())
	{
		MessageBox(L"密码不能为空!", L"提示");
		return;
	}
	conn = mysql_init(NULL);
	if (0 == mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gbk"))//设置字符集
	{
		cout << "设置字符集成功\n\n" << endl;
	}
	// connect to database
	if (!mysql_real_connect(conn, server, user, password, database, 3306, NULL, 0))
	{
		std::cout << stderr << "%s\n" << mysql_error(conn);
		return ;
	}
	CString sql;
	sql.Format(_T("select * from user where User_Name='%s'"), name);
	USES_CONVERSION;
	char* mysql = T2A(sql);
	if (mysql_query(conn, mysql))
	{
		MessageBox(_T("查询数据出错"), _T("警告"), MB_OK);
		return;
	}
	res = mysql_use_result(conn);
	if ((row = mysql_fetch_row(res)) != NULL)
	{
		if ((CString)row[2] != pass)
		{
			MessageBox(_T("用户名或密码错误!"), _T("警告"), MB_OK);
			Password.SetWindowText(L"");
			return;
		}
		else
		{
			MessageBox(_T("登录成功"), _T("提示"), MB_OK);
			Meun m(name);
			m.DoModal();
			return;
		}
	}
	else
	{
		MessageBox(_T("用户名或密码错误!"), _T("警告"), MB_OK);
		Password.SetWindowText(L"");
	}
	mysql_close(conn);
}

void CsystemDlg::OnBnClickedButtonNoname()//匿名登录
{
	// TODO: 在此添加控件通知处理程序代码
	CString cr = L"匿名用户";
	Login.SetWindowText(cr);
	Password.SetWindowText(L"******");
	Meun m(cr);
	m.DoModal();
}

void CsystemDlg::OnBnClickedButtonReg()//注册
{
	// TODO: 在此添加控件通知处理程序代码
	Register reg;
	reg.DoModal();
}

void CsystemDlg::OnBnClickedButtonFog()//忘记密码
{
	// TODO: 在此添加控件通知处理程序代码
	AlterPass alt;
	alt.DoModal();
}

用户注册

在这里插入图片描述

功能:用户的注册
分析:注册需要用户输入详细的个人信息,我们需要对输入进行非空判断,并检查输入密码和确认密码是否一致。都满足条件则向用户表中添加注册的一条记录。
为了用户表记录保持唯一性,我们在获取输入的用户名和邮箱后先查询表中的记录,如果有重复则提示用户名/邮箱已被注册,我们要求注册用户重新填写用户名和邮箱进行注册。
注册成功后,即赠送5个积分用于资源共享。这里只需要在注册插入时默认插入字段User_Score = 5.

void Register::OnBnClickedOk()
{
	// TODO: 在此添加控件通知处理程序代码
	CString name, mail, age, pass, pass2;
	GetDlgItemText(IDC_EDIT_NAME, name);
	GetDlgItemText(IDC_EDIT_MAIL, mail);
	GetDlgItemText(IDC_EDIT_AGE, age);
	GetDlgItemText(IDC_EDIT_PASS, pass);
	GetDlgItemText(IDC_EDIT_PASS2, pass2);
	conn = mysql_init(NULL);//conn分配初始化MySQL对象
	if (0 == mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gbk"))//设置字符集
	{

	}
	// connect to database
	if (!mysql_real_connect(conn, server, user, password, database, 3306, NULL, 0))
	{
		MessageBox(_T("没有获得数据库连接"), _T("警告"), MB_OK);
		return;
	}
	if (!name.GetLength()) MessageBox(L"用户名不能为空!", L"提示");
	else if (!mail.GetLength()) MessageBox(L"邮箱不能为空!", L"提示");
	else if (!age.GetLength()) MessageBox(L"年龄不能为空!", L"提示");
	else if (!pass.GetLength()) MessageBox(L"密码不能为空!", L"提示");
	else if (!pass2.GetLength()) MessageBox(L"确认密码不能为空!", L"提示");
	else
	{
		CString s, e;
		s.Format(L"Select * from user where User_Name='%s'", name);
		e.Format(L"Select * from user where User_Mail='%s'", mail);
		USES_CONVERSION;
		char* mysql = T2A(s);
		char* mysql2 = T2A(e);
		if (mysql_query(conn, mysql))//mysql_query(mysql连接,想要进行的查询语句)
		{
			MessageBox(_T("查询数据出错"), _T("警告"), MB_OK);
			mysql_close(conn);
			return;
		}
		res = mysql_use_result(conn);
		if ((row = mysql_fetch_row(res))!=NULL)
		{
			MessageBox(L"该用户名已存在!", L"警告");
		}
		else
		{
			if (mysql_query(conn, mysql2))//mysql_query(mysql连接,想要进行的查询语句)
			{
				MessageBox(_T("查询数据出错"), _T("警告"), MB_OK);
				mysql_close(conn);
				return;
			}
			res = mysql_use_result(conn);
			if ((row = mysql_fetch_row(res)) != NULL)
			{
				MessageBox(L"该邮箱已被注册!", L"警告");
			}
			else if (pass != pass2)
			{
				MessageBox(L"两次输入密码不一致!", L"提示");
			}
			else
			{
				CString sql;
				int age1 = _ttoi(age);
				sql.Format(L"Insert into user(User_Name,User_Pass,User_Score,User_Age,User_Mail,User_Last_Login) VALUES('%s', '%s', '%d', '%d', '%s','00:00:00')", name, pass, 5, age1, mail);
				//USES_CONVERSION;
				mysql = T2A(sql);
				if (mysql_query(conn, mysql))
				{
					MessageBox(_T("注册失败!"), _T("警告"), MB_OK);
					mysql_close(conn);
					return;
				}
				MessageBox(L"注册成功,赠送您5积分!", L"提示", MB_OK);
				mysql_close(conn);
				CDialog::OnOK();
			}
		}
	}
}

忘记密码

在这里插入图片描述

功能:用户修改密码
分析:找回密码首先对输入进行非空判断
我们需要用户填写正确的用户名及邮箱,且要求用户名邮箱匹配同一条记录(同一个用户),并检查两次输入密码是否一致,一致则修改表中记录的内容。

void AlterPass::OnBnClickedOk()
{
	// TODO: 在此添加控件通知处理程序代码
	CString name, mail, pass, pass2;
	GetDlgItemText(IDC_EDIT_NAME, name);
	GetDlgItemText(IDC_EDIT_MAIL, mail);
	GetDlgItemText(IDC_EDIT_PASS, pass);
	GetDlgItemText(IDC_EDIT_PASS2, pass2);
	conn = mysql_init(NULL);//conn分配初始化MySQL对象
	if (0 == mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gbk"))//设置字符集
	{

	}
	// connect to database
	if (!mysql_real_connect(conn, server, user, password, database, 3306, NULL, 0))
	{
		MessageBox(_T("没有获得数据库连接"), _T("警告"), MB_OK);
		return;
	}
	if (!name.GetLength()) MessageBox(L"用户名不能为空!", L"提示");
	else if (!mail.GetLength()) MessageBox(L"邮箱不能为空!", L"提示");
	else if (!pass.GetLength()) MessageBox(L"新密码不能为空!", L"提示");
	else if (!pass2.GetLength()) MessageBox(L"确认密码不能为空!", L"提示");
	else
	{
		CString s;
		s.Format(L"Select * from user where User_Name='%s'", name);
		USES_CONVERSION;
		char* mysql = T2A(s);
		if (mysql_query(conn, mysql))//mysql_query(mysql连接,想要进行的查询语句)
		{
			MessageBox(_T("查询数据出错"), _T("警告"), MB_OK);
			mysql_close(conn);
			return;
		}
		res = mysql_use_result(conn);
		if ((row = mysql_fetch_row(res)) != NULL)
		{
			mysql_close(conn);
			if(mail==(CString)row[5])
			{
				if (pass != pass2)
				{
					MessageBox(L"两次输入密码不一致!", L"提示");
				}
				else
				{
					RevisePass(name, pass);
					CDialog::OnOK();
				}
			}
			else
			{
				MessageBox(L"请填写正确的邮箱!", L"警告");
				Edit_Mail.SetWindowText(_T(""));//添加清空操作
			}
		}
		else
		{
			MessageBox(L"该用户不存在!", L"警告");
			Edit_Name.SetWindowText(_T(""));//添加清空操作
		}
	}
}

void AlterPass::RevisePass(CString name,CString pass)
{
	CString sql;
	sql.Format(L"update user set User_Pass='%s' where User_Name='%s'", pass, name);
	USES_CONVERSION;
	char* mysql = T2A(sql);
	conn = mysql_init(NULL);//conn分配初始化MySQL对象
	if (0 == mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gbk"))//设置字符集
	{

	}
	// connect to database
	if (!mysql_real_connect(conn, server, user, password, database, 3306, NULL, 0))
	{
		MessageBox(_T("没有获得数据库连接"), _T("警告"), MB_OK);
		return ;
	}
	if (mysql_query(conn, mysql))
	{
		MessageBox(_T("更新失败!"), _T("警告"), MB_OK);
		mysql_close(conn);
		return;
	}
	MessageBox(L"密码修改成功!", L"提示", MB_OK);
	mysql_close(conn);
}

2.菜单

菜单展示

在这里插入图片描述

功能:菜单功能
分析:添加其他类的头文件,每个按钮的点击事件下定义相应的对象,访问对象的对话框,并向其传入登录用户的用户名。

void Meun::OnBnClickedButtonChat()//聊天室
{
	Chat_Room ch(str);
	ch.DoModal();
	// TODO: 在此添加控件通知处理程序代码
}

void Meun::OnBnClickedCancel()//退出按钮
{
	// TODO: 在此添加控件通知处理程序代码
	int m=MessageBox(_T("退出程序?") ,_T("提示"), MB_OKCANCEL);
	if(m==1) CDialog::OnCancel();
}

void Meun::OnBnClickedButtonUp()//资源分享
{
	// TODO: 在此添加控件通知处理程序代码
	FtpClient Ftp(str);
	Ftp.DoModal();
}

void Meun::OnBnClickedButtonView()//查看个人信息
{
	// TODO: 在此添加控件通知处理程序代码
	Self_Infor sif(str);
	sif.DoModal();
}

void Meun::OnBnClickedButtonSch()//资源搜索
{
	// TODO: 在此添加控件通知处理程序代码
	Book_Search book;
	book.DoModal();
}

3.聊天室

利用UDP协议实现

在这里插入图片描述

功能:在局域网中实现聊天功能
分析:用户在局域网上发送广播消息,同时也接受其他用户发送的广播消息,收到的信息显示在上面的列表框中,下面的文本框用于编辑用户要广播发送的信息。
需要在OnInitDialog()中创建套接字并绑定本地地址,并调用WSAAsyncSelect()函数用于接收信息的数据报套接字注册FD_READ网络事件
在利用sendto发送数据时,需要将提取的字符串在Unicode下由CString类型转换为const char*类型。

BOOL Chat_Room::OnInitDialog()
{
	CDialog::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标
	
	// TODO: 在此添加额外的初始化代码
	udpsock = socket(AF_INET, SOCK_DGRAM, 0);
	int vsize = sizeof(BOOL);
	BOOL yes = TRUE;
	setsockopt(udpsock, SOL_SOCKET, SO_BROADCAST, (char*)&yes, vsize);

	struct sockaddr_in localaddr;
	int len = sizeof(struct sockaddr_in);
	localaddr.sin_family = AF_INET;
	localaddr.sin_port = htons(PORT);
	localaddr.sin_addr.s_addr = INADDR_ANY;
	if (bind(udpsock, (sockaddr*)&localaddr, len) == SOCKET_ERROR)
	{
		MessageBox(_T("bind local address error!"));
		closesocket(udpsock);
		WSACleanup();
		return 0;
	}
	if (WSAAsyncSelect(udpsock, m_hWnd, RECVMSG, FD_READ) != 0)
		MessageBox(_T("套接字消息注册失败!"));
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

afx_msg LRESULT Chat_Room::OnRecvmsg(WPARAM wParam, LPARAM lParam)
{
	char buf[1000];
	CString str;
	int a;
	a = recvfrom(udpsock, buf, sizeof(buf), 0, NULL, NULL);
	if (a > 0)
	{
		//MessageBox((LPCTSTR)(buf));
		str.Format(_T("%s:%s"), tr, buf);//tr为登录用户的用户名
		m_List.AddString(str);
	}
	return 0;
}

void Chat_Room::OnBnClickedOk()
{
	// TODO: 在此添加控件通知处理程序代码
	CString str;
	GetDlgItemText(IDC_EDIT1, str);
	if (!str.GetLength())
	{
		MessageBox(L"输入消息不能为空!", L"提示");
		return;
	}
	struct sockaddr_in  broadcastaddr;//广播地址
	int len = sizeof(broadcastaddr);
	broadcastaddr.sin_family = AF_INET;
	broadcastaddr.sin_port = htons(PORT);
	broadcastaddr.sin_addr.s_addr = INADDR_BROADCAST;
	UpdateData();
	//Unicode下CString转换到const char*
	sendto(udpsock, (LPCSTR)(LPCTSTR)str, 1000, 0, (struct sockaddr*)&broadcastaddr, len);
	GetDlgItem(IDC_EDIT1)->SetWindowText(_T(""));//点击发送后将Edit中的字清空
}

void Chat_Room::OnBnClickedCancel()
{
	// TODO: 在此添加控件通知处理程序代码
	closesocket(udpsock);
	CDialog::OnCancel();
}

4.资源共享

利用FTP服务器实现

本对话框改编于FTP基于MFC对话框实现与服务器文件传输,感谢大佬的思路以及源代码。

上传资源

在这里插入图片描述
本项目的服务器端基于windowsFTP服务器,上传时需要用户至少选择一个类别上传。
在这里插入图片描述
这里我们利用CString filename = strname.Left(n);取出文件名,CString category = strdir.Right(strdir.GetLength()-1); 取出文件夹名。
文件夹名就是上传资源的类别,我们可以利用文件名和文件夹名作为Book_Name和Book_cate在数据库中添加记录。
还少了一个出版社名,这需要用户手动输入。

在这里插入图片描述
上传成功后,获得5个积分。
在这里插入图片描述

void FtpClient::OnUpLoad()
{
	// TODO: 在此添加控件通知处理程序代码
	if (!bconnect)
	{
		MessageBox(L"请先连接FTP服务器!");
		return;
	}
	CString str;
	CString strname;
	//弹出“打开”对话框
	CFileDialog file(true, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("所有文件(*.*)|*.*|"), this);
	if (file.DoModal() == IDOK)
	{
		str = file.GetPathName();
		strname = file.GetFileName();
	}
	CString strdir;
	pFtpConnection->GetCurrentDirectory(strdir);

	//将文件名和类别取出来入库
	int n = strname.ReverseFind('.');
	CString	filename = strname.Left(n);//去掉后缀
	CString category = strdir.Right(strdir.GetLength()-1);  //去掉前缀
	//上传文件这里利用数据库查询限制不能上传库中已有的资源
	if (!filename.GetLength()) return;
	if (category.GetLength()-1==0)
	{
		MessageBox(L"请至少选择一个类别再上传", L"提示");
		return;
	}
	if (!Search(filename))
	{
		//上传文件
		BOOL bput = pFtpConnection->PutFile((LPCTSTR)str, (LPCTSTR)strname);
		//获取出版社
		Book_Pub book;
		book.DoModal();
		CString publisher=book.Get_Publish();//成员函数获取用户输入的出版社名
		//添加到数据库
		Add_Book(filename,category, publisher);
		if (bput)
		{
			pInternetSession->Close();//关闭会话
			this->ConnectFtp();//重新连接保持持续会话
			pFtpConnection->SetCurrentDirectory(strdir);
			this->UpdateDir();//更新目录列表
			if (tr != "匿名用户") Update_Score(tr);
			MessageBox(_T("上传成功!获得5积分!"), L"提示");
		}
	}
	else
	{
		MessageBox(L"上传失败,库中已有您的资源!", L"提示");
	}
}

void FtpClient::Add_Book(CString file,CString cate,CString publisher)
{
	conn = mysql_init(NULL);//conn分配初始化MySQL对象
	if (0 == mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gbk"))//设置字符集
	{

	}
	// connect to database
	if (!mysql_real_connect(conn, server, user, password, database, 3306, NULL, 0))
	{
		MessageBox(_T("没有获得数据库连接"), _T("警告"), MB_OK);
		return;
	}
	CString sql;
	sql.Format(L"insert into book(Book_Name,Book_Update_Times,Book_Cate,Book_Publish) values('%s', '0', '%s', '%s')", file,cate, publisher);
	USES_CONVERSION;
	char* mysql = T2A(sql);
	if (mysql_query(conn, mysql))
	{
		MessageBox(_T("插入数据出错"), _T("警告"), MB_OK);
		return;
	}
}

bool FtpClient::Search(CString name)
{
	conn = mysql_init(NULL);//conn分配初始化MySQL对象
	if (0 == mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gbk"))//设置字符集
	{

	}
	// connect to database
	if (!mysql_real_connect(conn, server, user, password, database, 3306, NULL, 0))
	{
		MessageBox(_T("没有获得数据库连接"), _T("警告"), MB_OK);
		return false;
	}
	CString sql;
	sql.Format(L"select * from book where Book_Name='%s'", name);
	USES_CONVERSION;
	char* mysql = T2A(sql);
	if (mysql_query(conn, mysql))
	{
		MessageBox(_T("查找数据出错"), _T("警告"), MB_OK);
		return false;
	}
	res = mysql_use_result(conn);
	if ((row = mysql_fetch_row(res)) != NULL) return true;
	else return false;
}

void FtpClient::Update_Score(CString str)
{
	conn = mysql_init(NULL);//conn分配初始化MySQL对象
	if (0 == mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gbk"))//设置字符集
	{

	}
	// connect to database
	if (!mysql_real_connect(conn, server, user, password, database, 3306, NULL, 0))
	{
		MessageBox(_T("没有获得数据库连接"), _T("警告"), MB_OK);
		return;
	}
	CString sql;
	sql.Format(L"update user set User_Score = User_Score +5 where User_Name='%s'", str);
	USES_CONVERSION;
	char* mysql = T2A(sql);
	if (mysql_query(conn, mysql))
	{
		MessageBox(_T("更新数据出错"), _T("警告"), MB_OK);
		return;
	}
	mysql_free_result(res);
	mysql_close(conn);
}

资源下载

下载时首先点击进入相应文件夹选择资源,再对用户记录进行查询,积分大于等于5可以下载,下载后扣除五个积分。
在这里插入图片描述
积分不足时则弹窗提示。
在这里插入图片描述

void FtpClient::OnDownload()
{
	// TODO: 在此添加控件通知处理程序代码
	CString selfile;
	if (!bconnect)
	{
		MessageBox(L"请先连接FTP服务器!");
		return;
	}
	if (FileName.GetCurSel() == LB_ERR)
	{
		MessageBox(L"请至少选择一个资源下载!");
		return;
	}
	FileName.GetText(FileName.GetCurSel(), selfile);//获得想要下载资源名
	//MessageBox(selfile);
	if (!selfile.IsEmpty())
	{
		if (tr != "匿名用户")
		{
			if (Judge_Score(tr))
			{
				Update_Formal(selfile);
			}
			else
			{
				MessageBox(L"积分不足,无法下载!", L"警告");
			}
		}
		else
		{
			Update_Formal(selfile);
		}
	}
}

void FtpClient::Update_Formal(CString selfile)
{
	//弹出另存为对话框
	CFileDialog file(true, NULL, selfile, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("所有文件(*.*)|*.*|"), this);
	if (file.DoModal() == IDOK)
	{
		CString strPath;
		CString strdir;
		strPath = file.GetPathName();
		pFtpConnection->GetCurrentDirectory(strdir);
		pFtpConnection->GetFile(selfile, strPath);//下载文件到的本地位置
		pInternetSession->Close();
		this->ConnectFtp();
		pFtpConnection->SetCurrentDirectory(strdir);
		this->UpdateDir();
		if(tr!="匿名用户") Revise_Score(tr);
		MessageBox(_T("下载成功,扣除您5积分!"), L"提示");
	}
}

bool FtpClient::Judge_Score(CString str)
{
	conn = mysql_init(NULL);//conn分配初始化MySQL对象
	if (0 == mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gbk"))//设置字符集
	{

	}
	// connect to database
	if (!mysql_real_connect(conn, server, user, password, database, 3306, NULL, 0))
	{
		MessageBox(_T("没有获得数据库连接"), _T("警告"), MB_OK);
		return false;
	}
	CString sql;
	sql.Format(L"select User_Score from user where User_Name='%s'", str);
	USES_CONVERSION;
	char* mysql = T2A(sql);
	if (mysql_query(conn, mysql))
	{
		MessageBox(_T("查询数据出错"), _T("警告"), MB_OK);
		return false;
	}
	res = mysql_use_result(conn);
	if ((row = mysql_fetch_row(res)) != NULL)
	{
		//MessageBox(_T("查询成功!"), _T("提示"), MB_OK);
		int score =_ttoi((CString)row[0]);
		//MessageBox((CString)row[0]);
		if (score < 5) return false;
		else return true;
	}
}

void FtpClient::Revise_Score(CString str)
{
	conn = mysql_init(NULL);//conn分配初始化MySQL对象
	if (0 == mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gbk"))//设置字符集
	{

	}
	// connect to database
	if (!mysql_real_connect(conn, server, user, password, database, 3306, NULL, 0))
	{
		MessageBox(_T("没有获得数据库连接"), _T("警告"), MB_OK);
		return;
	}
	CString sql;
	sql.Format(L"update user set User_Score = User_Score -5 where User_Name='%s'", str);
	USES_CONVERSION;
	char* mysql = T2A(sql);
	if (mysql_query(conn, mysql))
	{
		MessageBox(_T("更新数据出错"), _T("警告"), MB_OK);
		return;
	}
	mysql_free_result(res);
	mysql_close(conn);
}

5.资源搜索

在这里插入图片描述

功能:用户输入类别搜索资源
分析:用户输入资源类别进行查询,对输入进行非空判断,非空则在book表中进行查询,返回消息弹窗并将类别名传入show()展示该类别所有资源。

void Book_Search::OnBnClickedSearch()
{
	// TODO: 在此添加控件通知处理程序代码
	CString cate;
	GetDlgItemText(IDC_EDIT_SCH, cate);
	if (!cate.GetLength())
	{
		MessageBox(L"输入不能为空!", L"警告");
		return;
	}
	conn = mysql_init(NULL);//conn分配初始化MySQL对象
	if (0 == mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gbk"))//设置字符集
	{

	}
	// connect to database
	if (!mysql_real_connect(conn, server, user, password, database, 3306, NULL, 0))
	{
		MessageBox(_T("没有获得数据库连接"), _T("警告"), MB_OK);
		return;
	}
	CString sql;
	sql.Format(L"select *from book where Book_Cate='%s'", cate);
	USES_CONVERSION;
	char* mysql = T2A(sql);
	if (mysql_query(conn, mysql))
	{
		MessageBox(_T("查询数据出错"), _T("警告"), MB_OK);
		return;
	}
	res = mysql_use_result(conn);
	if ((row = mysql_fetch_row(res)) != NULL)
	{
		MessageBox(_T("查询成功!"), _T("提示"), MB_OK);
		Show_Resource show(cate);
		show.DoModal();
	}
	else
	{
		MessageBox(_T("抱歉,库中暂无此类资源!"), _T("通知"), MB_OK);
		return;
	}
	mysql_free_result(res);
	mysql_close(conn);
}

资源显示

在这里插入图片描述

功能:显示输入类别的所有资源
分析:
在这里插入图片描述
选定List Control控件,选择其视图为报表模式。
对标题及表头在DoDataExchange()中进行初始化。

void Show_Resource::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST2, Res_List);
	CString title;
	title.Format(L"%s资源",cate);
	SetDlgItemText(IDC_STATIC_TITLE, title);
	Res_List.InsertColumn(0, _T("资源名称"));
	Res_List.SetColumnWidth(0, 200);
	Res_List.InsertColumn(1, L"资源分类");
	Res_List.SetColumnWidth(1, 100);
	Res_List.InsertColumn(2, _T("资源出版社"));
	Res_List.SetColumnWidth(2, 140);
	Res_List.InsertColumn(3, _T("累计下载次数"));
	Res_List.SetColumnWidth(3, 110);
	Show();
}

然后利用类别在book表中查询,将查询结果显示在相应列中。

void Show_Resource::Show()
{
	conn = mysql_init(NULL);//conn分配初始化MySQL对象
	if (0 == mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gbk"))//设置字符集
	{

	}
	// connect to database
	if (!mysql_real_connect(conn, server, user, password, database, 3306, NULL, 0))
	{
		MessageBox(_T("没有获得数据库连接"), _T("警告"), MB_OK);
		return;
	}
	CString sql;
	sql.Format(L"select *from book where Book_Cate='%s'", cate);
	USES_CONVERSION;
	char* mysql = T2A(sql);
	if (mysql_query(conn, mysql))
	{
		MessageBox(_T("查询数据出错"), _T("警告"), MB_OK);
		return;
	}
	res = mysql_use_result(conn);
	Res_List.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);//调整选框
	Res_List.DeleteAllItems();
	int i = 0;
	// output table name
	while ((row = mysql_fetch_row(res)) != NULL)
	{
		Res_List.InsertItem(i, (CString)(row[1]));
		Res_List.SetItemText(i, 1, (CString)(row[3]));
		Res_List.SetItemText(i, 2, (CString)(row[4]));
		Res_List.SetItemText(i, 3, (CString)(row[2]));
		i++;
	}
	mysql_free_result(res);
	mysql_close(conn);
}

6.查看个人信息

在这里插入图片描述

功能:查看详细的个人信息
分析:通过登陆的用户名在表中查询,将查询结果显示在statictext上。

void Self_Infor::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//添加一些代码
	SetDlgItemText(IDC_STATIC_NAME, str);//text显示选中行的id
	if (str == "匿名用户")
	{
		SetDlgItemText(IDC_STATIC_MAIL, (CString)("无"));
		SetDlgItemText(IDC_STATIC_AGE, (CString)("无"));
		SetDlgItemText(IDC_STATIC_SCORE, (CString)("无限"));
		return;
	}
	conn = mysql_init(NULL);//conn分配初始化MySQL对象
	if (0 == mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gbk"))//设置字符集
	{

	}
	// connect to database
	if (!mysql_real_connect(conn, server, user, password, database, 3306, NULL, 0))
	{
		MessageBox(_T("没有获得数据库连接"), _T("警告"), MB_OK);
		return;
	}
	CString sql;
	sql.Format(L"select * from user where User_Name='%s'", str);
	USES_CONVERSION;
	char* mysql = T2A(sql);
	if (mysql_query(conn, mysql))
	{
		MessageBox(_T("查询数据出错"), _T("警告"), MB_OK);
		return;
	}
	res = mysql_use_result(conn);
	if ((row = mysql_fetch_row(res)) != NULL)
	{
		SetDlgItemText(IDC_STATIC_NAME, (CString)row[1]);
		SetDlgItemText(IDC_STATIC_MAIL, (CString)row[5]);
		SetDlgItemText(IDC_STATIC_AGE, (CString)row[4]);
		SetDlgItemText(IDC_STATIC_SCORE, (CString)row[3]);
	}
	else
	{
		MessageBox(_T("查询本行出错"), _T("警告"), MB_OK);
		return;
	}
	mysql_free_result(res);
	mysql_close(conn);
}

签到功能

在这里插入图片描述
在这里插入图片描述

通过CTime类获取签到当天的年月日,并与表中User_Last_Login的数据比对,如果不相同则更新数据并显示签到成功,如果相同则说明当日已经签到,弹窗提醒。

void Self_Infor::OnBnClickedButtonSign()
{
	// TODO: 在此添加控件通知处理程序代码
	if (str == "匿名用户") MessageBox(L"欲签到,请您先注册登录!",L"提示");
	CTime t = CTime::GetCurrentTime();
	int nYear = t.GetYear();
	int nMonth = t.GetMonth();
	int nDay = t.GetDay();
	CString today;
	today.Format(L"%d:%d:%d", nYear, nMonth, nDay);
	//MessageBox(today);
	conn = mysql_init(NULL);//conn分配初始化MySQL对象
	if (0 == mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gbk"))//设置字符集
	{

	}
	// connect to database
	if (!mysql_real_connect(conn, server, user, password, database, 3306, NULL, 0))
	{
		MessageBox(_T("没有获得数据库连接"), _T("警告"), MB_OK);
		return;
	}
	CString sql;
	sql.Format(L"select * from user where User_Name='%s'", str);
	USES_CONVERSION;
	char* mysql = T2A(sql);
	if (mysql_query(conn, mysql))
	{
		MessageBox(_T("查询数据出错"), _T("警告"), MB_OK);
		return;
	}
	res = mysql_use_result(conn);
	if ((row = mysql_fetch_row(res)) != NULL)
	{
		if ((CString)row[6]!= today)
		{
			Update_Score(today);
			MessageBox(L"签到成功,获得5积分!", L"提示");
			int score = _ttoi((CString)row[3])+5;
			CString ans;
			ans.Format(L"%d",score);
			SetDlgItemText(IDC_STATIC_SCORE, ans);
		}
		else
		{
			MessageBox(L"您今天已经签到过了!", L"提示");
		}
	}
	mysql_free_result(res);
}

void Self_Infor::Update_Score(CString today)
{
	conn = mysql_init(NULL);//conn分配初始化MySQL对象
	if (0 == mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gbk"))//设置字符集
	{

	}
	// connect to database
	if (!mysql_real_connect(conn, server, user, password, database, 3306, NULL, 0))
	{
		MessageBox(_T("没有获得数据库连接"), _T("警告"), MB_OK);
		return;
	}
	CString sql;
	sql.Format(L"update user set User_Last_Login = '%s' , User_Score = User_Score +5 where User_Name='%s'", today,str);
	USES_CONVERSION;
	char* mysql = T2A(sql);
	if (mysql_query(conn, mysql))
	{
		MessageBox(_T("更新数据出错"), _T("警告"), MB_OK);
		return;
	}
	res = mysql_use_result(conn);
	mysql_close(conn);
}

四、总结

这次课题的目的首先是为了练习socket套接字编程,将聊天和文件传输运用到课题中去。但是文件传输这里一直没找到合适且可行的方法,直到看到了利用FTP服务器的文件传输的博客,因为之前没有了解过相关的知识,所以进行改编并运用到项目中来。
从一筹莫展到完成项目花费了大概将近两周的时间,完成项目还是需要搜索大量的知识、关注细节并不断调试错误,还是很能提高编程能力的。
附项目源代码及数据库表结构和数据:C++基于MFC课程设计——学习公社


  • 6
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
网络编程聊天室是一种基于网络的应用程序,允许多个用户通过网络进行实时的消息交流。MFC(Microsoft Foundation Classes)是微软提供的一套用于Windows平台的C++类库,可以简化Windows应用程序的开发。在MFC中开发网络编程聊天室可以使用socket套接字编程来实现。 以下是一个简单的MFC网络编程聊天室的示例: 1. 创建MFC应用程序项目,并添加一个对话框。 2. 在对话框中添加一个编辑框用于显示聊天消息,一个编辑框用于输入消息,一个按钮用于发送消息。 3. 在对话框类的头文件中添加以下成员变量和函数声明: ```cpp #include <afxsock.h> class CMyDialog : public CDialog { public: CMyDialog(CWnd* pParent = nullptr); CAsyncSocket m_socket; CString m_strServerIP; UINT m_nServerPort; void ConnectToServer(); void DisconnectFromServer(); void SendMessageToServer(CString message); // ... protected: virtual void DoDataExchange(CDataExchange* pDX); virtual BOOL OnInitDialog(); afx_msg void OnButtonSend(); afx_msg void OnButtonConnect(); afx_msg void OnButtonDisconnect(); afx_msg LRESULT OnSocketReceive(WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP() }; ``` 4. 在对话框类的源文件中实现成员函数: ```cpp CMyDialog::CMyDialog(CWnd* pParent /*=nullptr*/) : CDialog(IDD_MYDIALOG, pParent) { m_strServerIP = _T("127.0.0.1"); // 服务器IP地址 m_nServerPort = 12345; // 服务器端口号 } void CMyDialog::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Text(pDX, IDC_EDIT_SERVER_IP, m_strServerIP); DDX_Text(pDX, IDC_EDIT_SERVER_PORT, m_nServerPort); } BOOL CMyDialog::OnInitDialog() { CDialog::OnInitDialog(); // 初始化socket库 AfxSocketInit(); // 创建socket对象 m_socket.Create(); return TRUE; } void CMyDialog::ConnectToServer() { // 连接到服务器 m_socket.Connect(m_strServerIP, m_nServerPort); } void CMyDialog::DisconnectFromServer() { // 断开与服务器的连接 m_socket.Close(); } void CMyDialog::SendMessageToServer(CString message) { // 发送消息到服务器 m_socket.Send((LPCTSTR)message, message.GetLength()); } void CMyDialog::OnButtonSend() { // 获取输入的消息 CString message; GetDlgItemText(IDC_EDIT_MESSAGE, message); // 发送消息到服务器 SendMessageToServer(message); // 清空输入框 SetDlgItemText(IDC_EDIT_MESSAGE, _T("")); } void CMyDialog::OnButtonConnect() { // 连接到服务器 ConnectToServer(); } void CMyDialog::OnButtonDisconnect() { // 断开与服务器的连接 DisconnectFromServer(); } LRESULT CMyDialog::OnSocketReceive(WPARAM wParam, LPARAM lParam) { // 接收服务器发送的消息 char buffer[1024]; int bytesRead = m_socket.Receive(buffer, sizeof(buffer) - 1); if (bytesRead > 0) { buffer[bytesRead] = '\0'; CString message(buffer); // 在编辑框中显示消息 GetDlgItem(IDC_EDIT_CHAT)->SetWindowText(message); } return 0; } BEGIN_MESSAGE_MAP(CMyDialog, CDialog) ON_BN_CLICKED(IDC_BUTTON_SEND, &CMyDialog::OnButtonSend) ON_BN_CLICKED(IDC_BUTTON_CONNECT, &CMyDialog::OnButtonConnect) ON_BN_CLICKED(IDC_BUTTON_DISCONNECT, &CMyDialog::OnButtonDisconnect) ON_MESSAGE(WM_SOCKET, &CMyDialog::OnSocketReceive) END_MESSAGE_MAP() ``` 5. 在对话框的资源文件中添加相应的控件,并设置控件的ID和属性。 6. 编译并运行程序,输入服务器的IP地址和端口号,点击连接按钮连接到服务器。然后可以输入消息并点击发送按钮发送消息到服务器,服务器会将消息广播给所有连接的客户端。 注意:以上示例只是一个简单的MFC网络编程聊天室的实现,实际的聊天室可能需要更多的功能和处理逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

新西兰做的饭

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

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

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

打赏作者

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

抵扣说明:

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

余额充值