基于MFC框架的mySQL数据库访问计算器

发布时间 2023-11-14 22:11:24作者: hsdhfgw

该计算器是在上次基础上去掉了许多计算方法,只保留了基本的加减乘除四则运算,实现了用户登录功能,计算过程保留在数据库的功能:
第一步:创建数据库,以创建成功,下面是创建后的表格:

数据库名称为mydata,里面有两张表分别是computer以及user。

原本我想利用Nodejs中间件的方式让MFC应用程序访问mySQL数据库,但是出了一些问题。
创建Node项目后,建立一个app.js文件:
//创建一个MySQL连接
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'numberone',
database: 'mydata'
});

//创建一个 API 终点:使用下面的代码将数据发送到客户端:
//这段代码将创建一个名为 /data 的 API 终点,它将查询数据库中的数据并将其返回给客户端。
const express = require('express');
const app = express();
app.get('/data', (req, res) => {
const sql = 'SELECT * FROM computer';
connection.query(sql, (error, results, fields) => {
if (error) {
console.error('Error fetching data:', error);
res.status(500).send('Failed to fetch data from MySQL database');
} else {
res.send(results);
console.log('Database operation successful:', results); // 添加日志信息
}
});
});
//查询用户账号密码
app.get('/user', (req, res) => {
const sql = 'SELECT * FROM user';
connection.query(sql, (error, results, fields) => {
if (error) {
console.error('Error fetching data:', error);
} else {
res.send(results);
}
})
})

const port = 3000;

app.listen(port, () => {
console.log('Server is running on port ${port}');
console.log('URL:http://localhost:3000');
console.log('xia mian shi ri zhi:>>>>>>>>>>>>');
});
建立这个文件后,在项目文件目录中启动app.js会在本地打开3000端口监听数据库的访问事件:

下面是在浏览器访问的结果:
image
image
这是控制台输出的日志:
image

这就说明通过这两个URL可以正确获取到数据库内部的数据,但是由于字符集的问题,在MFC中通过URL访问后结果是一坨乱码。
下面是我尝试在MFC应用中的访问函数:
void CAboutDlg::SendHTTPRequest()
{TCHAR szHeaders[] = _T("Content-Type: application/json\r\n"); // 请求头部
TCHAR szData[] = _T("{"name":"John","age":30}\r\n"); // 请求数据
HINTERNET hInternet = InternetOpen(_T("MyApp"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); // 打开一个 Internet 会话
if (hInternet)
{
HINTERNET hConnect = InternetOpenUrl(hInternet, _T("http://localhost:3000/user"), szHeaders, _tcslen(szHeaders), INTERNET_FLAG_RELOAD, NULL); // 打开一个 URL
if (hConnect)
{
TCHAR szResponse[4096]; // 存储响应数据的缓冲区
DWORD dwBytesRead = 0;
while (InternetReadFile(hConnect, szResponse, sizeof(szResponse), &dwBytesRead) && dwBytesRead)
{
// 处理响应数据,这里示例只打印到控制台
szResponse[dwBytesRead] = '\0';
_tprintf(_T("%s"), szResponse);
CString myCString;
myCString.Format(_T("%s"), szResponse);
myCString = _T("是你的v哦是");
MessageBox(myCString.GetString(), _T("错误提示"), MB_ICONERROR);
}InternetCloseHandle(hConnect); // 关闭 URL
}
else
{
// 处理连接错误
MessageBox(_T("处理连接错误!"), _T("错误提示"), MB_ICONERROR);
}InternetCloseHandle(hInternet); // 关闭会话
}
else
{
// 处理初始化错误
MessageBox(_T("处理初始化错误!"), _T("错误提示"), MB_ICONERROR);
}
}

这样不行,偶然间在CSDN上有一篇文章,用另一种方法实现了MFCy应用访问MySQL数据库的方法:http://https://blog.csdn.net/qq_34438969/article/details/117456809?app_version=6.1.5&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22117456809%22%2C%22source%22%3A%222201_75686160%22%7D&utm_source=app
用这个方法,我实现了我的计算器:
下面是我的计算器展示:
1.计算器主界面:
image
2.点击=按钮后构造的SQL插入语句:
image
3.插入成功提示:
image
4.后端数据库查看:
image
5.登录界面:
image
6.数据库连接成功提示:
image
7.登录成功提示:
image
8.登录失败提示:(数据库中没有baga用户)该提示有待改进,明明是用户错误
image
9.user表展示:
image
以下是主要实现代码:

// MFC_ComputerDlg.cpp: 实现文件
include "pch.h"
include "framework.h"
include "MFC_Computer.h"
include "MFC_ComputerDlg.h"
include "afxdialogex.h"
//http请求函数头文件
include <afx.h>
include <afxinet.h>
include <Windows.h>
include <afxdisp.h>
ifdef _DEBUG
define new DEBUG_NEW
endif
include <mysql.h>
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持

// 实现
protected:
DECLARE_MESSAGE_MAP()
public:
// 账号
CString username;
// 密码
CString password;
void SendHTTPRequest();
afx_msg void OnBnClickedButton3();
afx_msg void OnEnChangeEdit2();
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
, username(_T(""))
, password(_T(""))
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT1, username);
DDX_Text(pDX, IDC_EDIT2, password);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
ON_BN_CLICKED(IDC_BUTTON3, &CAboutDlg::OnBnClickedButton3)
ON_EN_CHANGE(IDC_EDIT2, &CAboutDlg::OnEnChangeEdit2)
END_MESSAGE_MAP()
// CMFCComputerDlg 对话框
CMFCComputerDlg::CMFCComputerDlg(CWnd* pParent /=nullptr/)
: CDialogEx(IDD_MFC_COMPUTER_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMFCComputerDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT1, CMFCComputerDlg::mStr);
}

