.NET編程技術——實驗09:Access數據庫的創建、表創建、MD5加密,數據、圖片保存在數據庫的用法

閱讀須知:純粹是本人啊Jun作爲初學者的筆記和個人對其中知識的複習,大神請繞道。微笑



實驗01:VS2015 對象瀏覽器的使用、簡單調試和斷點使用。

實驗04:RS485串口調試、基本控件使用、CRC算法應用

實驗05:RS485串口通訊,串口指令的收發應用,完成串口基礎功能,github地址:實驗05

實驗06:窗體應用的最小化在Windows狀態欄中顯示托盤圖標

實驗07:Windows的註冊表的基本使用方法,文件流保存爲文本文件基礎用法

實驗08:利用GDI+技術生成簡單驗證碼,類似excel的數據折線圖、並保存爲圖片

實驗09:Access數據庫的創建、表創建、MD5加密,數據、圖片保存在數據庫的用法

實驗10:將DataGridView表單數據保存爲excel文件,表單的基本格式化


包含實驗06~實驗10的功能:github地址:實驗10


實驗09題目如下:

2、通過Access創建出相應MDB數據庫,根據數據庫關係圖,建好數據表;

3、在系統中建立全局性的靜態的數據庫鏈接對象,在系統的登錄界面中,可以通過數據庫進行用戶名和密碼的驗證,確保只有合法用戶才能登錄,密碼要求用MD5進行加密;

4、系統中添加註銷功能,通過註銷動作,能夠清除用戶信息,能夠關閉數據庫鏈接,但無需關閉主界面。可以重複“登錄”-“註銷”這兩個動作;

5、在收發溫度中,能實時把溫度數據存儲到數據庫中;

6、在保存曲線圖時,可以選擇把曲線圖片直接保存到數據庫中。


先來看第2題 ->2、通過Access創建出相應MDB數據庫,根據數據庫關係圖,建好數據表;

在期末驗收的時候,我看到很多同學,都是先創建好access數據庫,並且在數據庫裏面建好表以後,在運行程序。

因爲強迫症的原因,堅決要我的程序可以自動創建數據庫和自動創建表結構,所以在這方面可是花了比較多的時間,不過當可以實現我的想法的時候,就不會覺得這些時間是被浪費掉了。


首先需要引用微軟的ADOX.dll。什麼是ADOX呢,百度給出解釋(Microsoft ActiveX Data ObjectsExtensions for Data Definition Language and Security)是對ADO對象和編程模型的擴展。他可用於創建,修改和刪除對象。


在找資料的同時,我發現好像普通的sql語句是不能創建一個數據庫的,唯有用了ADOX纔可以動態地創建數據庫。例如動態創建mdb文件。其實實現起來也不難,但是如果沒有了這一環節,我覺得會給用戶帶來很多的不方便。


using ADOX;
private ADOX.Catalog catalog = new Catalog();
public Access(string filePath)  //Access構造函數
{
    this.filePath = filePath;
    this.connection = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + filePath;   //新建數據庫的路徑
}


/// <summary>
/// 創建數據庫
/// </summary>
public void creatDataDB()
{


    if (!File.Exists(filePath))  //如果數據庫不存在,那就添加數據庫
    {
        try
        {
            catalog.Create(connection);   //  ADOX.Catalog 對象,可以新建一個數據庫


        }
        catch (Exception ex)
        {
            Console.WriteLine("error:" + ex);
        }
    }
}


因爲我的程序都是LoginForm登錄界面)開始的,所以Access數據庫對象,我用瞭如下的全局變量,

 public static Access access; //Access數據庫對象
 public static string accessFileRoad = @"..\..\..\\Jun.mdb";   //數據庫路徑


然後我的數據庫創建放在了RegisterForm用戶註冊界面)的中,然後調用LoginForm的access對象。

LoginForm.access.creatDataDB();  //創建數據庫
LoginForm.access.createUserTable("管理員");   //在數據庫創建管理員和一般用戶
LoginForm.access.createUserTable("一般用戶");


