用户登录案例 展示 三层架构

一、先做准备工作
App.config 【UI层】
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <connectionStrings>
    <add name="sqlCon" connectionString="Data Source=.;DataBase=db_NetShop;uid=sa;pwd=sasa"/>
  </connectionStrings>
</configuration>
 
SqlHelper.cs 【DAL层】
namespace SanCeng.DAL
{
    public static class SqlHelper
    {
        //获取配置文件中的连接字符串
        private static readonly string constr = ConfigurationManager.ConnectionStrings["sqlCon"].ConnectionString;
 
        /// <summary>
        /// 执行insert、delete、update的方法
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="pms"></param>
        /// <returns></returns>
        public static int ExecuteNonQuery(string sql, params SqlParameter[] pms)
        {
            using (SqlConnection con = new SqlConnection(constr))
            {
                using (SqlCommand cmd = new SqlCommand(sql, con))
                {
                    //如果pms为null,则直接调用cmd.Parameters.AddRange(pms)会报错。
                    if (pms != null)
                    {
                        cmd.Parameters.AddRange(pms);
                    }
                    con.Open();
                    return cmd.ExecuteNonQuery();
                }
 
            }
        }
 
        /// <summary>
        /// 执行sql语句,返回单个值。
        /// </summary>
        /// <param name="sql">要执行的sql语句</param>
        /// <param name="pms">sql语句中的参数</param>
        /// <returns></returns>
        public static object ExecuteScalar(string sql, params SqlParameter[] pms)
        {
            using (SqlConnection con = new SqlConnection(constr))
            {
                using (SqlCommand cmd = new SqlCommand(sql, con))
                {
                    //如果pms为null,则直接调用cmd.Parameters.AddRange(pms)会报错。
                    if (pms != null)
                    {
                        cmd.Parameters.AddRange(pms);
                    }
                    con.Open();
                    return cmd.ExecuteScalar();
                }
 
            }
        }
 
        /// <summary>
        /// 执行sql语句返回一个DataReader
        /// 当返回DataReader的时候,注意:
        /// 1.Connection不能关闭
        /// 2.DataReader不能关闭
        /// 3.command对象执行ExecuteReader()的时候需要传递一个参数CommandBehavior.CloseConnection
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="pms"></param>
        /// <returns></returns>
        public static SqlDataReader ExecuteReader(string sql, params SqlParameter[] pms)
        {
            SqlConnection con = new SqlConnection(constr);
            using (SqlCommand cmd = new SqlCommand(sql, con))
            {
                if (pms != null)
                {
                    cmd.Parameters.AddRange(pms);
                }
                con.Open();
                //当调用ExecuteReader()方法的时候,如果传递一个CommandBehavior.CloseConnection参数,则表示将来当用户关闭reader的时候,系统会自动将Connection也关闭掉。
                SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                return reader;
            }
 
        }
 
        /// <summary>
        /// 封装一个返回DataTable的方法。
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="pms"></param>
        /// <returns></returns>
        public static DataTable ExecuteDataTable(string sql, params SqlParameter[] pms)
        {
            SqlDataAdapter sqlAdapter = new SqlDataAdapter(sql, constr);
            if (pms != null)
            {
                sqlAdapter.SelectCommand.Parameters.AddRange(pms);
            }
            DataTable dt = new DataTable();
            sqlAdapter.Fill(dt);
            return dt;
        }
    }
}
 
二、画窗体,写DAL层 因为DAL层需要返回多个数据,所以要先写一个实体类
 
 
Tb_AdminEntity.cs 【Model】
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace SanCeng.Model
{
    public class Tb_AdminEntity
    {
        public Int64 AdminId { getset; }
        public string Admin { getset; }
        public string Password { getset; }
        public int? Age { getset; }
        public string RealName { getset; }
    }
}
说明:查看数据库表设计查看该字段是否为空,若为空 int ,datetime数据类型需要加?
 