BEGIN_MESSAGE_MAP(CMFCComputerDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON13, &CMFCComputerDlg::OnBnClickedButton13)
ON_BN_CLICKED(IDC_BUTTON14, &CMFCComputerDlg::OnBnClickedButton14)
ON_BN_CLICKED(IDC_BUTTON15, &CMFCComputerDlg::OnBnClickedButton15)
ON_BN_CLICKED(IDC_BUTTON9, &CMFCComputerDlg::OnBnClickedButton9)
ON_BN_CLICKED(IDC_BUTTON10, &CMFCComputerDlg::OnBnClickedButton10)
ON_BN_CLICKED(IDC_BUTTON11, &CMFCComputerDlg::OnBnClickedButton11)
ON_BN_CLICKED(IDC_BUTTON5, &CMFCComputerDlg::OnBnClickedButton5)
ON_BN_CLICKED(IDC_BUTTON6, &CMFCComputerDlg::OnBnClickedButton6)
ON_BN_CLICKED(IDC_BUTTON7, &CMFCComputerDlg::OnBnClickedButton7)
ON_BN_CLICKED(IDC_BUTTON18, &CMFCComputerDlg::OnBnClickedButton18)
ON_BN_CLICKED(IDC_BUTTON19, &CMFCComputerDlg::OnBnClickedButton19)
ON_BN_CLICKED(IDC_BUTTON1, &CMFCComputerDlg::OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON16, &CMFCComputerDlg::OnBnClickedButton16)
ON_BN_CLICKED(IDC_BUTTON12, &CMFCComputerDlg::OnBnClickedButton12)
ON_BN_CLICKED(IDC_BUTTON8, &CMFCComputerDlg::OnBnClickedButton8)
ON_BN_CLICKED(IDC_BUTTON4, &CMFCComputerDlg::OnBnClickedButton4)
ON_BN_CLICKED(IDC_BUTTON20, &CMFCComputerDlg::OnBnClickedButton20)
ON_BN_CLICKED(IDC_BUTTON2, &CMFCComputerDlg::OnBnClickedButton2)
ON_BN_CLICKED(IDC_BUTTON3, &CMFCComputerDlg::OnBnClickedButton3)
END_MESSAGE_MAP()
// CMFCComputerDlg 消息处理程序

BOOL CMFCComputerDlg::OnInitDialog()
{
CDialogEx::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: 在此添加额外的初始化代码return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}

void CMFCComputerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。

void CMFCComputerDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCComputerDlg::OnQueryDragIcon()
{
return static_cast(m_hIcon);
}//保存第一个数
void CMFCComputerDlg::SaveFirstValue()
{
UpdateData(TRUE);
mNum1 = _wtof(mStr);
mTempStr = mStr;
mStr = L"";
UpdateData(FALSE);
}
//计算
void CMFCComputerDlg::Calculator()
{
UpdateData(TRUE);
mNum2 = _wtof(mStr);
double result = 0.0f;
switch (mFlag)
{
case FLAG_JIA:
result = mNum1 + mNum2;
mTempStr = mTempStr + _T("+") + mStr + _T("=");
break;
case FLAG_JIAN:
result = mNum1 - mNum2;
mTempStr = mTempStr + _T("-") + mStr + _T("=");
break;
case FLAG_CHENG:
result = mNum1 * mNum2;
mTempStr = mTempStr + _T("") + mStr + _T("=");
break;
case FLAG_CHU:
if (mNum2 == 0) {
mTempStr = _T("出0错误");
}
else
{
result = mNum1 / mNum2;
mTempStr = mTempStr + _T("/") + mStr + _T("=");
}
break;
default:
break;
}
if (result - (int)result 《= 1e-5)
{mStr.Format(L"%d", (int)result);
}
else {
mStr.Format(L"%f", result);
}
mTempStr += mStr;//计算记录在mTempStr中
SaveMySql(mTempStr);
UpdateData(FALSE);
mNum1 = result;
mNum2 = 0.0f;
}void CMFCComputerDlg::SaveMySql(CString text)
{const char user[] = "root"; //填写你的 mysql 用户名const char pswd[] = "numberone"; //填写你的 mysql 密码const char host[] = "localhost";const char database[] = "mydata"; //填写你的 mysql 数据库名称unsigned int port = 3306;
MYSQL_RES
res;MYSQL_ROW row;MYSQL mysqlCon;
mysql_init(&mysqlCon);
if (!mysql_real_connect(&mysqlCon, host, user, pswd, database, port, NULL, 0))
{
AfxMessageBox(_T("访问数据库失败!"));
}
else
{mysql_query(&mysqlCon, "SET NAMES GBK"); //设置字符集,确保能够插入中文数据
// 插入数据的 SQL 语句(假设 computer 表有 text 列)CStringW sql;
sql.Format(_T("INSERT INTO computer (text) VALUES ('%s')"), text);AfxMessageBox(sql);

	LPCWSTR sqlW = sql.GetString();
	int size_needed = WideCharToMultiByte(CP_UTF8, 0, sqlW, -1, NULL, 0, NULL, NULL);  // 计算所需的缓冲区大小char* sql_char = new char[size_needed];

WideCharToMultiByte(CP_UTF8, 0, sqlW, -1, sql_char, size_needed, NULL, NULL); // 将宽字符转换为多字节字符
//AfxMessageBox(_T(sql_char));
if (mysql_query(&mysqlCon, sql_char) == 0)
{
AfxMessageBox(_T("插入成功!"));
}
else
{
AfxMessageBox(_T("插入失败!"));
}
}mysql_close(&mysqlCon);
}

//1
void CMFCComputerDlg::OnBnClickedButton13()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
mStr += L"1";
UpdateData(FALSE);
}

void CMFCComputerDlg::OnBnClickedButton14()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
mStr += L"2";
UpdateData(FALSE);
}

void CMFCComputerDlg::OnBnClickedButton15()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
mStr += L"3";
UpdateData(FALSE);
}

void CMFCComputerDlg::OnBnClickedButton9()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
mStr += L"4";
UpdateData(FALSE);
}

void CMFCComputerDlg::OnBnClickedButton10()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
mStr += L"5";
UpdateData(FALSE);
}

void CMFCComputerDlg::OnBnClickedButton11()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
mStr += L"6";
UpdateData(FALSE);
}

void CMFCComputerDlg::OnBnClickedButton5()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
mStr += L"7";
UpdateData(FALSE);
}

void CMFCComputerDlg::OnBnClickedButton6()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
mStr += L"8";
UpdateData(FALSE);
}

void CMFCComputerDlg::OnBnClickedButton7()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
mStr += L"9";
UpdateData(FALSE);
}

void CMFCComputerDlg::OnBnClickedButton18()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
mStr += L"0";
UpdateData(FALSE);
}

void CMFCComputerDlg::OnBnClickedButton19()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
if (-1 == mStr.Find(L'.'))
{
mStr += _T(".");
}
UpdateData(FALSE);
}

//清除所有
void CMFCComputerDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
mStr = L"";
UpdateData(FALSE);
}

void CMFCComputerDlg::OnBnClickedButton16()
{
// TODO: 在此添加控件通知处理程序代码
SaveFirstValue();
mFlag = FLAG_JIA;
}

void CMFCComputerDlg::OnBnClickedButton12()
{
// TODO: 在此添加控件通知处理程序代码
SaveFirstValue();
mFlag = FLAG_JIAN;
}

void CMFCComputerDlg::OnBnClickedButton8()
{
// TODO: 在此添加控件通知处理程序代码
SaveFirstValue();
mFlag = FLAG_CHENG;
}