下面就是老師教的程序的單一入口了,我的主窗體(MainForm)纔是真正的主程序,在初始化MainForm_Load事件之前,先定義一個LoginForm(登錄界面)對象,便進入了登錄界面。

/// <summary>
/// 主程序的單一入口
/// </summary>
public MainForm()
{
    LoginForm loginForm = new LoginForm();  //先定義一個LoginForm 窗體對象
    DialogResult result = loginForm.ShowDialog();   //窗體對象的模式對話結果,
    if (result == DialogResult.Cancel)   //如果結果爲Cancel,就退出整個程序
    {
        Environment.Exit(0);
    }

    else if (result == DialogResult.Yes)  //如果結果爲Yes,就初始化 MainForm_Load
    {
        InitializeComponent();
    }

}



進入登錄界面後,這是管理員的登錄,我這裏將註冊表和數據庫的信息都匹配了


if (adminRegistry.isRegistryValueNameExist(userName, ref password) && accessPassword != null)  //先判斷該管理員是否在數據庫和註冊表內
{
    if (string.Equals(passwordTextBox.Text.Trim(), password) && string.Equals(md5.MD5Encryption(passwordTextBox.Text.Trim()), accessPassword))  //密碼匹配正確,先將輸入框密碼MD5加密,再和數據庫的加密後的密碼比較
    {
        if (captchaText == recaptcha)  //驗證碼匹配正確
        {
            this.DialogResult = DialogResult.Yes;  //返回ok ,進入主窗體
        }
        else
            MessageBox.Show("驗證碼輸入錯誤!");

    }
    else
        MessageBox.Show("密碼錯誤!");
}
else
    MessageBox.Show("該管理員不存在!");


LoginForm(登錄界面)在用戶信息填寫成功後,並點擊“登錄”按鈕,就將窗體的返回結果DialogResult = Yes

 this.DialogResult = DialogResult.Yes;  //返回ok ,進入主窗體


這個之前 實驗07OpenFileDialog的時候,就是這個原理。

而DialogResult.Cancel 我記得是關閉窗體,對話框返回的結果


好吧,窗體對話框對象只能講這麼一點了,

下面就是ADOX的對象,但是我只創建了Catalog這個對象,Catalog(目錄),其他的對象基本都是創建表

和索引之類的,但是這些操作,我就更加喜歡用sql語句操作就好了,所以爲了動態創建一個mdb文件,

就大費周章調用一個引用,不知道是好是壞。


動態建完數據庫後,就可以運用sql語句進行建表和插入數據了,首先是引用OLEDB.dill這個玩意,

oledb鏈接SQL SERVER:

connection ="PROVIDER=SQLOLEDB; Data Source=" + filePath;

oledb鏈接Access:

connection = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + filePath;
全局性的靜態的數據庫鏈接對象:
OleDbConnection cn= new OleDbConnection(connection);

下面就是創建表的結構

//sql語句,
string queryString = "create table " + tableName + " (id AUTOINCREMENT primary key, 用戶名 varchar(50) NOT NULL, 密碼 varchar(50) NOT NULL)";
OleDbConnection cn = new OleDbConnection(connection);

cn.Open();

OleDbCommand cmd = new OleDbCommand(queryString, cn);

int i = cmd.ExecuteNonQuery();
Console.WriteLine("i: " + i);
cmd.Dispose();
cn.Close();
cn.Dispose();


我建了五個表,如下。其中“管理員”和“一般用戶”就是儲存管理員和一般用戶的信息,其中密碼已經經過了MD5加密算法進行了加密。



我記得老師說,MD5加密現在目前爲止是普通加密中最爲安全的,之前沒瞭解到,用了RSA加密,但是RSA加密

需要容器的,有加密也有解密,但是MD5是隻有加密,不能解密;意思就是你輸入你的密碼後,要匹配數據庫裏面

的加密後的密碼,也是需要MD5加密後才能匹配,所以一般就算在匹配途中,別人竊取了你的密碼都是加密後的

密文,不會出現明文,所以是比較安全。之前我不相信,在百度找MD5解密的工具:MD5解密 ,老師說,這個只

不過是記錄了24萬億條數據,並不是什麼解密算法,你只需要設置你的密碼爲8位以上,他就解不開了。

