C#桌面办公应用-工资管理系统系列五

接前文系列四,本文将讲解实现工资管理系统的代码的层次结构。主要采用的是MVCS模式的代码层次结构,视图层(V):是各种winform窗体;控制层(C):主要是winform窗体中各种控件的各个逻辑处理事件;而模型层(M)则是各个model实体以及数据库访问层的代码;最后是服务层(S):是从模型层(M)中获取数据库访问操作的结果并为逻辑控制处理层(C)提供服务的层次。除此之外,还有另外的几个层次:工具类层util:主要是本系统共用的一些工具类的操作;报表打印层report:主要是在处理报表方面的共有操作;公共信息层commonMessage:主要是存放本系统在进行相关逻辑处理时候需要存放的一些通用的信息;最后是存放“图片或者文件”的文件层imageAndFile。如下图所示

在此说明一下,本系统其实并非传统的桌面C/S的单机版办公系统,经过测试,本系统是可以在局域网内实现服务器共享的C/S的桌面办公系统,只需要对服务器进行相应的配置,从而实现只需在每台主机安装一个本系统的客户端,就可以访问局域网内的服务器的数据了!

下面介绍一下本管理系统登录模块的实现。在前期,本管理系统的登录比较简单,只是采用userName和password明文进行登录验证而已!今天心血来潮,觉得“一个好的管理系统应该有登录功能,而登录则会涉及密码的验证,而密码的使用必然涉及到安全性问题,而安全则会不自觉跟加密解密挂上钩!”,所以,今天花了一个多小时,实现了采用MD5+自定义的字符串 实现用户登录与注册时候的密码解密与密码加密的功能,在下面会进行介绍!

下图是本系统用户登录的流程图。在贴上用户登录代码之前,需要先将获取数据库连接、数据库访问层的代码和系统共用的类的代码贴上!在系统后续的讲解中会时常使用到,但由于篇幅原因,并没有贴上全部,所以如果需要的话,可以QQ联系我QQ:1974544863(记得备注:桌面办公应用),我愿意低出售你并与你进行相关交流!

后续系统中出现SqlConnection conn = DBConnection.MyConnection(); 是从dbConnection包中获取的,主要的代码为:

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;//引用SQL命名空间
using System.Windows.Forms;
namespace SMS.dbConnection
{
    class DBConnection//定义类型
    {
        /// <summary>
        /// 返回数据库连接的静态方法
        /// </summary>
        /// <returns>方法返回数据库连接对象</returns>
       public static SqlConnection MyConnection()
       {
            return new SqlConnection(//创建数据库连接对象
@"server=.;database=db_SMS;uid=sa;pwd=123456");//数据库连接字符串
       }
    }
}

而operate和cmmUtils是在类的开始之处定义的:

        public frmLogin()
        {
            InitializeComponent();
        }

        //创建数据库操作对象
        DBOperate operate = new DBOperate();
        //工具类
        CommonUtils cmmUtils = new CommonUtils();

而DBOperate类和CommonUtils类的代码的作用分别为:数据库访问和共用的工具类,下面贴出各自的部分代码,下面是DBOperate类的代码:

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Drawing;
using SMS.dbConnection;

namespace SMS.dbOperation
{
    class DBOperate
    {
        //获取数据库链接
        SqlConnection conn = DBConnection.MyConnection();

        /// <summary>
        /// 操作数据库,执行各种SQL语句
        /// </summary>
        /// <param name="strSql">SQL语句</param>
        /// <returns>方法返回受影响的行数</returns>
        public int OperateData(String strSql)
        {
            try
            {
                conn.Open();//打开数据库连接
                SqlCommand cmd = new SqlCommand(strSql, conn);//创建命令对象
                int i = (int)cmd.ExecuteNonQuery();//执行SQL命令
                conn.Close();//关闭数据库连接
                return i;//返回数值
            }
            catch (System.Exception ex)
            {
                return -1;
            }

        }

        /// <summary>
        /// 根据SQL语句查询返回n行数据
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="conn"></param>
        /// <returns></returns>
        public SqlDataReader getSQLData(String sql,SqlConnection conn)
        {
            conn.Open();
            SqlCommand cmd = new SqlCommand(sql, conn);
            SqlDataReader sdr = cmd.ExecuteReader();
            return sdr;
        }