void CMFCComputerDlg::OnBnClickedButton4()
{
// TODO: 在此添加控件通知处理程序代码
SaveFirstValue();
mFlag = FLAG_CHU;
}

void CMFCComputerDlg::OnBnClickedButton20()
{
// TODO: 在此添加控件通知处理程序代码
Calculator();
}

void CMFCComputerDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
mStr = L"";
UpdateData(FALSE);
}

void CMFCComputerDlg::OnBnClickedButton3()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
if (!mStr.IsEmpty()) {
mStr = mStr.Left(mStr.GetLength() - 1);
}
UpdateData(FALSE);
}void CAboutDlg::SendHTTPRequest()
{TCHAR szHeaders[] = _T("Content-Type: application/json\r\n"); // 请求头部TCHAR szData[] = _T("{"name":"John","age":30}\r\n"); // 请求数据HINTERNET hInternet = InternetOpen(_T("MyApp"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); // 打开一个 Internet 会话
if (hInternet)
{HINTERNET hConnect = InternetOpenUrl(hInternet, _T("http://localhost:3000/user"), szHeaders, _tcslen(szHeaders), INTERNET_FLAG_RELOAD, NULL); // 打开一个 URLif (hConnect){TCHAR szResponse[4096]; // 存储响应数据的缓冲区DWORD dwBytesRead = 0;while (InternetReadFile(hConnect, szResponse, sizeof(szResponse), &dwBytesRead) && dwBytesRead){// 处理响应数据,这里示例只打印到控制台szResponse[dwBytesRead] = '\0';_tprintf(_T("%s"), szResponse);CString myCString;myCString.Format(_T("%s"), szResponse);
myCString = _T("是你的v哦是");
MessageBox(myCString.GetString(), _T("错误提示"), MB_ICONERROR);
}InternetCloseHandle(hConnect); // 关闭 URL
}else{
// 处理连接错误
MessageBox(_T("处理连接错误!"), _T("错误提示"), MB_ICONERROR);
}InternetCloseHandle(hInternet); // 关闭会话
}else{
// 处理初始化错误
MessageBox(_T("处理初始化错误!"), _T("错误提示"), MB_ICONERROR);
}
}

//登录按钮
void CAboutDlg::OnBnClickedButton3()
{
GetDlgItem(IDC_EDIT1)->GetWindowText(username); //获得输入的用户名
GetDlgItem(IDC_EDIT2)->GetWindowText(password); //获得输入的密码 const char user[] = "root"; //填写你的 mysql 用户名
const char pswd[] = "numberone"; //填写你的 mysql 密码
const char host[] = "localhost";
const char database[] = "mydata"; //填写你的 mysql 数据库名称
unsigned int port = 3306; MYSQL_RES* res;
MYSQL_ROW row;
MYSQL mysqlCon; if (username.IsEmpty() || password.IsEmpty())
{
MessageBox(_T("用户名或密码不能为空!"), _T("用户登录信息"));
return;
} mysql_init(&mysqlCon);
if (!mysql_real_connect(&mysqlCon, host, user, pswd, database, port, NULL, 0))
{
AfxMessageBox(_T("访问数据库失败!"));
}
else
{
mysql_query(&mysqlCon, "SET USER GBK"); //设置字符集
AfxMessageBox(_T("访问数据库成功!"));
}//mysql_query(&myCont, "SET NAMES GBK"); //设置编码格式,否则在cmd下无法显示中文 nt ress = mysql_query(&mysqlCon, "select username, password from user");
if (ress == 0) //检测查询成功为0,不成功则非0
{res = mysql_store_result(&mysqlCon); //保存查询到的数据到 res
if (mysql_num_rows(res) == 0) //查询结果为空
{
AfxMessageBox(_T("用户不存在"));
}
else
{
row = mysql_fetch_row(res);
if (password == row[1])
{
mysql_free_result(res);
MessageBox(_T("登录成功!"));
}
else
{
AfxMessageBox(_T("密码错误!"));
}
}
}
else
{
AfxMessageBox(_T("访问失败!"));
}mysql_close(&mysqlCon);
}

void CAboutDlg::OnEnChangeEdit2()
{
// TODO: 如果该控件是 RICHEDIT 控件,它将不
// 发送此通知,除非重写 CDialogEx::OnInitDialog()
// 函数并调用 CRichEditCtrl().SetEventMask(),
// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
// TODO: 在此添加控件通知处理程序代码
}
吐槽一下,这个代码插入功能真的是狗屎,显示的乱七八糟。将代码中的字符强制进行转换。转义出一些乱七八糟的东西。