感覺非常有道理。



MD5加密也比較簡單,代碼:

using System.Security.Cryptography;  //MD5需要的引用
class Md5
{
    private MD5 md5;

    public Md5()
    { 
        md5 = new MD5CryptoServiceProvider();

    }

    /// <summary>
    /// MD5不可逆的加密
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public string MD5Encryption(string input)
    {
        string output = null;
        byte[] inputByte = Encoding.Default.GetBytes(input);
        byte[] outputByte = md5.ComputeHash(inputByte);

        for(int i=0;i<outputByte.Length;i++)
        {
            output += outputByte[i].ToString("X");   //轉換爲16進制數
        }

        //   output = Encoding.Default.GetString(outputByte);

        return output;

    }

}


4、系統中添加註銷功能,通過註銷動作,能夠清除用戶信息,能夠關閉數據庫鏈接,但無需關閉主界面。可以重複“登錄”-“註銷”這兩個動作;

這裏註銷的功能,我想了好久,最後無能爲力,只能重新啓動程序好了

Application.Restart();

5、在收發溫度中,能實時把溫度數據存儲到數據庫中;

其實我覺得,會了Access操作,這些都是同一樣東西來的,數據庫的增刪改查,

但是我寫的Access類就不算很好的一個類。很多重複的操作,很是尷尬。

LoginForm.access.insertTemperature("溫度表", LoginForm.userName, DateTime.Now.ToString(), tempTextBox.Text + "℃");


溫度表就是儲存用戶獲取的溫度和獲取時間



6、在保存曲線圖時,可以選擇把曲線圖片直接保存到數據庫中。

最後一題,在Access數據庫裏保存圖片算是一個難點了,溫度折現圖表就是儲存用戶想要保存的溫度圖片,其中在Access中保存圖片的格式是OLEObject,

數據庫插入圖片代碼:由於存進去的是長二進制類型,其實就是byte數組)其實這種插入語句我不太會用,但是從語法看起來就是在這些字段中Add一個變量進去數據庫。

cmd.Parameters.Add("@type",OleDbType.VarChar).Value = userType; 

代碼:

/// <summary>
/// 插入圖片
/// </summary>
/// <param name="tableName"></param>
/// <param name="fileName"></param>
public void insertPicutre(string tableName, string userType, string userName, string pictureName, string fileName)
{
    try
    {


        FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
        BinaryReader binaryReader = new BinaryReader(fs);
        byte[] data = binaryReader.ReadBytes((int)fs.Length);


        Console.WriteLine("輸入圖片信息:" + Encoding.Default.GetString(data));


        //string queryString = "insert into " + tableName + " (圖片名, 圖片) values( '" + pictureName + "', '" + data + "')";  //原來的語句,插入圖片不完整
        string queryString1 = "insert into " + tableName + " (用戶類型, 用戶名, 圖片名, 圖片) values (@type, @name, @pic, @data)";  //改良後的語句,插入圖片完整




        OleDbConnection cn = new OleDbConnection(connection);
        cn.Open();


        OleDbCommand cmd = new OleDbCommand(queryString1, cn);


        cmd.Parameters.Add("@type",OleDbType.VarChar).Value = userType;  // 另一種插入方法   
        cmd.Parameters.Add("@name", OleDbType.VarChar).Value = userName;
        cmd.Parameters.Add("@pic", OleDbType.VarChar).Value = pictureName;
        cmd.Parameters.Add("@data", OleDbType.Binary).Value = data;


        cmd.ExecuteNonQuery();
        cmd.Dispose();
        cn.Close();
        cn.Dispose();
    }
    catch (OleDbException ex)
    {
        Console.WriteLine("error from insertPicture: " + ex);
    }
}


既然能插入圖片了,那麼查詢圖片就簡單了,這裏查找的sql語句就好理解一點。由於這次的實驗沒有給出返回圖片

的功能,但是期末考覈我就添加上了,到時我會整理在Github上:https://github.com/JunStitch

查詢圖片代碼:返回一個byte數組就ok啦

