• (八)Asp.NET中三层架构的应用


    一、 什么是三层架构?

    生活中的三层

    初始结构:

    在现实生活中,如果老王开了一家饭店,前期顾客比较少,自己来招待客人、在后厨炒菜、每天去市场采购食材。但是随着顾客量的增加,饭店的生意越来越兴隆,自己一个人单干忙的不可开交。就好比我们的软件系统一样,我们的用户是浏览我们的网页的,主要的功能是体现在UI层面,用户和系统产生交互,UI层面需要接收用户的数据信息、处理逻辑、访问数据库等等。那么如果我们的业务足够复杂和庞大,我们把所有的代码都集中在一个地方,那么对于项目后期的扩展或者维护会变得异常困难。

     

     改变成三层:

    为了缓解人手不足的局面,老王便招来了若干个服务员、厨师和采购员,他们各司其职,每个人都有自己的专职工作,这样合理的分功让饭店的日常经营变得十分顺利。那么对于我们的软件开发也应该是同样的道理,我们应该按照不同的处理的业务模块来进行合理的划分,一般我们会把系统架构分为UI表现层、业务逻辑层、数据访问层这样的三层,这就是经典的三层架构。

     

    使用三层架构的目的:

    目的:解耦

    服务员(UI层)请假——另找服务员

    厨师(BLL层)辞职——招聘另一个厨师

    采购员(DAL层)辞职——招聘另一个采购员

    顾客反映:

    你们店服务态度不好——服务员的问题。开除服务员

    你们店菜里有虫子——厨师的问题。换厨师

    UI(表现层):主要是指与用户交互的界面。用于接收用户输入的数据和显示处理后用户需要的数据。

    BLL(业务逻辑层):UI层和DAL层之间的桥梁。实现业务逻辑。业务逻辑具体包含:验证、计算、业务规则等等。

    DAL(数据访问层):与数据库打交道。主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。(当然这些操作都是基于UI层的。用户的需求反映给界面(UI),UI反映给BLLBLL反映给DALDAL进行数据的操作,操作后再一一返回,直到将用户所需数据反馈给用户)

    那么在三层架构中各层之间为了能够处理一个统一的功能,相互直接是如何依赖的呢?

    我们从UI表现层出发依次从上往下来看,表现层需要调用业务逻辑层,业务逻辑层需要调用数据访问层,而数据的在每个层的传输需要通过Model实体层。

    那么引入了三层架构之后我们的请求流程变为了用户在UI表现层提交数据,调用业务逻辑层中的方法来处理当前功能的业务逻辑,如果要和数据库做交互,那么需要在业务逻辑层中调用数据访问层来对数据进行操作,数据访问层最终会有一个处理的结果,有可能是操作成功失败,也有可能是读取数据,数据访问将这个结果返回给业务逻辑层,业务逻辑层获取这个结果之后将它返回给UI表现层,这样三层架构的请求流程就结束了。

    接下来,我们来演示三层架构的实现具体步骤:

    二、 三层架构综合应用

    1、在项目中添加类库MODEL

       Model层中添加项目所需的实体类:如:Product类和ProductCategory类

     /// <summary>
        /// 产品
        /// </summary>
        public class Product
        {
            /// <summary>
            /// 主键Id
            /// </summary>
            public int Id { get; set; }
    
            /// <summary>
            /// 产品名称
            /// </summary>
            public string ProductName { get; set; }
    
            /// <summary>
            /// 市场价
            /// </summary>
            public decimal MarketPrice { get; set; }
    
            /// <summary>
            /// 售价
            /// </summary>
            public decimal SellingPrice { get; set; }
    
            /// <summary>
            /// 类别Id
            /// </summary>
            public int CategoryId { get; set; }
    
            /// <summary>
            /// 简介
            /// </summary>
            public string Introduction { get; set; }
    
            /// <summary>
            /// 是否上架
            /// </summary>
            public bool IsOnSale { get; set; }
    
            /// <summary>
            /// 添加时间
            /// </summary>
            public DateTime AddTime { get; set; }
     /// <summary>
        /// 产品类别
        /// </summary>
        public class ProductCategory
        {
            /// <summary>
            /// 主键Id
            /// </summary>
            public int Id { get; set; }
    
            /// <summary>
            /// 名称
            /// </summary>
            public string Name { get; set; }
        }

    2、在项目中添加类库DAL

      DAL中添加数据访问助手类:DBHelper类

    public class DBHelper
        {
            //1.声明一个数据库连接字符串
    
            private static readonly string connStr = ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString;
    
            /// <summary>
            /// 执行增删改的方法,返回受影响的行数
            /// </summary>
            /// <param name="sql"></param>
            /// <param name="pams"></param>
            /// <returns></returns>
            public static int ExecuteNonQuery(string sql, params SqlParameter[] pams)
            {
                //1.声明数据库连接
    
                using (SqlConnection conn = new SqlConnection(connStr))
                {
                    //2.声明命令
                    using (SqlCommand cmd = new SqlCommand(sql, conn))
                    {
                        //添加参数
                        if (pams != null && pams.Length > 0)
                        {
                            cmd.Parameters.AddRange(pams);
                        }
                        //3.打开数据库连接
                        if (conn.State == ConnectionState.Closed)
                        {
                            conn.Open();
                        }
                        //4.执行命令
                        return cmd.ExecuteNonQuery();
                    }
                }
            }
    
    
            /// <summary>
            /// 执行查询,返回首行首列
            /// </summary>
            /// <param name="sql"></param>
            /// <param name="pams"></param>
            /// <returns></returns>
            public static object ExecuteScalar(string sql, params SqlParameter[] pams)
            {
                //1.声明数据库连接
                using (SqlConnection conn = new SqlConnection(connStr))
                {
                    //2.声明命令
                    using (SqlCommand cmd = new SqlCommand(sql, conn))
                    {
                        //添加参数
                        if (pams != null && pams.Length > 0)
                        {
                            cmd.Parameters.AddRange(pams);
                        }
                        //3.打开数据库连接
                        if (conn.State == ConnectionState.Closed)
                        {
                            conn.Open();
                        }
                        //4.执行命令
                        return cmd.ExecuteScalar();
                    }
                }
            }
    
    
            /// <summary>
            /// 执行查询,返回SqlDataReader对象
            /// </summary>
            /// <param name="sql"></param>
            /// <param name="pams"></param>
            /// <returns></returns>
            public static SqlDataReader ExecuteReader(string sql, params SqlParameter[] pams)
            {
                //1.声明数据库连接
                SqlConnection conn = new SqlConnection(connStr);
                //2.声明命令
                using (SqlCommand cmd = new SqlCommand(sql, conn))
                {
                    //添加参数
                    if (pams != null && pams.Length > 0)
                    {
                        cmd.Parameters.AddRange(pams);
                    }
                    //3.打开数据库连接
                    if (conn.State == ConnectionState.Closed)
                    {
                        conn.Open();
                    }
    
                    //4.执行命令
                    return cmd.ExecuteReader(CommandBehavior.CloseConnection);
                }
    
            }
    
            /// <summary>
            /// 执行查询,返回DataTable对象
            /// </summary>
            /// <param name="sql"></param>
            /// <param name="pams"></param>
            /// <returns></returns>
            public static DataTable ExecuteTable(string sql, params SqlParameter[] pams)
            {
                //1.声明SqlDataAdapter对象
                using (SqlDataAdapter sda = new SqlDataAdapter(sql, connStr))
                {
                    //2.添加参数
                    if (pams != null && pams.Length > 0)
                    {
                        sda.SelectCommand.Parameters.AddRange(pams);
                    }
                    DataTable dt = new DataTable();
                    sda.Fill(dt);
                    return dt;
                }
    
            }
    
            /// <summary>
            /// 执行查询,返回SqlDataReader对象(存储过程)
            /// </summary>
            /// <param name="sql"></param>
            /// <param name="pams"></param>
            /// <returns></returns>
            public static SqlDataReader ExecuteReaderProc(string procName, params SqlParameter[] pams)
            {
                //1.声明数据库连接
                SqlConnection conn = new SqlConnection(connStr);
                //2.声明命令
                using (SqlCommand cmd = new SqlCommand(procName, conn))
                {
                    //指定查询命令的存储过程类型
                    cmd.CommandType = CommandType.StoredProcedure;
                    //添加参数
                    if (pams != null && pams.Length > 0)
                    {
                        cmd.Parameters.AddRange(pams);
                    }
                    //3.打开数据库连接
                    if (conn.State == ConnectionState.Closed)
                    {
                        conn.Open();
                    }
    
                    //4.执行命令
                    return cmd.ExecuteReader(CommandBehavior.CloseConnection);
                }
    
            }
    
            /// <summary>
            /// 执行增删改的方法,返回受影响的行数(存储过程版)
            /// </summary>
            /// <param name="sql"></param>
            /// <param name="pams"></param>
            /// <returns></returns>
            public static int ExecuteNonQueryProc(string procName, params SqlParameter[] pams)
            {
                //1.声明数据库连接
    
                using (SqlConnection conn = new SqlConnection(connStr))
                {
                    //2.声明命令
                    using (SqlCommand cmd = new SqlCommand(procName, conn))
                    {
                        cmd.CommandType = CommandType.StoredProcedure;
    
                        //添加参数
                        if (pams != null && pams.Length > 0)
                        {
                            cmd.Parameters.AddRange(pams);
                        }
                        //3.打开数据库连接
                        if (conn.State == ConnectionState.Closed)
                        {
                            conn.Open();
                        }
                        //4.执行命令
                        return cmd.ExecuteNonQuery();
                    }
                }
            }
        }
    DBHelper

      DAL中添加ProductDAL类和ProductCategoryDAL,并在该类中添加实现增删改查的方法:

    ProductCategoryDAL中获取类别信息:

    /// <summary>
            /// 获取产品类别
            /// </summary>
            /// <returns></returns>
            public DataTable GetCategoryList()
            {
                //声明SQL语句
                string sql = "select * from ProductCategory";
                return DbHelper.ExecuteTable(sql);
            }

    ProductDAL中获取产品信息:

    /// <summary>
            /// 查询产品列表
            /// </summary>
            /// <param name="productName"></param>
            /// <param name="categoryId"></param>
            /// <returns></returns>
            public DataTable GetProductList(string productName,int categoryId)
            {
                //定义SQL语句
                string sql = "select p.Id,p.ProductName,p.MarketPrice,p.SellingPrice,pc.Name,p.IsOnSale,p.AddTime from Product as p left join ProductCategory as pc on p.CategoryId=pc.Id";
                List<string> listWhere = new List<string>();
                List<SqlParameter> listPams = new List<SqlParameter>();
    
                //多条件判断
                if (!string.IsNullOrWhiteSpace(productName))
                {
                    listWhere.Add("p.ProductName like @ProductName");
                    listPams.Add(new SqlParameter("@ProductName", $"%{productName}%"));
                }
                if (categoryId > 0)
                {
                    listWhere.Add("p.CategoryId = @CategoryId");
                    listPams.Add(new SqlParameter("@CategoryId", categoryId));
                }
    
                if (listWhere.Count > 0)
                {
                    sql += " where " + string.Join(" and ", listWhere.ToArray());
                }
    
                return DbHelper.ExecuteTable(sql, listPams.ToArray());
            }
    查询产品列表
     /// <summary>
            /// 根据Id获取产品
            /// </summary>
            /// <param name="id"></param>
            /// <returns></returns>
            public Product GetProductById(int id)
            {
                string sql = "select * from Product where Id=@Id";
                SqlParameter[] pams = {
                    new SqlParameter("@Id",id)
                };
                SqlDataReader reader = DbHelper.ExecuteReader(sql, pams);
                if(reader.HasRows)
                {
                    if(reader.Read())
                    {
                        Product model = new Product() {
                            AddTime=Convert.ToDateTime(reader["AddTime"]),
                            CategoryId=Convert.ToInt32(reader["CategoryId"]),
                            Id=Convert.ToInt32(reader["Id"]),
                            Introduction=reader["Introduction"].ToString(),
                            IsOnSale=Convert.ToBoolean(reader["IsOnSale"]),
                            MarketPrice=Convert.ToDecimal(reader["MarketPrice"]),
                            ProductName=reader["ProductName"].ToString(),
                            SellingPrice=Convert.ToDecimal(reader["SellingPrice"])
                        };
                        return model;
                    }
                }
                return null;
            }
    根据Id获取产品
     /// <summary>
            /// 更新产品
            /// </summary>
            /// <param name="model"></param>
            /// <returns></returns>
            public bool Update(Product model)
            {
                string sql = "update Product set ProductName=@ProductName,MarketPrice=@MarketPrice,SellingPrice=@SellingPrice,CategoryId=@CategoryId, Introduction=@Introduction,IsOnSale=@IsOnSale where Id=@Id";
                SqlParameter[] pams = {
                    new SqlParameter("@ProductName",model.ProductName),
                    new SqlParameter("@MarketPrice",model.MarketPrice),
                    new SqlParameter("@SellingPrice",model.SellingPrice),
                    new SqlParameter("@CategoryId",model.CategoryId),
                    new SqlParameter("@Introduction",model.Introduction),
                    new SqlParameter("@IsOnSale",model.IsOnSale),
                    new SqlParameter("@Id",model.Id)
                };
    
                return DbHelper.ExecuteNonQuery(sql, pams) > 0;
            }
    更新产品
    /// <summary>
            /// 删除产品
            /// </summary>
            /// <param name="id"></param>
            /// <returns></returns>
            public bool Delete(int id)
            {
                string sql = "delete from Product where Id=@Id";
                SqlParameter[] pams = {
                    new SqlParameter("@Id",id)
                };
    
                return DbHelper.ExecuteNonQuery(sql, pams) > 0;
            }
    删除产品
            /// <summary>
            /// 添加产品
            /// </summary>
            /// <param name="model">产品实体</param>
            /// <returns></returns>
     public bool Add(Product model)
            {
                string sql = "insert into Product values(@ProductName,@MarketPrice,@SellingPrice,@CategoryId,@Introduction,@IsOnSale,@AddTime)";
                SqlParameter[] pams = {
                    new SqlParameter("@ProductName",model.ProductName),
                    new SqlParameter("@MarketPrice",model.MarketPrice),
                    new SqlParameter("@SellingPrice",model.SellingPrice),
                    new SqlParameter("@CategoryId",model.CategoryId),
                    new SqlParameter("@Introduction",model.Introduction),
                    new SqlParameter("@IsOnSale",model.IsOnSale),
                    new SqlParameter("@AddTime",DateTime.Now)
                };
    
                return DbHelper.ExecuteNonQuery(sql, pams) > 0;
            }
    添加产品

    3、在项目中添加BLL类库

      BLL中添加ProductBLLProductCategoryBLL类,并添加业务逻辑层方法:

     public class ProductCategoryBLL
        {
            ProductCategoryDAL dal = new ProductCategoryDAL();
    
            /// <summary>
            /// 获取产品类别
            /// </summary>
            /// <returns></returns>
            public DataTable GetCategoryList()
            {
                return dal.GetCategoryList();
            }
        }
        public class ProductBLL
        {
            ProductDAL dal = new ProductDAL();
    
            /// <summary>
            /// 查询产品列表
            /// </summary>
            /// <param name="productName"></param>
            /// <param name="categoryId"></param>
            /// <returns></returns>
            public DataTable GetProductList(string productName, int categoryId)
            {
                return dal.GetProductList(productName, categoryId);
            }
    
            /// <summary>
            /// 获取Id获取产品
            /// </summary>
            /// <param name="id"></param>
            /// <returns></returns>
            public Product GetProductById(int id)
            {
                return dal.GetProductById(id);
            }
    
            /// <summary>
            /// 更新产品
            /// </summary>
            /// <param name="model"></param>
            /// <returns></returns>
            public bool Update(Product model)
            {
                return dal.Update(model);
            }
    
            /// <summary>
            /// 删除产品
            /// </summary>
            /// <param name="id"></param>
            /// <returns></returns>
            public bool Delete(int id)
            {
                return dal.Delete(id);
            }
    
            /// <summary>
            /// 添加产品
            /// </summary>
            /// <param name="model">产品模型</param>
            /// <returns></returns>
            public bool Add(Product model)
            {
                return dal.Add(model);
            }
        }

    4、在项目中添加Asp.NET Web应用程序,作为UI层,并添加Web窗体

      在窗体中添加GridView控件,并进行数据绑定的配置:

    界面效果如下:

    在后台调用BLL层中获取产品类别的方法,并将数据绑定到下拉框中:

    ProductBLL bllProduct = new ProductBLL();
            ProductCategoryBLL bllCategory = new ProductCategoryBLL();
    
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!IsPostBack)
                {
                    //绑定类别下拉框
                    BindCategory();
    
                    //绑定产品
                    BindProductList();
                }
            }
    
            /// <summary>
            /// 绑定类别下拉框方法
            /// </summary>
            private void BindCategory()
            {
                DataTable dt = bllCategory.GetCategoryList();
                ddl_Category.DataSource = dt;
                ddl_Category.DataTextField = "Name";
                ddl_Category.DataValueField = "Id";
                ddl_Category.DataBind();
                //插入默认项
                ddl_Category.Items.Insert(0, new ListItem("全部", "0"));
            }

    调用BLL层中获取产品信息的业务逻辑方法,将数据绑定到GridView中:

     /// <summary>
            /// 绑定产品方法
            /// </summary>
            private void BindProductList()
            {
                string productName = txt_ProductName.Text.Trim();
                int categoryId = Convert.ToInt32(ddl_Category.SelectedValue);
    
                DataTable dt = bllProduct.GetProductList(productName, categoryId);
                gv_Product.DataSource = dt;
                gv_Product.DataBind();
            }

    为查询按钮添加一个点击事件,进行多条件查询:

     /// <summary>
            /// 多条件搜索
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            protected void btn_Search_Click(object sender, EventArgs e)
            {
                BindProductList();
            }

    至此,列表查询功能完成

    -----------------------------------------------------------

     GridView中进行删除按钮的处理

    先在操作模板列上添加一个LinkButton服务器控件,并添加CommandName和CommandArgument这两个属性:

    添加一个js确认提示:

    GirdView中添加RowCommand事件:

    调用BLL层中的删除产品的方法:

    protected void gv_Product_RowCommand(object sender, GridViewCommandEventArgs e)
            {
                if (e.CommandName == "del")
                {
                    int id = Convert.ToInt32(e.CommandArgument);
    
                    if (bllProduct.Delete(id))
                    {
                        ClientScript.RegisterStartupScript(this.GetType(), "alert", "<script>alert('删除成功')</script>");
                        BindProductList();
                    }
                    else
                    {
                        ClientScript.RegisterStartupScript(this.GetType(), "alert", "<script>alert('删除失败')</script>");
                    }
                }
            }

    ---------------------------------------------------------

    添加产品功能实现:

    按照要求在页面中添加控件:

     在后台页面加载的时读取下拉框数据:

    ProductBLL bllProduct = new ProductBLL();
            ProductCategoryBLL bllCategory = new ProductCategoryBLL();
    
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!IsPostBack)
                {
                    //绑定类别下拉框
                    BindCategory();
                }
            }
    
            /// <summary>
            /// 绑定类别下拉框方法
            /// </summary>
            private void BindCategory()
            {
                DataTable dt = bllCategory.GetCategoryList();
                ddl_Category.DataSource = dt;
                ddl_Category.DataTextField = "Name";
                ddl_Category.DataValueField = "Id";
                ddl_Category.DataBind();
            }
    绑定下拉菜单

    为按钮添加点击事件实现添加功能:

     protected void btn_Save_Click(object sender, EventArgs e)
            {
                Product model = new Product()
                {
                    CategoryId = Convert.ToInt32(ddl_Category.SelectedValue),
                    Introduction = txt_Introduction.Text,
                    IsOnSale = ck_IsOnSale.Checked,
                    MarketPrice = Convert.ToDecimal(txt_MarketPrice.Text),
                    ProductName = txt_ProductName.Text,
                    SellingPrice = Convert.ToDecimal(txt_SellingPrice.Text)
                };
    
                //添加成功后,弹出消息提示,并跳转至首页
                if (bllProduct.Add(model))
                {
                    Page.ClientScript.RegisterStartupScript(this.GetType(), "alert", "<script>alert('添加成功!');location.href='/Index.aspx';</script>");
                }
                else
                {
                    Page.ClientScript.RegisterStartupScript(this.GetType(), "alert", "<script>alert('添加失败!');</script>");
                }
            }

    --------------------------------------------------

    编辑产品功能实现:

       按照要求在页面中添加控件:

      

    在类别页面添加跳转到编辑页面的链接:

    在后台添加获取下拉框数据的方法:

            ProductBLL bllProduct = new ProductBLL();
            ProductCategoryBLL bllCategory = new ProductCategoryBLL();
    
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!IsPostBack)
                {
                    //绑定类别下拉框
                    BindCategory();
    
                    //绑定产品信息
                    BindProductInfo();
                }
            }
    
            /// <summary>
            /// 绑定类别下拉框方法
            /// </summary>
            private void BindCategory()
            {
                DataTable dt = bllCategory.GetCategoryList();
                ddl_Category.DataSource = dt;
                ddl_Category.DataTextField = "Name";
                ddl_Category.DataValueField = "Id";
                ddl_Category.DataBind();
            }
    绑定下拉菜单

    添加根据id获取当前编辑的产品的方法:

    /// <summary>
            /// 绑定产品信息方法
            /// </summary>
            private void BindProductInfo()
            {
                int id = Convert.ToInt32(Request.QueryString["id"]);
                Product model = bllProduct.GetProductById(id);
                if (model != null)
                {
                    txt_ProductName.Text = model.ProductName;
                    txt_Introduction.Text = model.Introduction;
                    txt_MarketPrice.Text = model.MarketPrice.ToString();
                    txt_SellingPrice.Text = model.SellingPrice.ToString();
                    ddl_Category.SelectedValue = model.CategoryId.ToString();
                    ck_IsOnSale.Checked = model.IsOnSale;
                    lbl_Id.Text = model.Id.ToString();
                }
    
            }

    为按钮添加点击事件实现更新:

    /// <summary>
            /// 提交修改
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            protected void btn_Save_Click(object sender, EventArgs e)
            {
                Product model = new Product()
                {
                    CategoryId = Convert.ToInt32(ddl_Category.SelectedValue),
                    Id = Convert.ToInt32(Request.QueryString["id"]),
                    Introduction = txt_Introduction.Text,
                    IsOnSale = ck_IsOnSale.Checked,
                    MarketPrice = Convert.ToDecimal(txt_MarketPrice.Text),
                    ProductName = txt_ProductName.Text,
                    SellingPrice = Convert.ToDecimal(txt_SellingPrice.Text)
                };
    
                //修改成功后,弹出消息提示,并跳转至首页
                if (bllProduct.Update(model))
                {
                    Page.ClientScript.RegisterStartupScript(this.GetType(), "alert", "<script>alert('修改成功!');location.href='/Index.aspx';</script>");
                }
                else
                {
                    Page.ClientScript.RegisterStartupScript(this.GetType(), "alert", "<script>alert('修改失败!');</script>");
                }
            }

    -----------------------------

    利用三层架构与GridView相结合,GirdView的使用方法和之前基本一致,改变为三层架构之后,我们发现原本在UI层中的代码明显减少了很多,通过ADO.NET访问数据库的部分放在了数据访问层,体现出了高内聚、低耦合的思想。

  • 相关阅读:
    简洁的Python
    python docker
    django-rest-framework笔记-类视图篇
    itertools库
    python 内置库
    python 数据分类
    python元组
    django-rest-framework笔记-请求与响应篇
    Centos 安装.NET CORE 3.1
    api接口签名验证
  • 原文地址:https://www.cnblogs.com/JuneDream/p/14077650.html
Copyright © 2020-2023  润新知