b展示视频: 数据库大作业—日常记账系统(C# winform + SQL Server).
USE Application
DROP TABLE IF EXISTS UserData; /*用户信息*/
DROP TABLE IF EXISTs Account; /*用户账本数据*/
CREATE TABLE UserData
(
ID NCHAR(10) PRIMARY KEY, /*用户ID*/
UserPassword NCHAR(32), /*用户密码*/
UserMail NCHAR(30), /*用户邮箱*/
UserPhoto image, /*用户照片*/
UserName NCHAR(30), /*用户名*/
);
CREATE TABLE Account
(
UserID NCHAR(10),
InOrOut NCHAR(10),
ConsumeType NCHAR(10),
Price FLOAT,
NOTE NCHAR(200),
RecordDate DATE,
);
/*管理员初始账号*/
INSERT INTO UserData(ID,UserPassword,UserMail,UserName) VALUES('100001',' ','[email protected]','小田txw');
GO
创建了2个表:
用于存储用户的信息,包括用户名、用户ID、用户密码、用户邮箱、用户头像。
用于存储用户的记账信息,包括用户ID、账单类型、金额、备注、时间。
MailVeriCode
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Database
{
public class MailVeriCode
{
///
/// 生成随机验证码
///
/// 验证码长度
public static string CreateRandomMailCode(int CodeLength)
{
int randNum;
char code;
string randomCode = String.Empty;//随机验证码
//生成一定长度的随机验证码
//Random random = new Random();//生成随机数对象
for (int i = 0; i < CodeLength; i++)
{
//利用GUID生成6位随机数
byte[] buffer = Guid.NewGuid().ToByteArray();//生成字节数组
int seed = BitConverter.ToInt32(buffer, 0);//利用BitConvert方法把字节数组转换为整数
Random random = new Random(seed);//以生成的整数作为随机种子
randNum = random.Next();
//randNum = random.Next();
if (randNum % 3 == 1)
{
code = (char)('A' + (char)(randNum % 26));//随机大写字母
}
else if (randNum % 3 == 2)
{
code = (char)('a' + (char)(randNum % 26));//随机小写字母
}
else
{
code = (char)('0' + (char)(randNum % 10));//随机数字
}
randomCode += code.ToString();
}
return randomCode;
}
///
/// 发送邮件验证码
///
/// 发件人邮箱地址
/// 收件人邮箱地址
/// 邮件主题
/// 邮件内容
/// 邮箱授权码
///
public static bool SendMailMessage(string MyEmailAddress, string RecEmailAddress, string Subject, string Body, string AuthorizationCode)
{
MailMessage mail = new MailMessage();
mail.From = new MailAddress(MyEmailAddress);//发件人邮箱地址
mail.To.Add(new MailAddress(RecEmailAddress));//收件人邮箱地址
mail.Subject = Subject;//邮件标题
mail.Body = Body; //邮件内容
mail.Priority = MailPriority.High;//优先级
SmtpClient client = new SmtpClient();//qq邮箱:smtp.qq.com;126邮箱:smtp.126.com
client.Host = "smtp.qq.com";
client.Port = 587;//SMTP端口465或587
client.EnableSsl = true;//使用安全加密SSL连接
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.Credentials = new NetworkCredential(MyEmailAddress, AuthorizationCode);//验证发件人身份(发件人邮箱,邮箱授权码);
try
{
client.Send(mail);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "发送失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
return true;
}
///
/// 验证QQ邮箱
///
/// 邮箱
///
public static bool CheckMail(string mail)
{
string str = @"^[1-9][0-9]{4,}@qq.com$";
Regex mReg = new Regex(str);
if (mReg.IsMatch(mail))
{
return true;
}
return false;
}
}
}
CreateRandomMailCode
用于生成要发送的验证码,将验证码长度作为形参,返回字符串型的验证码。
SendMailMessage
用于发送邮件,使用了C#自带的类MailAddress
、SmtpClient
、NetworkCredential
等。收件人邮箱、发件人邮箱、发件人邮箱授权码、邮件内容、邮件标题作为形参,完成邮箱验证码的发送,完成发送后,返回true
的bool值,否则返回false
。
CheckMail
用于检测用户填入的邮箱验证码与发送的是否一致,返回bool类性值。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Database
{
public partial class Login : Form
{
public string code; //储存生成验证码
public Login()
{
InitializeComponent();
init();
}
#region 初始化参数
private void init()
{
this.MaximizeBox = false; //禁止最大化
//使标签透明化
title_lab.BackColor = Color.Transparent;
account_lab.BackColor = Color.Transparent;
password_lab.BackColor = Color.Transparent;
vericode_lab.BackColor = Color.Transparent;
veri_lab.BackColor= Color.Transparent;
//使按钮透明化
login_btn.FlatStyle = FlatStyle.Flat;
login_btn.ForeColor = Color.Transparent;
login_btn.BackColor = Color.Transparent;
login_btn.FlatAppearance.BorderSize = 1;
login_btn.FlatAppearance.MouseOverBackColor = Color.Transparent;
login_btn.FlatAppearance.MouseDownBackColor = Color.Transparent;
register_btn.FlatStyle = FlatStyle.Flat;
register_btn.ForeColor = Color.Transparent;
register_btn.BackColor = Color.Transparent;
register_btn.FlatAppearance.BorderSize = 1;
register_btn.FlatAppearance.MouseOverBackColor = Color.Transparent;
register_btn.FlatAppearance.MouseDownBackColor = Color.Transparent;
forget_linkbtn.FlatStyle = FlatStyle.Flat;
forget_linkbtn.ForeColor = Color.Transparent;
forget_linkbtn.BackColor = Color.Transparent;
checkBox1.BackColor = Color.Transparent;
//验证码生成
CreatVeriCode();
}
#endregion
#region 生成随机验证码
private void CreatVeriCode()
{
//随机实例化
code = "";
Random ran = new Random();
int number;
char code1;
//取五个数
for (int i = 0; i < 5; i++)
{
number = ran.Next();
if (number % 2 == 0)
code1 = (char)('0' + (char)(number % 10));
else
code1 = (char)('A' + (char)(number % 26)); //转化为字符
this.code += code1.ToString();
}
vericode_lab.Text = code;
}
#endregion
#region 登录按钮事件(连接数据库验证用户名和密码)
private void login_btn_Click(object sender, EventArgs e)
{
string username = account_txt.Text.Trim();
string password = EncryptWithMD5(password_txt.Text.Trim());
//创建数据库连接对象
string sqlconf = "Data Source = .;Initial Catalog = Application;Integrated Security = SSPI";
SqlConnection sqlConnection = new SqlConnection(sqlconf);
sqlConnection.Open();
string sql = "select ID,UserPassword from UserData where UserName = '" + username + "'and UserPassword = '" + password + "'";
SqlCommand cmd = new SqlCommand(sql, sqlConnection);
SqlDataReader reader = cmd.ExecuteReader();
if(reader.HasRows && vericode_txt.Text.ToLower() == code.ToLower())
{
new Main(username).Show();
this.Hide();
}
else if(reader.HasRows && vericode_txt.Text.ToLower()!=code.ToLower())
{
MessageBox.Show("验证码有误,登录失败!","警告");
CreatVeriCode();
return;
}
else
{
MessageBox.Show("账号密码有误,登录失败!", "警告");
return;
}
reader.Close();
sqlConnection.Close();
}
#endregion
#region 注册界面
private void register_btn_Click(object sender, EventArgs e)
{
new Register().Show();
}
#endregion
#region MD5加密算法
private string EncryptWithMD5(string source)//MD5加密
{
byte[] sor = Encoding.UTF8.GetBytes(source);
MD5 md5 = MD5.Create();
byte[] result = md5.ComputeHash(sor);
StringBuilder strbul = new StringBuilder(40);
for (int i = 0; i < result.Length; i++)
{
strbul.Append(result[i].ToString("x2"));//加密结果"x2"结果为32位,"x3"结果为48位,"x4"结果为64位
}
return strbul.ToString();
}
#endregion
#region 点击验证码标签刷新验证码
private void vericode_lab_Click(object sender, EventArgs e)
{
CreatVeriCode();
}
#endregion
private void forget_linkbtn_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
new Forget().Show();
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if (checkBox1.Checked)
{
//复选框被勾选,显示密码
password_txt.PasswordChar = new char();
}
else
{
//复选框为被勾选,隐藏密码
password_txt.PasswordChar = '*';
}
}
}
}
主要方法:init
、CreatVeriCode
、login_btn_Click
、register_btn_Click
、EncryptWithMD5
、vericode_lab_Click
、forget_linkbtn_LinkClicked
、checkBox1_CheckedChanged
其中
init
:初始化方法,初始化界面和生成初始的验证码。
CreatVeriCode
:验证码生成方法。
login_btn_Click
:点击登录按钮事件,具体的事件后面描述。
register_btn_Click
:点击注册按钮事件,调出注册界面。
EncryptWithMD5
:MD5加密算法方法,实际的密码经过该方法后,返回经MD5加密的密码。
vericode_lab_Click
:点击验证码标签事件,点击验证码标签后,会刷新验证码。
forget_linkbtn_LinkClicked
:点击忘记密码事件,调出找回密码界面。
checkBox1_CheckedChanged
:复选框改变事件,用于改变密码文本框的显示(显示密码和隐藏密码)。
按下“登录”按钮后,程序会与Application数据库连接,根据输入的用户名和密码,从UserData表中查询相应的数据,若存在用户名且密码正确,则会验证输入的验证码是否正确,若正确,则调出主界面。
登录界面的主要功能:
登录界面较为简单,要实现的功能不多,主要就是为了调出其他界面。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Database
{
public partial class Register : Form
{
public static string pathPicture;
public Byte[] mybyte = new byte[0];
public Register()
{
InitializeComponent();
init();
}
#region 参数初始化
private void init()
{
this.MaximizeBox = false; //禁止最大化
//使标签透明化
mail_lab.BackColor = Color.Transparent;
passwordreg_lab.BackColor = Color.Transparent;
vericode_lab.BackColor = Color.Transparent;
register_lab.BackColor = Color.Transparent;
username_lab.BackColor = Color.Transparent;
pic_lab.BackColor = Color.Transparent;
//使按钮透明化
Mail_btn.FlatStyle = FlatStyle.Flat;
Mail_btn.ForeColor = Color.Transparent;
Mail_btn.BackColor = Color.Transparent;
Mail_btn.FlatAppearance.BorderSize = 1;
Mail_btn.FlatAppearance.MouseOverBackColor = Color.Transparent;
Mail_btn.FlatAppearance.MouseDownBackColor = Color.Transparent;
register_btn.FlatStyle = FlatStyle.Flat;
register_btn.ForeColor = Color.Transparent;
register_btn.BackColor = Color.Transparent;
register_btn.FlatAppearance.BorderSize = 1;
register_btn.FlatAppearance.MouseOverBackColor = Color.Transparent;
register_btn.FlatAppearance.MouseDownBackColor = Color.Transparent;
pictureBox1.BackColor = Color.Transparent;
checkBox1.BackColor = Color.Transparent;
}
#endregion
#region 获取邮箱验证码(MailMessage类和SmtpClient类)
int seconds1 = 60;//倒计时60s
int seconds2 = 60 * 5;//验证码有效时间5分钟
string strMailVeriCode;
private void Mail_btn_Click(object sender, EventArgs e)
{
string recEMailAddress = Mail_txt.Text.Trim();//收件人邮箱
strMailVeriCode = MailVeriCode.CreateRandomMailCode(6);
string strBody = "验证码:" + strMailVeriCode + ",5分钟内有效,请勿泄漏于他人。如非本人操作,请忽略。系统邮件请勿回复。";//邮件内容
string strSubject = "【小田账本】注册验证";//邮件标题
string strMyEmailAddress = "[email protected]";//发件人邮箱
string strAuthorizationCode = "xxxxxxxxxxxxxxxx";//邮箱授权码
if (string.IsNullOrEmpty(recEMailAddress))//判断是否输入了邮箱
{
MessageBox.Show("请输入邮箱!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
Mail_txt.Focus();
}
else if (MailVeriCode.CheckMail(recEMailAddress) == false)//判断邮箱格式是否正确
{
MessageBox.Show("您输入的QQ邮箱有误,请重新输入!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
Mail_txt.Focus();
return;
}
else//发送验证码
{
//发送
if (MailVeriCode.SendMailMessage(strMyEmailAddress, recEMailAddress, strSubject, strBody, strAuthorizationCode) == true)
{
Mail_btn.Enabled = false;
//计时器初始化
timer1.Interval = 1000;
timer1.Start();
timer2.Interval = 1000;
timer2.Start();
}
else
{
vericode_txt.Focus();
}
}
}
#endregion
#region 倒计时1方法
private void timer1_Tick(object sender, EventArgs e)
{
if (seconds1 > 0)
{
seconds1--;
Mail_btn.Text = "剩余" + seconds1.ToString() + "秒";
}
else
{
timer1.Stop();
Mail_btn.Text = "获取验证码";
Mail_btn.Enabled = true;
}
}
#endregion
#region 倒计时2方法
private void timer2_Tick(object sender, EventArgs e)
{
if (seconds2 == 0)
{
timer2.Stop();
//旧的验证码过期,生成一个新的验证码
strMailVeriCode = MailVeriCode.CreateRandomMailCode(6);
}
}
#endregion
#region 注册按钮事件
private void register_btn_Click(object sender, EventArgs e)
{
string mailVeriCode = vericode_txt.Text.Trim();//邮箱验证码
//先确认一些重要信息为非空
if (username_txt.Text.Trim() != "" && passwordreg_txt.Text.Trim() != "")
{
if(pathPicture==null)
{
//为避免登录后在主界面读取数据库头像报错,强制要求选择初始头像
//还有一种思路就是在数据库中存放一个初始头像,当注册界面打开时,自动将初始头像导入,也可以防止无头像报错问题
MessageBox.Show("请选择头像!");
return;
}
else
{
string sqlconf = "Data Source = .;Initial Catalog = Application;Integrated Security = SSPI";
SqlConnection sqlConnection = new SqlConnection(sqlconf);
string username = username_txt.Text.Trim();
string mail = Mail_txt.Text.Trim();
sqlConnection.Open();
string sql1 = "select UserName from UserData where UserName = '" + username + "'";
SqlCommand sqlCommand1 = new SqlCommand(sql1, sqlConnection); //确认用户名是否已被注册
SqlDataReader sqlDataReader1 = sqlCommand1.ExecuteReader();
bool a = sqlDataReader1.HasRows;
sqlDataReader1.Close();
if (a)
{
MessageBox.Show("用户名已注册!");
return;
}
else
{
string sql2 = "select UserName from UserData where UserMail = '" + mail + "'";
SqlCommand sqlCommand2 = new SqlCommand(sql2, sqlConnection); //确认该邮箱是否已被注册
SqlDataReader sqlDataReader2 = sqlCommand2.ExecuteReader();
bool b = sqlDataReader2.HasRows;
sqlDataReader2.Close();
if (b)
{
MessageBox.Show("该邮箱已注册!");
return;
}
else
{
if (string.IsNullOrEmpty(mailVeriCode) == true)
{
MessageBox.Show("请输入验证码", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
vericode_txt.Focus();
return;
}
else if (mailVeriCode.ToLower() != strMailVeriCode.ToLower())//判断邮箱验证码是否输入正确;不区分字母大小写
{
MessageBox.Show("您输入的验证码有误!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
vericode_txt.Focus();
return;
}
//查找最大的ID值
string sql4 = "select max(ID) as maxid from UserData";
SqlCommand command1 = new SqlCommand(sql4, sqlConnection);
SqlDataReader maxid = command1.ExecuteReader();
maxid.Read();
int newid = Convert.ToInt32(maxid["maxid"]) + 1;
maxid.Close();
string password = EncryptWithMD5(passwordreg_txt.Text.Trim());
string sql3 = "insert into UserData(ID,UserPassword,UserMail,UserName,UserPhoto)" + "values (@userid, @userpassword,@usermail,@username,@userphoto)";
SqlCommand command = new SqlCommand(sql3, sqlConnection);
SqlParameter sqlParameter = new SqlParameter("@userid", newid);
command.Parameters.Add(sqlParameter);
sqlParameter = new SqlParameter("@userpassword", password);
command.Parameters.Add(sqlParameter);
sqlParameter = new SqlParameter("@usermail", Mail_txt.Text);
command.Parameters.Add(sqlParameter);
sqlParameter = new SqlParameter("@username", username_txt.Text);
command.Parameters.Add(sqlParameter);
sqlParameter = new SqlParameter("@userphoto", System.Data.SqlDbType.Image);
sqlParameter.Value = mybyte;
command.Parameters.Add(sqlParameter);
command.ExecuteNonQuery();
sqlConnection.Close();
MessageBox.Show("注册成功!");
this.Close();
}
}
}
}
else
{
MessageBox.Show("请先将信息填写完整!");
}
}
#endregion
#region MD5加密算法
private string EncryptWithMD5(string source)//MD5加密
{
byte[] sor = Encoding.UTF8.GetBytes(source);
MD5 md5 = MD5.Create();
byte[] result = md5.ComputeHash(sor);
StringBuilder strbul = new StringBuilder(40);
for (int i = 0; i < result.Length; i++)
{
strbul.Append(result[i].ToString("x2"));//加密结果"x2"结果为32位,"x3"结果为48位,"x4"结果为64位
}
return strbul.ToString();
}
#endregion
#region 添加头像
private void pictureBox1_Click(object sender, EventArgs e)
{
//设置文件对话框显示的初始目录为系统桌面
this.openFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
//设置当前选定筛选器字符串以决定对话框中“文档类型”选项
this.openFileDialog1.Filter = "bmp文件(*.bmp)|*.bmp|gif文件(*.gif)|*.gif|jpeg文件(*.jpg)|*.jpg|png文件(*.png)|*.png";
//设置对话框中当前选定筛选器的索引
this.openFileDialog1.FilterIndex = 3;
//关闭对话框,还原当前目录
this.openFileDialog1.RestoreDirectory = true;
//设置对话框标题
this.openFileDialog1.Title = "选择头像照片";
if (this.openFileDialog1.ShowDialog() == DialogResult.OK)
{
pathPicture = this.openFileDialog1.FileName;
FileStream fs = new FileStream(pathPicture, FileMode.Open, FileAccess.Read);
mybyte = new byte[fs.Length];
fs.Read(mybyte, 0, mybyte.Length);
pictureBox1.Image = Image.FromStream(fs);
//将照片位于标签上方,以免被标签覆盖遮挡
pictureBox1.BringToFront();
fs.Close();
}
}
#endregion
//因为不想再添加再次确认密码的功能,直接添加复选框显示密码,让用户确认输入的密码
#region 显示/隐藏密码
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if(checkBox1.Checked)
{
//复选框被勾选,显示密码
passwordreg_txt.PasswordChar = new char();
}
else
{
//复选框为被勾选,隐藏密码
passwordreg_txt.PasswordChar = '*';
}
}
#endregion
}
}
主要方法:init
、Mail_btn_Click
、timer1_Tick
、timer2_Tick
、register_btn_Click
、EncryptWithMD5
、pictureBox1_Click
、checkBox1_CheckedChanged
其中
init
:初始化方法,初始化界面。
Mail_btn_Click
:获取验证码按钮事件,用于获取邮箱验证码。
timer1_Tick
:计时器1计时事件,用于将计时器1的时间显示在“获取验证码”上,提示用户还有多久才能再次获取验证码。
timer2_Tick
:时间2计时事件,用于计时已发送验证码的有效时间。
register_btn_Click
:点击“注册”按钮的事件,具体的事件后面描述。
EncryptWithMD5
:MD5加密算法方法,实际的密码经过该方法后,返回经MD5加密的密码。
pictureBox1_Click
:点击图片框触发的事件,打开本地文件对话框,选择要上传的头像图片。
checkBox1_CheckedChanged
:复选框改变事件,用于改变密码文本框的显示(显示密码和隐藏密码)。
用于触发打开文件对话框,选择要上传的新头像。
这里主要使用了自定义类MailVeriCode,详细方法上面已给出。只需要向MailVeriCode的SendMailMessage方法里传参:收件人邮箱、发件人邮箱、发件人邮箱授权码、邮件内容、邮件标题,即可完成发送。但在此之前,也需要用MailVeriCode类中的CheckMail方法检验收件人邮箱的有效性(只支持发送qq邮箱)。
同时,打开两计时器的计时,一个作为获取新验证码的时间放在“获取验证码”按钮上,另一个作为验证码的有效性计时。
这里主要是判断用户所有输入信息的正确性,包括用户名是否已被注册、邮箱是否已被注册、头像是否已上传、邮箱验证码是否正确。通过连接Application数据库,查询UserData表,若用户名和邮箱均未被注册、头像已上传,且邮箱验证码正确,则将用户名、用户邮箱、新生成的ID、用户密码以及邮箱插入UserData表中,完成用户的注册。
注册界面的主要功能:
注册界面的较登录界面复杂一些,登录界面主要是对数据库进行查询操作,而注册界面要完成数据库的查询、插入操作。除此之外,还要完成邮箱验证码的发送和规定有效时间。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Database
{
public partial class Forget : Form
{
public Forget()
{
InitializeComponent();
init();
}
#region 参数初始化
private void init()
{
this.MaximizeBox = false; //禁止最大化
//使标签透明化
forget_lab.BackColor = Color.Transparent;
mail_lab.BackColor = Color.Transparent;
password_lab.BackColor = Color.Transparent;
vericode_lab.BackColor = Color.Transparent;
//使按钮透明化
mail_btn.FlatStyle = FlatStyle.Flat;
mail_btn.ForeColor = Color.Transparent;
mail_btn.BackColor = Color.Transparent;
mail_btn.FlatAppearance.BorderSize = 1;
mail_btn.FlatAppearance.MouseOverBackColor = Color.Transparent;
mail_btn.FlatAppearance.MouseDownBackColor = Color.Transparent;
showpw_btn.BackColor = Color.Transparent;
}
#endregion
#region 获取验证码按钮事件
int seconds1 = 60;//倒计时60s
int seconds2 = 60 * 5;//验证码有效时间5分钟
string strMailVeriCode;
private void mail_btn_Click(object sender, EventArgs e)
{
string recEMailAddress = mail_txt.Text.Trim();//收件人邮箱
if(!mail_exist(recEMailAddress))
{
MessageBox.Show("邮箱未注册!");
return;
}
strMailVeriCode = MailVeriCode.CreateRandomMailCode(6);
string strBody = "验证码:" + strMailVeriCode + ",5分钟内有效,请勿泄漏于他人。如非本人操作,请忽略。系统邮件请勿回复。";//邮件内容
string strSubject = "【小田账本】找回密码";//邮件标题
string strMyEmailAddress = "[email protected]";//发件人邮箱
string strAuthorizationCode = "xxxxxxxxxxxx";//邮箱授权码
if (string.IsNullOrEmpty(recEMailAddress))//判断是否输入了邮箱
{
MessageBox.Show("请输入邮箱!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
mail_txt.Focus();
}
else if (MailVeriCode.CheckMail(recEMailAddress) == false)//判断邮箱格式是否正确
{
MessageBox.Show("您输入的QQ邮箱有误,请重新输入!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
mail_txt.Focus();
return;
}
else//发送验证码
{
//发送
if (MailVeriCode.SendMailMessage(strMyEmailAddress, recEMailAddress, strSubject, strBody, strAuthorizationCode) == true)
{
mail_btn.Enabled = false;
//计时器初始化
timer1.Interval = 1000;
timer1.Start();
timer2.Interval = 1000;
timer2.Start();
}
else
{
vericode_txt.Focus();
}
}
}
#endregion
#region 时钟1计时事件
private void timer1_Tick(object sender, EventArgs e)
{
if (seconds1 > 0)
{
seconds1--;
mail_btn.Text = "剩余" + seconds1.ToString() + "秒";
}
else
{
timer1.Stop();
mail_btn.Text = "获取验证码";
mail_btn.Enabled = true;
}
}
#endregion
#region 时钟2计时事件
private void timer2_Tick(object sender, EventArgs e)
{
if (seconds2 == 0)
{
timer2.Stop();
//旧的验证码过期,生成一个新的验证码
strMailVeriCode = MailVeriCode.CreateRandomMailCode(6);
}
}
#endregion
#region 查找邮箱存在性
private bool mail_exist(string mail)
{
string sqlconf = "Data Source = .;Initial Catalog = Application;Integrated Security = SSPI";
SqlConnection sqlConnection = new SqlConnection(sqlconf);
sqlConnection.Open();
string sql1 = "select UserMail from UserData where UserMail = '" + mail + "'";
SqlCommand sqlCommand1 = new SqlCommand(sql1, sqlConnection); //确认邮箱是否已被注册
SqlDataReader sqlDataReader = sqlCommand1.ExecuteReader();
bool a = sqlDataReader.HasRows;
sqlDataReader.Close();
sqlConnection.Close();
if (a)
{
return true; //邮箱存在
}
else
{
return false; //邮箱不存在
}
}
#endregion
#region 找回密码确认按钮事件
private void confirm_btn_Click(object sender, EventArgs e)
{
string mailVeriCode = vericode_txt.Text.Trim();//邮箱验证码
//先确认一些重要信息为非空
if (mail_txt.Text.Trim() != "" && password_txt.Text.Trim() != "")
{
string mail = mail_txt.Text.Trim();
if(!mail_exist(mail))
{
MessageBox.Show("邮箱未注册!");
return;
}
if (string.IsNullOrEmpty(mailVeriCode) == true)
{
MessageBox.Show("请输入验证码", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
vericode_txt.Focus();
return;
}
else if (mailVeriCode.ToLower() != strMailVeriCode.ToLower())//判断邮箱验证码是否输入正确;不区分字母大小写
{
MessageBox.Show("您输入的验证码有误!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
vericode_txt.Focus();
return;
}
string sqlconf = "Data Source = .;Initial Catalog = Application;Integrated Security = SSPI";
SqlConnection sqlConnection = new SqlConnection(sqlconf);
string password = EncryptWithMD5(password_txt.Text.Trim());
sqlConnection.Open();
string sqlStr = "update UserData Set UserPassword = '" + password + "'where UserMail = '"+ mail +"'";
SqlCommand cmd = new SqlCommand(sqlStr, sqlConnection);
cmd.ExecuteNonQuery();
MessageBox.Show("修改密码成功!");
sqlConnection.Close();
this.Close();
}
else if (mail_txt.Text.Trim() == "" && password_txt.Text.Trim() != "")
{
MessageBox.Show("请填写邮箱!","提示");
mail_txt.Focus();
}
else if (mail_txt.Text.Trim() != "" && password_txt.Text.Trim() == "")
{
MessageBox.Show("请填写新密码!", "提示");
password_txt.Focus();
}
else
{
MessageBox.Show("请完善相关信息!", "提示");
mail_txt.Focus();
}
}
#endregion
#region MD5加密算法
private string EncryptWithMD5(string source)//MD5加密
{
byte[] sor = Encoding.UTF8.GetBytes(source);
MD5 md5 = MD5.Create();
byte[] result = md5.ComputeHash(sor);
StringBuilder strbul = new StringBuilder(40);
for (int i = 0; i < result.Length; i++)
{
strbul.Append(result[i].ToString("x2"));//加密结果"x2"结果为32位,"x3"结果为48位,"x4"结果为64位
}
return strbul.ToString();
}
#endregion
#region 显示/隐藏密码
private void showpw_btn_CheckedChanged(object sender, EventArgs e)
{
if (showpw_btn.Checked)
{
//复选框被勾选,显示密码
password_txt.PasswordChar = new char();
}
else
{
//复选框为被勾选,隐藏密码
password_txt.PasswordChar = '*';
}
}
#endregion
}
}
主要方法:init
、mail_btn_Click
、timer1_Tick
、timer2_Tick
、confirm_btn_Click
、EncryptWithMD5
、showpw_btn_CheckedChanged
、mail_exist
其中
init
:初始化方法,初始化界面。
mail_btn_Click
:获取验证码按钮事件,用于获取邮箱验证码。
timer1_Tick
:计时器1计时事件,用于将计时器1的时间显示在“获取验证码”上,提示用户还有多久才能再次获取验证码。
timer2_Tick
:时间2计时事件,用于计时已发送验证码的有效时间。
confirm_btn_Click
:点击“确认”按钮的事件,具体的事件后面描述。
EncryptWithMD5
:MD5加密算法方法,实际的密码经过该方法后,返回经MD5加密的密码。
showpw_btn_CheckedChanged
:复选框改变事件,用于改变密码文本框的显示(显示密码和隐藏密码)。
mail_exist
:连接数据库,查询账户邮箱的存在性。
这里就不再赘述了,和注册界面的“获取验证码”按钮出发的事件完全一样,就是将邮件的标题改为“找回密码”。
首先,连接Application数据库通过UserData表确认邮箱是否已注册,若已注册,则检查输入验证码的正确性,若上述信息均正确,则将输入的新密码更新到UserData表中相应邮箱的用户密码。
找回界面的主要功能:
获取邮箱验证码;
通过验证账户邮箱的存在性和验证码的正确性,连接数据库进行用户密码更新操作。
找回密码的实现和注册账户差不多,可以说大部分代码可以直接从注册界面照搬,唯一的区别在于,找回密码需要的数据交互更少,不需要向数据库表插入数据,只需要查询数据和更新数据。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Database
{
public partial class Main : Form
{
private static float inmoney;
private static float outmoney;
public static string pathPicture;
static string userid;
static string username;
static string usermail;
static string password;
public Main()
{
InitializeComponent();
}
#region 有参构造窗体初始化
public Main(string Username)
{
InitializeComponent();
init(Username);
}
#endregion
#region 初始化参数和导入数据库数据
public void init(string Username)
{
inmoney = 0;
outmoney = 0;
this.MaximizeBox = false; //禁止最大化
//创建数据库连接对象
string sqlconf = "Data Source = .;Initial Catalog = Application;Integrated Security = SSPI";
SqlConnection sqlConnection = new SqlConnection(sqlconf);
sqlConnection.Open();
string sqlStr = "select *from UserData where UserName = '" + Username + "'";
SqlCommand cmd = new SqlCommand(sqlStr, sqlConnection);
SqlDataReader sqlDataReader = cmd.ExecuteReader();
//获取查询到的内容
if (sqlDataReader.Read())
{
usermail = sqlDataReader["UserMail"].ToString().Trim();
userid = sqlDataReader["ID"].ToString();
username = Username;
password = sqlDataReader["UserPassword"].ToString();
}
sqlDataReader.Close();
//加载用户信息
id_lab.Text = userid;
username_lab.Text = username;
mail_lab.Text = usermail;
//加载头像
sqlStr = "select UserPhoto from UserData where UserName = '" + Username + "'";
cmd = new SqlCommand(sqlStr, sqlConnection);
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
sqlDataAdapter.Fill(ds, "UserData");
int c = ds.Tables["UserData"].Rows.Count;
if (c > 0)
{
Byte[] mybyte = new byte[0];
mybyte = (Byte[])(ds.Tables["UserData"].Rows[c - 1]["UserPhoto"]);
MemoryStream ms = new MemoryStream(mybyte);
pictureBox1.Image = Image.FromStream(ms);
}
else
pictureBox1.Image = null;
//加载记账数据
sqlStr = "select *from Account where UserID = '" + Main.userid + "'";
cmd = new SqlCommand(sqlStr, sqlConnection);
sqlDataReader = cmd.ExecuteReader();
while(sqlDataReader.Read())
{
string inorout_tmp = sqlDataReader["InOrOut"].ToString().Trim();
string conType_tmp = sqlDataReader["ConsumeType"].ToString();
float price_tmp = (float)Convert.ToDouble(sqlDataReader["Price"]);
string note_tmp = sqlDataReader["NOTE"].ToString();
string time_tmp = Convert.ToDateTime(sqlDataReader["RecordDate"]).Date.ToString("D");
if(inorout_tmp.Equals("收入"))
{
income_list.Items.Add(conType_tmp + "\t" + price_tmp.ToString() + "元\t" + time_tmp + "\t" + note_tmp);
innum_lab.Text = income_list.Items.Count.ToString();
inmoney = inmoney + price_tmp;
inmoney_lab.Text = Convert.ToString(inmoney);
}
else
{
expend_list.Items.Add(conType_tmp + "\t" + price_tmp.ToString() + "元\t" + time_tmp + "\t" + note_tmp);
outnum_lab.Text = expend_list.Items.Count.ToString();
outmoney = outmoney + price_tmp;
outmoney_lab.Text = Convert.ToString(outmoney);
}
}
sqlConnection.Close();
}
#endregion
#region 收入单选按钮事件
private void income_btn_CheckedChanged(object sender, EventArgs e)
{
matter_box.Items.Clear();
matter_box.Items.Add("工资");
matter_box.Items.Add("理财");
matter_box.Items.Add("礼金");
matter_box.Items.Add("其他");
matter_box.Text = "";
}
#endregion
#region 支出单选按钮事件
private void expend_btn_CheckedChanged(object sender, EventArgs e)
{
matter_box.Items.Clear();
matter_box.Items.Add("餐饮");
matter_box.Items.Add("购物");
matter_box.Items.Add("交通");
matter_box.Items.Add("娱乐");
matter_box.Items.Add("医疗");
matter_box.Items.Add("彩票");
matter_box.Items.Add("旅行");
matter_box.Items.Add("运动");
matter_box.Items.Add("通讯");
matter_box.Items.Add("社交");
matter_box.Items.Add("学习");
matter_box.Items.Add("其他");
matter_box.Text = "";
}
#endregion
#region 记录按钮事件
private void record_btn_Click(object sender, EventArgs e)
{
//创建数据库连接对象
string sqlconf = "Data Source = .;Initial Catalog = Application;Integrated Security = SSPI";
SqlConnection sqlConnection = new SqlConnection(sqlconf);
string inorout;
if (income_btn.Checked == true)
{
income_list.Items.Add(matter_box.Text+"\t"+money_txt.Text+"元\t"+ dateTimePicker1.Text+"\t"+note_txt.Text);
innum_lab.Text = income_list.Items.Count.ToString();
inmoney = inmoney + float.Parse(money_txt.Text);
inmoney_lab.Text = Convert.ToString(inmoney);
inorout = "收入";
}
else
{
expend_list.Items.Add(matter_box.Text + "\t" + money_txt.Text + "元\t" + dateTimePicker1.Text + "\t" + note_txt.Text);
outnum_lab.Text = expend_list.Items.Count.ToString();
outmoney_lab.Text = Convert.ToString(float.Parse(outmoney_lab.Text) + float.Parse(money_txt.Text));
inorout = "支出";
}
//更新数据库
string consumeType = matter_box.Text;
string note = note_txt.Text;
float price = float.Parse(money_txt.Text.Trim());
string time = dateTimePicker1.Text;
sqlConnection.Open();
string insertStr = "insert into Account(UserID,InOrOut,ConsumeType,NOTE,Price,RecordDate)" + "values('" + userid + "','" + inorout + "','" + consumeType + "','" + note + "','" + price + "','" + Convert.ToDateTime(time) + "')";
SqlCommand cmd = new SqlCommand(insertStr, sqlConnection);
cmd.ExecuteNonQuery();
sqlConnection.Close();
}
#endregion
#region 点击头像事件(修改头像)
private void pictureBox1_Click(object sender, EventArgs e)
{
//设置文件对话框显示的初始目录为系统桌面
this.openFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
//设置当前选定筛选器字符串以决定对话框中“文档类型”选项
this.openFileDialog1.Filter = "bmp文件(*.bmp)|*.bmp|gif文件(*.gif)|*.gif|jpeg文件(*.jpg)|*.jpg|png文件(*.png)|*.png";
//设置对话框中当前选定筛选器的索引
this.openFileDialog1.FilterIndex = 3;
//关闭对话框,还原当前目录
this.openFileDialog1.RestoreDirectory = true;
//设置对话框标题
this.openFileDialog1.Title = "选择头像照片";
if (this.openFileDialog1.ShowDialog() == DialogResult.OK)
{
Byte[] picbyte = new byte[0];
pathPicture = this.openFileDialog1.FileName;
FileStream fs = new FileStream(pathPicture, FileMode.Open, FileAccess.Read);
picbyte = new byte[fs.Length];
fs.Read(picbyte, 0, picbyte.Length);
pictureBox1.Image = Image.FromStream(fs);
fs.Close();
//连接数据库,更换头像信息(因为不会更新sql server的二进制数据流,用了一个比较笨的方法:直接删除重写账号信息)
string sqlconf = "Data Source = .;Initial Catalog = Application;Integrated Security = SSPI";
SqlConnection sqlConnection = new SqlConnection(sqlconf);
string userid = id_lab.Text.Trim();
sqlConnection.Open();
string sqlStr = "delete from UserData where ID = '" +userid+ "'";
SqlCommand sqlCommand = new SqlCommand(sqlStr,sqlConnection);
sqlCommand.ExecuteNonQuery();
sqlStr = "insert into UserData(ID,UserPassword,UserMail,UserName,UserPhoto)" + "values (@userid, @userpassword,@usermail,@username,@userphoto)";
SqlCommand command = new SqlCommand(sqlStr, sqlConnection);
SqlParameter sqlParameter = new SqlParameter("@userid", userid);
command.Parameters.Add(sqlParameter);
sqlParameter = new SqlParameter("@userpassword", password);
command.Parameters.Add(sqlParameter);
sqlParameter = new SqlParameter("@usermail", usermail);
command.Parameters.Add(sqlParameter);
sqlParameter = new SqlParameter("@username", username);
command.Parameters.Add(sqlParameter);
sqlParameter = new SqlParameter("@userphoto", System.Data.SqlDbType.Image);
sqlParameter.Value = picbyte;
command.Parameters.Add(sqlParameter);
command.ExecuteNonQuery();
sqlConnection.Close();
MessageBox.Show("更改头像成功!");
}
}
#endregion
#region 关闭窗口事件
private void Main_FormClosed(object sender, FormClosedEventArgs e)
{
System.Environment.Exit(0);
}
#endregion
}
}
主要方法:
init
、income_btn_CheckedChanged
、expend_btn_CheckedChanged
、record_btn_Click
、pictureBox1_Click
、Main_FormClosed
其中
init
:初始化方法,初始化界面,以及将用户数据从数据库导入。
income_btn_CheckedChanged
和expend_btn_CheckedChanged
:单选框选择改变事件,用于更新下拉栏的内容。
record_btn_Click
:“记录”按钮事件,具体的事件后面描述。
pictureBox1_Click
:点击图片框触发的事件,打开本地文件对话框,选择要上传的头像图片,用于更改头像。
Main_FormClosed
:窗口关闭事件,当窗口关闭后,使所有程序结束运行。
当点击"记录按钮后",会将用户选择的记录类型、金额、时间以及备注附加到相应种类的ListBox上,并连接Application数据库,将当前用户ID和记账的数据添加到Account表上。
用于触发打开文件对话框,选择要上传的新头像。选择成功后,删除UserData上对应用户的数据,重新给该用户创建新账号,附上新头像(其他信息不变)(感觉这是比较笨的方法了,但是本人初学数据库太菜,不知道怎么单独更新照片的数据)。
这是所有窗体中,需要实现数据库交互功能最多的窗体(但是论实现的功能和复杂性,还是比注册界面略逊一筹),也是整个系统主要的窗体,用于实现记账功能。其中需要与数据库的进行数据交互的操作就有:查询、插入、删除。
个人认为不足的是没有删除记录项的功能,这导致整个系统很累赘,但由于时间关系,最终没能完善,有能力的各位大佬可以再次基础上继续完善,日后我自己若是有机会完善的话会再次更新。
【参考资料】
数据库大作业-代码展示(C#).
C# 数据库大作业-学生管理系统.
ASP.NET(C#)操作SQL Server数据库.
SQL | 菜鸟教程.