/// <summary>
/// get 一張 圖片
/// </summary>
/// <param name="tableName"></param>
/// <param name="pictureName"></param>
public byte[] getPicture(string tableName, string userType, string userName, string pictureName)
{
    byte[] pictureByte = null;
    try
    {
        //string queryString = "select 圖片 from " + tableName + " where ";
        string queryString = "select 圖片 from " + tableName + " where 用戶類型 = '" + userType + "' And 用戶名 = '" + userName + "' And  圖片名 = '" + pictureName+"' ";
        OleDbConnection cn = new OleDbConnection(connection);
        cn.Open();

        OleDbCommand cmd = new OleDbCommand(queryString, cn);

        pictureByte = (byte[])cmd.ExecuteScalar();

        Console.WriteLine("輸出圖片信息:" + Encoding.Default.GetString(pictureByte));

        cmd.Dispose();
        cn.Close();
        cn.Dispose();

    }
    catch (OleDbException ex)
    {
        Console.WriteLine("error from getPicture: " + ex);
    }

    return pictureByte;
}


還有就是,只有管理員纔可以進行串口的設置,一般用戶不能進行串口設置,只能獲取溫度。

按照我的理解,由於我電腦串口名稱是COM3,除了溫度計這個串口,還有其他的串口,所以爲了區分串口名,在註銷之前,我就會將串口的所有設置保存在了“串口配置表”裏,如下圖。

/// <summary>
/// “註銷”按鈕 , 當“管理員” 註銷時,其設置的串口配置將會被保存
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// 
    private void logoutButton_Click(object sender, EventArgs e)
{
    if (LoginForm.userType == "管理員")
    {
        config[0] = portComboBox.Text;
        config[1] = baudRateComboBox.Text;
        config[2] = dataBitComboBox.Text;
        config[3] = stopBitComboBox.Text;

        if (hexReceRadioButton.Checked)  //如果接收類型爲16進制
            config[4] = "HEX";
        else
            config[5] = "ASCII";

        if (hexSendRadioButton.Checked) //如果發送類型爲16進制
            config[5] = "HEX";
        else
            config[5] = "ASCII";

        LoginForm.access.updateConfig("串口配置表", config);
    }

    Application.Restart();
            
}





下面附上用戶信息的Access數據庫的增刪改查代碼吧:


/// <summary>
/// 創建管理員和普通用戶用戶表
/// </summary>
/// <param name="tableName"></param>
public void createUserTable(string tableName)
{
    if (File.Exists(filePath))//如果數據庫存在
    {
        try
        {

            //sql語句,
            string queryString = "create table " + tableName + " (id AUTOINCREMENT primary key, 用戶名 varchar(50) NOT NULL, 密碼 varchar(50) NOT NULL)";
            OleDbConnection cn = new OleDbConnection(connection);

            cn.Open();

            OleDbCommand cmd = new OleDbCommand(queryString, cn);

            int i = cmd.ExecuteNonQuery();
            Console.WriteLine("i: " + i);
            cmd.Dispose();
            cn.Close();
            cn.Dispose();


        }
        catch (OleDbException ex)
        {
            Console.WriteLine("error: " + ex.Message);
        }
    }
    else
    {
        Console.WriteLine("數據庫不存在,不能創建表");
        // MessageBox.Show("數據庫不存在,不能創建表");
    }
}


/// <summary>
/// 插入用戶或者管理員,插入成功返回true
/// </summary>
/// <param name="tableName"></param>
/// <param name="fileName"></param>
public bool insertUser(string tableName, string name, string password)
{
    bool flag = false;
    try
    {
        if (searchUser(tableName, name) == null)
        {
            string queryString = "insert into " + tableName + " (用戶名,密碼) values( '" + name + "' , '" + password + "')";
            //string queryString = "insert into " + tableName + " (用戶名,密碼) values('', '" + name + "' , '" + password + "')";
            //string queryString = "insert into " + tableName + " values('1','admin','admin')";
            OleDbConnection cn = new OleDbConnection(connection);
            cn.Open();

            OleDbCommand cmd = new OleDbCommand(queryString, cn);
            cmd.ExecuteNonQuery();
            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            flag = true;
        }
        else
        {
            Console.WriteLine("用戶名已存在!");
            //MessageBox.Show("用戶名已存在!");
        }
    }
    catch (OleDbException ex)
    {
        Console.WriteLine("error from insertUser: " + ex);
    }

    return flag;
}