        /// <summary>
        /// 方法用于绑定DataGridView控件
        /// </summary>
        /// <param name="dgv">DataGridView控件</param>
        /// <param name="sql">SQL语句</param>
        public void BindDataGridView(DataGridView dgv, String sql)
        {
            SqlDataAdapter sda = new SqlDataAdapter(sql, conn);//创建数据适配器对象
            DataSet ds = new DataSet();//创建数据集对象
            sda.Fill(ds);//填充数据集
            dgv.DataSource = ds.Tables[0];//绑定到数据表
            ds.Dispose();//释放资源
        }

        /// <summary>
        /// 查找某个字段数量
        /// </summary>
        /// <param name="strsql">SQL语句</param>
        /// <returns>方法返回指定记录的数量</returns>
        public int HumanNum(String strsql)
        {
            conn.Open();//打开数据库连接
            SqlCommand cmd = new SqlCommand(strsql, conn);//创建命令对象
            int i = (int)cmd.ExecuteScalar();//执行SQL命令
            conn.Close();//关闭数据库连接
            return i;//返回数值
        }

        /// <summary>
        /// 根据数据库字段组成的sql语句,查询返回的结果集也是对应需要查询的数据库字段的值
        /// </summary>
        /// <param name="sql">sql中指定了要查询的字段</param>
        /// <param name="fieldNames">数据库字段数组</param>
        /// <returns></returns>
        public String[] GetDatasFromSelectedTable(String sql,String[] fieldNames)
        {
            SqlDataAdapter sda = new SqlDataAdapter(sql, conn);//创建数据适配器对象
            DataSet ds = new DataSet();//创建数据集
            sda.Fill(ds);//填充数据集
            ds.Dispose();//释放资源
            //MessageBox.Show(ds.Tables[0].Rows.Count+"");
            String[] dataResults=new String[fieldNames.Length];
            if (ds.Tables[0].Rows.Count==0)
            {
                return null;
            }
            for (int i = 0; i < fieldNames.Length;i++ )
            {
                dataResults[i] = ds.Tables[0].Rows[0][fieldNames[i]].ToString().Trim();
            }
            return dataResults;
        }

        /// <summary>
        /// 使用此方法可以得到数据集
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <returns>方法返回数据集</returns>
        public DataSet GetTable(String sql)
        {
            SqlDataAdapter sda = new SqlDataAdapter(sql, conn);//创建数据适配器对象
            DataSet ds = new DataSet();//创建数据集
            sda.Fill(ds);//填充数据集
            ds.Dispose();//释放资源
            return ds;//返回数据集
        }

        /// <summary>
        /// //绑定下拉列表
        /// </summary>
        /// <param name="strTable">数据库表名</param>
        /// <param name="cb">ComboBox对象</param>
        /// <param name="i">指定数据列索引</param>
        public void BindDropdownlist(String strSQL, ComboBox cb, int i)
        {
            conn.Open();//打开数据库连接
            SqlCommand cmd = new SqlCommand(strSQL, conn);
            SqlDataReader sdr = cmd.ExecuteReader();//得到数据读取器
            while (sdr.Read())
            {
                cb.Items.Add(sdr[i].ToString().Trim());//添加信息
            }
            conn.Close();//关闭数据库连接
        }
    }
}