Tb_AdminDal.cs 【DAL层】
using SanCeng.Model;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace SanCeng.DAL
{
    public class Tb_AdminDal
    {
        public Tb_AdminEntity getUserInfoByLoginName(string loginName)
        {
            Tb_AdminEntity adminEntity = new Tb_AdminEntity();
            string sql = "select * from tb_Admin where Admin=@admin";
            SqlDataReader reader=SqlHelper.ExecuteReader(sql,new SqlParameter("@admin",loginName));
            if (reader.HasRows)
            {
                if (reader.Read())
                {
                    adminEntity.AdminId = reader.GetInt64(0);
                    adminEntity.Admin = reader.GetString(1);
                    adminEntity.Password = reader.GetString(2);
                    adminEntity.Age = reader.IsDBNull(3) ? null : (int?)reader.GetInt32(3);
                    adminEntity.RealName = reader.IsDBNull(4) ? null : reader.GetString(4);
                }
            }
            else
            {
                adminEntity = null;
            }
            return adminEntity;
        }
    }
}
说明:注意可空字段的判断
 
三、写业务层 和 业务层的公共类 和 枚举状态类
 
CommonHelper.cs 【业务层】
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
 
namespace SanCeng.BLL
{
    public static class CommonHelper
    {
        public static string md5Create(string str)
        {
            byte[] strByte = System.Text.Encoding.UTF8.GetBytes(str);
            MD5 md5 = MD5.Create();
            byte[] md5Byte = md5.ComputeHash(strByte);
            md5.Clear();
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < md5Byte.Length; i++)
            {
                sb.Append(md5Byte[i].ToString("x2"));
            }
            return sb.ToString();
 
        }
    }
}
 
说明:公共类主要是静态类 方法是静态方法
 
LoginResult.cs 【业务层】
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace SanCeng.BLL
{
 
    public enum LoginStatus
    {
        DataNullValue,
        NoLoginName,
        PasswordError,
        Success
    }
 
}
说明:枚举不要写在类外面
 
Tb_AdminBll.cs 【业务层】
using SanCeng.DAL;
using SanCeng.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace SanCeng.BLL
{
    public class Tb_AdminBll
    {
        public LoginStatus CheckLogin(string loginName, string password, out Int64 adminId,out string realName)
        {
            //总结:1.实体类不必new 直接接收
            //2.不要else情况绑定是成功,因为有许多未知情况不知道
            //3.逻辑业务层不要往静态类中(GlobalHelper)存数据,那个在UI层存
            //4.MD5处理密码也在业务层处理
            //5.UI层需要数据的话,可以在业务逻辑层用输出参数实现
            //6.枚举不要写类里面 直接写命名空间外面
 
            Tb_AdminDal adminDal = new Tb_AdminDal();
            Tb_AdminEntity adminEntity = adminDal.getUserInfoByLoginName(loginName);
            adminId = -1;
            realName = null;
            if (string.IsNullOrEmpty(loginName) || string.IsNullOrEmpty(password))
            {
                return LoginStatus.DataNullValue;
            }
            else if (adminEntity==null//用户名不存在
            {
                return LoginStatus.NoLoginName;
            }
            else if (adminEntity.Password==CommonHelper.md5Create(password))//登录成功
            {
                adminId = adminEntity.AdminId;
                realName = adminEntity.RealName;
                return LoginStatus.Success;
            }
            else //密码错误
            {
                return LoginStatus.PasswordError;
            }
        }
    }
}
 
四、写UI层 为了存储窗体间共享数据 还要写一个GlobalHleper.cs
 
GlobalHleper.cs 【UI层】
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace SanCeng
{
    public static class GlobalHelper
    {
        public static Int64 AdminId;
        public static string RealName;
    }
}
 
frmLogin.cs 【UI层】
using SanCeng.BLL;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace SanCeng
{
    public partial class frmLogin : Form
    {
        public frmLogin()
        {
            InitializeComponent();
        }
 
        private void btnLogin_Click(object sender, EventArgs e)
        {
            string loginName = txtUserName.Text.Trim();
            string password = txtPassword.Text;
            Int64 adminId;
            string realName;
            LoginStatus result = new Tb_AdminBll().CheckLogin(loginName, password,out adminId,out realName);
            switch (result)
            {
                case LoginStatus.DataNullValue:
                    MessageBox.Show("用户名、密码不能为空");
                    break;
                case LoginStatus.NoLoginName:
                    MessageBox.Show("用户名不存在");
                    break;
                case LoginStatus.PasswordError:
                    MessageBox.Show("密码错误");
                    break;
                case LoginStatus.Success:
                    GlobalHelper.AdminId = adminId;
                    GlobalHelper.RealName=realName;
                    MessageBox.Show("登录成功");
                    break;
            }       
        }
    }
}
 
完成!!!!!!!
原文地址:https://www.cnblogs.com/jiayue360/p/3166979.html