一、先做准备工作
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 { get; set; }
public string Admin { get; set; }
public string Password { get; set; }
public int? Age { get; set; }
public string RealName { get; set; }
}
}说明:查看数据库表设计查看该字段是否为空,若为空 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;
}
}
}
}
完成!!!!!!!