下面是CmmUtils类的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace SMS.utils
{
    class CommonUtils
    {
        /// <summary>
        /// 为GetDatasFromSelectedTable方法提供sql参数
        /// </summary>
        /// <param name="fieldNames">要查询数据库表的字段名</param>
        /// <param name="tempSQL">是拼接后的数据库语句的from后面的部分</param>
        /// <returns></returns>
        public String organizeSqlStatementWithFields(String[] fieldNames, String tempSQL)
        {
            StringBuilder strSql = new StringBuilder("select ");
            for (int i = 0; i < fieldNames.Length; i++)
            {
                if (i != fieldNames.Length - 1)
                {
                    strSql.Append(fieldNames[i] + ",");
                }
                else
                {
                    strSql.Append(fieldNames[i]);
                }
            }
            strSql.Append(tempSQL);
            return strSql.ToString();
        }

        /// <summary>
        /// 获取系统当前的日期和时间
        /// </summary>
        /// <returns></returns>
        public String getSystemCurrentTime()
        {
            StringBuilder sb = new StringBuilder("");
            sb.Append(DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.DayOfWeek.ToString() + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Second.ToString());
            return sb.ToString();
        }

        //只能输入数字
        public void onlyInputDigitNumber(object sender, KeyPressEventArgs e)
        {
            if (((int)e.KeyChar < 48 || (int)e.KeyChar > 57) && (int)e.KeyChar != 8)
            {
                e.Handled = true;
            }
        }

        //只能输入数字和小数点,小数点只能一位且不能在第一位
        public void onlyInputDigitAndDotNumber(object sender, KeyPressEventArgs e,TextBox textBox)
        {
            if (e.KeyChar != 8 && e.KeyChar != 13 && e.KeyChar != 46 && !char.IsNumber(e.KeyChar))
            {
                e.Handled = true;
            }
            if (e.KeyChar == 46 && textBox.Text.Length == 0)
            {
                e.Handled = true;
                return;
            }
            int a = 0;
            try
            {
                a = textBox.Text.ToString().Trim().Split('.').Length;
            }
            catch { }
            if (e.KeyChar == 46 && a > 1)
            {
                e.Handled = true;
            }
        }

        //只能下拉选择
        public void onlyDropDownToSelect(object sender, KeyPressEventArgs e)
        {
            MessageBox.Show("请进行下拉选择而无需手动填写!", "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
            e.Handled = true;
        }

    }
}

(1)首先贴上没有解密的用户登录代码:

        //登录事件
        private void buttonLogin_Click(object sender, EventArgs e)
        {
            try
            {
                string userName = textBoxUserName.Text.Trim();
                string userPwd = textBoxPwd.Text.Trim();
                if (userName == "" || userPwd == "")
                {
                    MessageBox.Show("用户名或密码不能为空!", "友情提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }
                else
                {
                    SqlConnection conn = DBConnection.MyConnection();
                    String sql = "select * from tb_employee where loginName='"+userName+"' and loginPassword='"+userPwd+"'";
                    SqlDataReader sdr=operate.getSQLData(sql, conn);
                    sdr.Read();

                    //存在该用户名与密码
                    if (sdr.HasRows)
                    {
                        conn.Close();
                        this.Hide();

                        CommonMessage.userName = userName;
                        CommonMessage.userPassword = userPwd;

                        String[] selFieldNames = new String[]{
                            "powerName"
                        };
                        String tempSQL=" from tb_employee,tb_powerType where tb_employee.powerId=tb_powerType.powerId and tb_employee.loginName='"+userName+"'";

                        String strSql=cmmUtils.organizeSqlStatementWithFields(selFieldNames, tempSQL);
                        String[] dataResults = operate.GetDatasFromSelectedTable(strSql.ToString(), selFieldNames);

                        CommonMessage.userPower = dataResults[0];

                        Console.Write(userName + "--" + userPwd + "--" + CommonMessage.userPower);

                        frmMain fMain = new frmMain();
                        fMain.ShowDialog();
                    }
                    else
                    {
                        //清空文本内容
                        textBoxUserName.Text = "";
                        textBoxPwd.Text = "";
                        MessageBox.Show("用户名或密码错误!", "友情提示", MessageBoxButtons.OK, MessageBoxIcon.Information);

                        frmLogin_Activated(sender, e);
                    }
                }
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message + "\n请与管理员联系!", "错误信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }

        }

(2)接着贴上有MD5加解密的用户登录的代码:

        //加密解密工具
        MD5EncryptAndDecrypt md5 = new MD5EncryptAndDecrypt();

        //登录事件
        private void buttonLogin_Click(object sender, EventArgs e)
        {
            try
            {
                string userName = textBoxUserName.Text.Trim();
                string userPwd = textBoxPwd.Text.Trim();
                if (userName == "" || userPwd == "")
                {
                    MessageBox.Show("用户名或密码不能为空!", "友情提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }
                else
                {

                    String[] loginFieldNames = new String[]{
                            "loginPassword","loginKey"
                        };
                    String tempSQL = " from tb_employee where loginName='" + userName + "'";
                    String strSql = cmmUtils.organizeSqlStatementWithFields(loginFieldNames, tempSQL);
                    Console.WriteLine(strSql);
                    String[] dataResults = operate.GetDatasFromSelectedTable(strSql.ToString(), loginFieldNames);
                    if (dataResults==null)
                    {
                        MessageBox.Show("该用户名不存在!", "友情提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                    else
                    {
                        //Console.WriteLine("密码密文: " + dataResults[0] + "\n密码密钥: " + dataResults[1]);
                        String loginPasswordEncrypt = dataResults[0];
                        String loginKeyTemp = dataResults[1];
                        String loginKeyReal = loginKeyTemp.Substring(0, loginKeyTemp.IndexOf(CommonMessage.lastKeyStr));
                        //MessageBox.Show(loginKeyReal);
                        String loginPasswordDecrypt = md5.MD5Decrypt(loginPasswordEncrypt, loginKeyReal);
                        if (!userPwd.Equals(loginPasswordDecrypt))
                        {
                            MessageBox.Show("用户密码错误!", "友情提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        }
                        else
                        {
                            //MessageBox.Show("登陆成功!", "友情提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            this.Hide();

                            CommonMessage.userName = userName;
                            CommonMessage.userPassword = userPwd;

                            String[] selFieldNames = new String[]{
                                "powerName"
                        };
                            String tempPowerSQL = " from tb_employee,tb_powerType where tb_employee.powerId=tb_powerType.powerId and tb_employee.loginName='" + userName + "'";

                            String strPowerSql = cmmUtils.organizeSqlStatementWithFields(selFieldNames, tempPowerSQL);
                            String[] dataPowerResults = operate.GetDatasFromSelectedTable(strPowerSql.ToString(), selFieldNames);

                            CommonMessage.userPower = dataPowerResults[0];

                            Console.Write(userName + "--" + userPwd + "--" + CommonMessage.userPower);

                            frmMain fMain = new frmMain();
                            fMain.ShowDialog();
                        }
                    }
                }
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message + "\n请与管理员联系!", "错误信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }

        }

其中,MD5EncryptAndDecrypt 功能包括:产生密钥,加密密码明文为密码密文,解密密码密文为密码明文。其源代码可以参考我的下一篇博客!

在这里需要说明的,本系统虽然是MD5,但还在密钥Key中还拼接上了一段自定义的字符串,在本系统中为“520lancy”,所以在解密的时候需要去掉这段自定义的字符串,截断的代码为上述代码的String
loginKeyReal = loginKeyTemp.Substring(0, loginKeyTemp.IndexOf(CommonMessage.lastKeyStr)); 其中CommonMessage.lastKeyStr即为自定义的那段字符串。

下面是效果!登录界面和登录过程的处理以及成功后的主界面!

下文将介绍MD5加密的简要原理以及我采用C#实现并将其应用在本系统的源代码!

时间: 2024-10-12 05:42:21

C#桌面办公应用-工资管理系统系列五的相关文章

C#桌面办公应用-工资管理系统系列七

接前文工资管理系统系列六,本文将介绍C# winform应用程序中的查询模块功能.其中,就包括了综合.模糊查询以及分页查询:值得说明的是,综合查询,其实就是多个条件组合起来的组合查询啦,只不过我换了个不严谨的称呼罢了!组合多个条件并采用模糊查询的方法实现查询功能:而对于分页查询,我想,参与过企业的项目或者是一些实用的项目的博友而言,都不会陌生,就像我一样,我是搞java开发的,公司用的数据库是mysql,所以对于项目中前端页面使用的分页查询我是再熟悉不过了,这个等改天有空我也写篇博文介绍介绍我们

C#桌面办公应用-工资管理系统系列九

今天介绍介绍一下我自主开发的工资管理系统中的"汇总查询打印"模块,改小模块具有以下的功能:可以汇总统计员工的工资发放明细信息,可以查询指定的某个部门下的某些员工的工资发放明细信息,并打印成报表!开发的流程为:建立一个用于汇总的数据库表.制作报表.汇总.查询打印!我自己觉得这个功能是相当有趣的,而且在实际的企业中也具有一定的适用性,可以根据企业的需要自主定制相应的报表!若有博友想获取该系统的源码,或者想作为自己的毕业设计的系统实现,可以加我QQ:1974544863进行交流! 下面以&q

用Qt写软件系列五:一个安全防护软件的制作(1)

引言 又有许久没有更新了.Qt,我心爱的Qt,为了找工作不得不抛弃一段时间,业余时间来学一学了.本来计划要写一系列关于Qt组件美化的博文,但是写了几篇之后就没坚持下去了.技术上倒是问题不大,主要是时间不够充裕.这段时间写几篇关于界面整体设计的博文,从最基础的界面元素开始,到最后构建一个页面元素丰富的桌面应用程序.Trojan Assessment Platform是一个原型设计项目,只是实现了有限的一部分功能.远远还称不上是一个评估平台.这里仅仅侧重于用Qt做界面的实现. 界面预览 首先还是看看

权限管理系统系列之序言

权限管理系统我相信每个系统都会需要,所以设计一个好的权限管理系统会在系统开发中起到至关重要的作用,节省人力成本和资源,可以不用每次都为权限设计煞费心机.可能每个公司对权限的设计大体相同,略有不同,但是都会不离其中.用户.部门.角色.权限之间的关系作调整.本人现在职于某公司,专门做权限的二次开发,对权限這一块的功能现在略知一二,现想分享出来跟各位园友一同学习交流,共同进步.将会在日后推出如下系列的文章,共同学习权限设计,希各位园友支持和拍砖. 一.权限管理系统系列之WCF通信 主要是介绍整个权限管

BOS物流管理系统-第五天

BOS物流管理系统-第五天-定区管理-WebServcie远程调用 主要内容: 分区设置-导出(分区条件查询后的结果导出为Excel-POI生成Excel和文件下载) 定区管理---定区添加(定区关联分区和取派员,easyUi相关的注意的地方) 定区管理-分页条件查询(复习-form表单json转换,Spring Data Specification ) 定区管理-定区关联客户(模拟系统间:bos和crm(Customer Relational Managerment)的远程调用-WebServ

Apache Kafka系列(五) Kafka Connect及FileConnector示例

Apache Kafka系列(一) 起步 Apache Kafka系列(二) 命令行工具(CLI) Apache Kafka系列(三) Java API使用 Apache Kafka系列(四) 多线程Consumer方案 Apache Kafka系列(五) Kafka Connect及FileConnector示例 一. Kafka Connect简介 Kafka是一个使用越来越广的消息系统,尤其是在大数据开发中(实时数据处理和分析).为何集成其他系统和解耦应用,经常使用Producer来发送消

RX系列五 | Schedulers线程控制

RX系列五 | Schedulers线程控制 在我们上一篇文章中的,我们的小例子里有这么一段代码 //网络访问 .observeOn(Schedulers.io()) 事实上,我们在使用网络操作的时候,便可以控制其运行在哪个线程中,而Schedulers类,有四个方法,分别是 Schedulers.immediate(); Schedulers.newthread(); Schedulers.io(); Schedulers.computation(); 以及RxAndroid中的Android

MyBatis 系列五 之 关联映射

MyBatis 系列五 之 关联映射 一对多的关联映射 一对多关联查询多表数据 1.1在MyBatis映射文件中做如下配置 <!--一对多单向的连接两表的查询--> <resultMap type="Dept" id="deptMapper"> <id property="deptNo" column="deptNo"/> <result property="deptName

职工工资管理系统 --C语言

#include<stdio.h> #include<string.h> #include<stdlib.h> #define NUM 1000 void enter(); void search_num(); void dele_num(); void modi_num(); void browse(); void count(); void load(); void add(); void menu(); int n; //员工的总数 struct emploee