第一次敲机房入门用了不到三天,敲机房重构入门用了一个礼拜,自己的进步在哪呢?
登录界面:
登录的时候需要判断两张表,一张是User表,里面放的是管理员和操作员,一张是Student表,里面放的是一般用户。由于自己懒外加笨,所以就设置了两个登录界面。一般用户登录后是自己一个单独的窗体,只有自己的功能,操作员和管理员登录也只具备自己该有的功能,除了查询外不具有一般用户的功能。如下是初始模板,比较丑,后期在进行完善:
UI层(只以管理员/操作员为例,一般用户同理)
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;
using Entity;
namespace UI
{
public partial class FrmLogin : Form
{
public FrmLogin()
{
InitializeComponent();
}
public static string id;//方便后面的修改密码的窗体使用。
public static string stucardno;
//管理员或者操作员登录
private void btLogin_Click(object sender, EventArgs e)
{
if (txtUserName.Text.Trim() == "")
{
MessageBox.Show("用户ID不能为空,请您输入用户名");
return;//不继续往下走
}
if (txtPassword.Text == "")
{
MessageBox.Show("密码不能为空,请您输入密码");
return;
}
Entity.User_Info user = new Entity.User_Info();//实例化实体层
user.userID = txtUserName.Text.Trim();//将UI层的用户名传给相应的实体层
user.PWD = txtPassword.Text.Trim();//将UI层的密码也传给相应的实体层
Boolean flag = false;//bool就像是小名,boolean是大名,其实意思都一样。
Facade.LoginFacade fact = new Facade.LoginFacade();//实例化一个外观层
flag = fact.SelectUser(user);//调用外观层的方法
if (flag != false)
{
this.Hide();
id = txtUserName.Text.Trim();
MessageBox.Show("登录成功");
this.DialogResult = DialogResult.OK;
}
else
{
MessageBox.Show("密码或者用户名错误");
return;
}
}
private void btCancel_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
Facade层,门面层,举个例子:它就像进医院的门口接待员一样,客户端不需要直接访问医院内部复杂的结构,只需要和接待员打交道就好,降低了UI层和BLL层之间的耦合度。(来源于百度例子)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
namespace Facade
{
public class LoginFacade
{
public Boolean SelectUser(Entity.User_Info user)
{
bool flag;
BLL.LoginManager man = new BLL.LoginManager(); //实例化B层
flag = man.UserBLL(user);//调用B层,将查询的结果给flag
return flag;//返回U层
}
}
}
BLL层(Business Logic Layer):业务逻辑层。进行逻辑判断和存放功能函数,连接DAL层,但是为了降低耦合度,需要Factory层和IDAL层的帮助。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
namespace BLL
{
public class LoginManager
{
public bool UserBLL(Entity.User_Info userInfo)
{
Factory.LoginFacory Fact = new Factory.LoginFacory();//实例化一个工厂
IDAL.ILoginIDAL idal = Fact.CreateUser();//调取工厂中的方法,利用反射机制实例化DAL层。这里本来应该是DAL,换成了它的父类,IDAL,依赖于抽象。
DataTable table = idal.SelectUser(userInfo);//调取DAL层的方法,DAL层中的SelectUser继承了抽象工厂的方法。
bool flag;
if (table.Rows.Count == 0)//如果新的更新后的表中是空的,则····
{
flag = false;
}
else
{
flag = true;
}
return flag;//返回外观层
}
}
}
Factory层,Factory层只是实现接口而已,作为BLL和DAL之间的桥梁,说白了就是连接DAL层。工厂工厂,顾名思义,就是造东西的工厂,但是造的是接口。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;
using System.Configuration;
using System.IO;
namespace Factory//灵活的配制文件;面向的是抽象,而不是细节。
{
public class LoginFacory
{
//读取配制文件
string StrDB =ConfigurationManager.AppSettings["DB"];//从confilg配制文件中获取key值为“DB”的value,就是配制文件里的DAL。
public IDAL.ILoginIDAL CreateUser()
{
string ClassName = StrDB + "." + "LoginDAL";//DAL.LoginDAL;
return (IDAL.ILoginIDAL)Assembly.Load(StrDB).CreateInstance(ClassName);
//对上面的解释:Assembly.Load()在给定程序集的情况下,加载该程序集+程序集名称,CreateInstance+当前命名空间名称。返回到DAL.LoginDAL。(反射)
}
}
}
IDAL层,提供接口,DAL需要继承相应的IDLA层。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
namespace IDAL
{
public interface ILoginIDAL
{
DataTable SelectUser(Entity.User_Info userInfo);//放置接口函数,判断要登录的用户是否在数据表中存在。
}
}
DAL层(Data Access Layer):数据访问层,访问数据库并返回一个表的层。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
namespace DAL
{
public class LoginDAL : IDAL.ILoginIDAL//继承接口
{
//从User表中查询信息
public DataTable SelectUser(Entity.User_Info userInfo)
{
SQLHelper sqlHelper = new SQLHelper();//实例化一个数据查询的对象,此代码的作用是连接数据库。
SqlParameter[] sqlParams = { new SqlParameter("@userID", userInfo.userID),
new SqlParameter("@password", userInfo.PWD) };//SqlParameter是范围的意思,个人理解这行代码是规定新的东西。就是将PWD换成@password。
string sql = @"SELECT * FROM User_Info WHERE userID=@userID and PWD=@password";//查询数据库
DataTable table = sqlHelper.ExecuteQuery1(sql, sqlParams, CommandType.Text);/*SQLHelper查询,里面的参数依次是数据库查询、
设置新参数、默认的枚举类型。返回的table是一个新的数据表*/
return table;//新的更新后的表
}
}
}
SQLHelper层,放在DAL层里面,起到打开数据库和存储一些函数的作用。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
namespace DAL
{
public class SQLHelper
{
//sqlHelper的封装在DAL层,目的连接数据库,实现对数据库的增删改查的操作,所以sqlHelper不可以当做一层来看待,存在的目的服务于DAL层。定义数据库连接操作,指定在数据库上操作的类型、定义数据库读取操作。
private SqlConnection conn = null;
private SqlCommand cmd = null;
private SqlDataReader sdr = null;
public SQLHelper()
{
//ConfigurationManager表示读配置文件
string connStr = ConfigurationManager.AppSettings["connStr"];//读取数据库,ConnStr是从配置文件里面连接数据库的关键字。
conn = new SqlConnection(connStr);//连接数据库
}
private SqlConnection GetConn()
{
if (conn.State == ConnectionState.Closed)//表示当前的连接如果是关闭状态,则打开
{
conn.Open();
}
return conn;
}
//执行不带参数的增删改SQL语句或者存储过程
public int ExecuteNonQuery(string cmdText, CommandType ct)
{
int res;
try
{
cmd = new SqlCommand(cmdText, GetConn());
cmd.CommandType = ct;
res = cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (conn.State == ConnectionState.Closed)
{
conn.Close();
}
}
return res;
}
//执行带参数的增删改SQL语句或者存储过程
public int ExecuteQuery(string cmdText, SqlParameter[] paras, CommandType ct)
{
int res;
using (cmd = new SqlCommand(cmdText, GetConn()))
{
cmd.CommandType = ct;
cmd.Parameters.AddRange(paras);
res = cmd.ExecuteNonQuery();//用来更新数据
}
return res;
}
//执行不带参数的查询SQL语句或存储过程
public DataTable ExecuteNonQuery1(string cmdText, CommandType ct)
{
DataTable dt = new DataTable();
cmd = new SqlCommand(cmdText, GetConn());
cmd.CommandType = ct;
using (sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
dt.Load(sdr);
}
return dt;
}
//执行带参数的查询SQL语句或存储过程
public DataTable ExecuteQuery1(string cmdText, SqlParameter[] paras, CommandType ct)
{
DataTable dt = new DataTable();
cmd = new SqlCommand(cmdText, GetConn());
cmd.CommandType = ct;
cmd.Parameters.AddRange(paras);
using (sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
dt.Load(sdr);
}
return dt;
}
}
}
Entity层,实体层,存放数据库中的内容,使操作更方便。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Entity//把数据库里面的字段拿出来使用,比较方便。
{
public class User_Info
{
public string userID { get; set; }
public string UserName { get; set; }
public string PWD { get; set; }
public string Level { get; set; }
}
}