/// <summary>
/// 查找用戶,並且返回密碼
/// </summary>
/// <param name="tableName"></param>
/// <param name="name"></param>
public string searchUser(string tableName, string name)
{
    string password = null;
    if (File.Exists(filePath))//如果數據庫存在
    {
        try
        {
            bool flag = false;
            string queryString = "select 用戶名, 密碼 from " + tableName + " where 用戶名 = " + " '" + name + "' ";
                   

            OleDbConnection cn = new OleDbConnection(connection);
            cn.Open();

            OleDbDataAdapter adapter;
            adapter = new OleDbDataAdapter(queryString, cn);

            DataSet set = new DataSet();
            adapter.Fill(set);

            foreach (DataRow row in set.Tables[0].Rows)
            {
                foreach (DataColumn col in set.Tables[0].Columns)
                {
                    Console.Write(row[col].ToString() + '\t');

                    if (name == row["用戶名"].ToString())  //如果查找到相同的用戶名,則返回密碼,且退出循環
                    {
                        flag = true;
                        password = row["密碼"].ToString();
                        break;
                    }
                }
                Console.WriteLine();
            }

            if (!flag)
            {
                Console.WriteLine("沒有此用戶!");
                //MessageBox.Show("沒有此用戶!");
            }

        }
        catch (OleDbException ex)
        {
            Console.WriteLine("error from searchUser: " + ex);
        }
    }
    else
    {
        Console.WriteLine("數據庫不存在,不能查詢表");
        // MessageBox.Show("數據庫不存在,不能創建表");
    }

    return password;
}


/// <summary>
/// 用戶修改密碼
/// </summary>
/// <param name="tableName"></param>
/// <param name="config"></param>
public bool updatePassword(string tableName, string name, string oldPWD, string newPWD)
{
    bool flag = false;
    try
    {
        string password = searchUser(tableName, name);
        if (password != null)
        {
            if (password == oldPWD) //輸入驗證的沒有  md5 加密
            {

                OleDbConnection cn = new OleDbConnection(connection);
                cn.Open();

                string str = "update " + tableName + " set 密碼 = '" + newPWD + "' where 用戶名 = '" + name + "' ";

                OleDbCommand cmd = new OleDbCommand(str, cn);

                cmd.ExecuteNonQuery();
                cmd.Dispose();
                cn.Close();
                cn.Dispose();
                flag = true;
            }
            else
            {
                Console.WriteLine("密碼錯誤!");
                //MessageBox.Show("密碼錯誤!");
            }
        }

        else
        {
            Console.WriteLine("不存在此用戶!");
            //  MessageBox.Show("不存在此用戶!");
        }

    }
    catch (OleDbException ex)
    {
        Console.WriteLine("error from updateConfig : " + ex);
    }

    return flag;
}



/// <summary>
/// 刪除普通用戶
/// </summary>
/// <param name="tableName"></param>
/// <param name="name"></param>
/// <returns></returns>
public bool deleteUser(string tableName, string name)
{
    bool flag = false;
    try
    {
        if (searchUser(tableName, name) != null)
        {
            string quertString = "delete * from " + tableName + " where 用戶名 = '" + name + "' ";
            OleDbConnection cn = new OleDbConnection(connection);
            cn.Open();

            OleDbCommand cmd = new OleDbCommand(quertString, cn);
            cmd.ExecuteNonQuery();
            cmd.Dispose();
            cn.Close();
            cn.Dispose();
            flag = true;

        }
        else
        {
            Console.WriteLine("此用戶不存在!");
            // MessageBox.Show("不存在此用戶!");
        }
    }
    catch (OleDbException ex)
    {
        Console.WriteLine("error from updateConfig : " + ex);
    }

    return flag;

}



實驗09完成奮鬥,如果有疑問或者在哪些地方有錯誤的,歡迎大家指出,共同學習,共同進步。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章