31、三层架构、AJAX+FormsAuthentication实现登陆

三层架构

前段时间公司要求修改一个网站,打开后我疯了,一层没有都是调用的DB接口,遍地的SQL语句,非常杂乱。

什么是三层架构?

三层架构是将整个项目划分为三个层次:表现层、业务逻辑层、数据访问层。目的为了高内聚低耦合思想。

三层结构

表现层(UI):接受用户请求,数据的返回呈现。

业务逻辑层(BLL ):用来处理业务逻辑,处理用户提交的数据。

数据访问层(DAL):用来与数据库进行交互,处理增、删、改、差。

实体类对象(Model):用来存储实体类。

三层关系

UI表现层:接收用户输入的数据,并传递给业务逻辑层。

BLL业务逻辑层:把接收到的数据传递给数据访问层,并返回结果给UI层。

DAL数据访问层:负责与数据库进行交互,并将结果返回给BLL层。

什么时候需要分层?

当项目过大的时候可以分层开发,这样可以每个人负责的不同,共同进行开发。如果一个项目非常小的话,独立开发可以不分层。

操作步骤:

1、创建结构

新增三个类库分别是:BLL、DAL、Model,并建立一个UI层(winform 或 webform 或 MVC项目)设置启动项为UI层。

这里随个人喜欢可以再加一个Common层,负责处理其他常用方法。

2、引用关系

DAL要用到Model,BLL要用到DAL、CL和Model,UI要用到BLL、Model和CL。相互引用即可。

实现登陆

登陆是所有系统的入口,相信大家一般都用session,本例使用FormsAuthentication微软提供的身份认证,存储在cookie中。

假设有如下管理员表:

mif_id:唯一标识,lever等级,usernmae,psw账号密码,trueName姓名,createTime创建日期,isLock是否锁定,Power权限。

编写实体类

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5
 6 namespace Model
 7 {
 8     /// <summary>
 9     /// 管理员实体类
10     /// </summary>
11     public class ManagerInfo
12     {
13         /// <summary>
14         /// 标识ID
15         /// </summary>
16         public int mif_id { get; set; }
17         /// <summary>
18         /// 暂时没用
19         /// </summary>
20         public int mif_pid { get; set; }
21         /// <summary>
22         /// 管理员等级
23         /// </summary>
24         public int mif_lever { get; set; }
25         /// <summary>
26         /// 账号
27         /// </summary>
28         public string mif_userName { get; set; }
29         /// <summary>
30         /// 密码
31         /// </summary>
32         public string mif_psw { get; set; }
33         /// <summary>
34         /// 姓名
35         /// </summary>
36         public string mif_trueName { get; set; }
37         /// <summary>
38         /// 创建时间
39         /// </summary>
40         public DateTime mif_createTime { get; set; }
41         /// <summary>
42         /// 是否锁定
43         /// </summary>
44         public bool mif_isLock { get; set; }
45         /// <summary>
46         /// 权限
47         /// </summary>
48         public string mif_power { get; set; }
49     }
50 }

ManagerInfo.cs

习惯性编写完Model重新生成下Model层,检查是否有错误。

编写数据访问层

引入sqlHelper文件(上一文章中找),修改UI中的web.config添加数据库连接字符串,并在sqlHelper中修改相关名称,注意引入System.configuration.dll。

编写操作ManagerInfo的数据访问类

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using Model;
 6 using System.Data.SqlClient;
 7
 8 namespace DAL
 9 {
10     /// <summary>
11     /// 管理员数据访问类
12     /// </summary>
13     public class ManagerInfoDal
14     {
15         /// <summary>
16         /// 通过账号查找
17         /// </summary>
18         /// <param name="userName"></param>
19         /// <returns></returns>
20         public static ManagerInfo row(string userName)
21         {
22             string sql = "select mif_id,mif_lever,mif_userName,mif_psw,mif_trueName,mif_createTime,mif_isLock from managerInfo where mif_userName = @uid";
23             var v = new ManagerInfo();
24             using (var dr = SQLHelper.ExecuteReader(sql, new SqlParameter("@uid", userName)))
25             {
26                 if (dr.Read())
27                 {
28                     v.mif_id = Convert.ToInt32(dr["mif_id"]);
29                     v.mif_lever = Convert.ToInt32(dr["mif_lever"]);
30                     v.mif_userName = dr["mif_userName"].ToString();
31                     v.mif_psw = dr["mif_psw"].ToString();
32                     v.mif_trueName = dr["mif_trueName"].ToString();
33                     v.mif_createTime = Convert.ToDateTime(dr["mif_createTime"]);
34                     v.mif_isLock = Convert.ToBoolean(dr["mif_isLock"]);
35                 }
36             }
37             return v;
38         }
39     }
40 }

ManagerInfoDal.cs

编写业务逻辑层

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using DAL;
 6 using System.Web.Security;
 7 using System.Web;
 8 using CL;
 9 using Model;
10
11 namespace BLL
12 {
13     /// <summary>
14     /// 管理员
15     /// </summary>
16     public class ManagerInfoBll
17     {
18         /// <summary>
19         /// 登陆
20         /// </summary>
21         /// <param name="userName"></param>
22         /// <param name="passWord"></param>
23         /// <param name="remember">是否记住</param>
24         /// <returns></returns>
25         public static string login(string userName, string passWord, string remember)
26         {
27             var v = ManagerInfoDal.row(userName);
28             if (v.mif_id > 0)
29             {
30                 if (v.mif_isLock == false)
31                 {
32                     if (v.mif_psw.Equals(createMD5.getMD5(passWord)))
33                     {
34                         var expires = DateTime.Now.AddMinutes(20);
35                         if (remember.Equals("on"))
36                         {
37                             expires = DateTime.Now.AddDays(8);
38                         }
39                         //将登陆的用户存储在Ticket中
40                         var ticket = new FormsAuthenticationTicket(0, userName, DateTime.Now, expires, true, userName);
41                         //使用Encrypt方法加密Ticket,并存储在cookie中
42                         var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket));
43                         //防止浏览器攻击窃取、伪造cookie信息
44                         cookie.HttpOnly = true;
45                         cookie.Expires = expires;
46                         HttpContext.Current.Response.Cookies.Add(cookie);
47                         return "0";
48                     }
49                     return "1";
50                 }
51                 return "2";
52             }
53             return "3";
54         }
55         public static ManagerInfo row(string userName)
56         {
57             return ManagerInfoDal.row(userName);
58         }
59         /// <summary>
60         /// 查询权限(通过数字查询名字)
61         /// </summary>
62         /// <param name="userRole">权限数字</param>
63         /// <returns></returns>
64         public static string getRole(int userRole)
65         {
66             switch (userRole)
67             {
68                 case 0:
69                     return "编辑";
70                 case 1:
71                     return "管理员";
72                 case 2:
73                     return "系统";
74                 default:
75                     return "暂无";
76             }
77         }
78     }
79 }

ManagerInfoBll.cs

管理员等级这里建议写成枚举,本人较懒。

FormsAuthenticationTicket这个东西比传统的session和cookie的好处就是 可以任意目录设置他的访问权限,如果没有登陆直接跳出到登陆页面。而不用每个页面一开始都认证一番~

还有 cookie.HttpOnly 在使用cookie时这一项最好设置一下,否则可能会客户端模拟cookie进行攻击。

编写通用层

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Security.Cryptography;
 5 using System.Text;
 6
 7 namespace CL
 8 {
 9     public class createMD5
10     {
11         public static string getMD5(string str)
12         {
13             var md5 = MD5.Create();
14             var buffer = Encoding.Default.GetBytes(str);
15             var mdbuffer = md5.ComputeHash(buffer);
16             StringBuilder result = new StringBuilder();
17             for (int i = 0; i < mdbuffer.Length; i++)
18             {
19                 result.Append(mdbuffer[i].ToString("x2"));
20             }
21             return result.ToString();
22         }
23     }
24 }

createMD5

生成MD5的代码,可不用。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Drawing;
 4 using System.Drawing.Drawing2D;
 5 using System.Drawing.Imaging;
 6 using System.IO;
 7 using System.Linq;
 8 using System.Text;
 9 using System.Web;
10
11 namespace CL
12 {
13     public static class createVlidate
14     {
15         /// <summary>
16         /// 字符
17         /// </summary>
18         /// <param name="len">几位</param>
19         /// <returns></returns>
20         public static string validation(int cd)
21         {
22             var ran = new Random();
23             int num, tem;
24             string rtuStr = "";
25             for (int i = 0; i < cd; i++)
26             {
27                 num = ran.Next();
28                 if (i % 2 == 1)
29                     tem = num % 10 + ‘0‘; //数字
30                 else
31                     tem = num % 26 + ‘A‘; //字母
32                 rtuStr += Convert.ToChar(tem).ToString();
33             }
34             //写入cookie
35             HttpCookie cookie = new HttpCookie("check");
36             cookie.Value = rtuStr.ToLower();
37             HttpContext.Current.Response.Cookies.Add(cookie);
38             return rtuStr;
39         }
40
41         /// <summary>
42         /// 生成图像
43         /// </summary>
44         /// <param name="check">字符</param>
45         public static byte[] drawImg(string check)
46         {
47             Bitmap img = new Bitmap(90, 34);
48             var ht = Graphics.FromImage(img);
49             ht.Clear(Color.White);
50             ht.DrawLine(new Pen(Color.SpringGreen), 1, 1, 90, 34);
51             Font font = new Font("微软雅黑", 20, FontStyle.Bold);
52             var jianbian = new LinearGradientBrush(new Rectangle(0, 0, img.Width, img.Height), Color.Teal, Color.Snow, 2f, true);
53             ht.DrawString(check, font, jianbian, 0, 0);
54             ht.DrawRectangle(new Pen(Color.Aqua), 0, 0, img.Width - 1, img.Height - 1);
55             MemoryStream ms = new MemoryStream();
56             img.Save(ms, ImageFormat.Jpeg);
57             ht.Dispose();
58             img.Dispose();
59             return ms.ToArray();
60         }
61     }
62 }

createValidate.cs

生成验证码的,可自己写。

编写展现层

首先需要在web.config中设置authentication节点为Forms验证模式,然后就可以在目录中任意设置访问级别了。

<authentication mode="Forms">
  <forms loginUrl="~/manage/index.html" timeout="10080" defaultUrl="~/manage/Net/" />
</authentication>

登陆页面代码

 1 <!DOCTYPE html>
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3 <head>
 4     <meta charset="utf-8" />
 5     <meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1" />
 6     <meta http-equiv="X-UA-Compatible" content="IE=9" />
 7     <meta name="viewport" content="width=device-width, initial-scale=1">
 8     <title>汉之殇管理系统</title>
 9     <link href="css/bootstrap.css" rel="stylesheet" />
10     <link href="css/admin.css" rel="stylesheet" />
11     <!--[if lt IE 9]>
12       <script src="http://apps.bdimg.com/libs/html5shiv/3.7/html5shiv.min.js"></script>
13       <script src="http://apps.bdimg.com/libs/respond.js/1.4.2/respond.min.js"></script>
14     <![endif]-->
15 </head>
16 <body class="login">
17     <nav class="navbar navbar-default navbar-static-top">
18         <div class="container">
19             <div class="navbar-header">
20                 <a href="login.html" class="navbar-brand">汉之殇管理系统</a>
21             </div>
22         </div>
23     </nav>
24     <div class="container">
25         <div class="panel panel-default">
26             <div class="panel-body">
27                 <div id="ts"></div>
28                 <h4 class="page-header">登陆</h4>
29                 <div class="form-group has-feedback">
30                     <label class="sr-only" for="userName">账号</label>
31                     <input type="text" id="userName" class="form-control" placeholder="账号" maxlength="50" autofocus />
32                     <span class="glyphicon glyphicon-user form-control-feedback" aria-hidden="true"></span>
33                 </div>
34                 <div class="form-group has-feedback">
35                     <label class="sr-only" for="passWord">密码</label>
36                     <input type="password" id="passWord" class="form-control" maxlength="50" placeholder="密码" />
37                     <span class="glyphicon glyphicon-lock form-control-feedback" aria-hidden="true"></span>
38                 </div>
39                 <div class="form-group has-feedback">
40                     <label class="sr-only" for="validateCode">验证码</label>
41                     <input type="text" id="validateCode" class="form-control validateCode" placeholder="验证码" maxlength="4" />
42                     <img src="checkLogin/ValidateCode.ashx" id="img" onclick="changeCode()" class="validateImg">
43                     <a href="javascript:changeCode()">看不清,换一张</a>
44                 </div>
45                 <div class="form-group">
46                     <input type="checkbox" id="remember" checked="checked" /> <span class="form-control-static">记住我 </span>
47                     <button id="submit" type="button" class="btn btn-primary col-xs-offset-4" style="width:40%">登录</button>
48                 </div>
49             </div>
50         </div>
51     </div>
52     <nav class="navbar navbar-default navbar-fixed-bottom">
53         <div class="container">
54             <div class="navbar-header">
55                 <p class="navbar-text">&copy; 2015 汉之殇 版权所有</p>
56             </div>
57         </div>
58     </nav>
59     <script src="js/jquery-1.7.2.min.js"></script>
60     <script src="js/status.js"></script>
61     <script src="js/login.js"></script>
62 </body>
63 </html>

index.html

验证码

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using CL;
 6
 7 namespace UI.manage.checkLogin
 8 {
 9     /// <summary>
10     /// ValidateCode 的摘要说明
11     /// </summary>
12     public class ValidateCode : IHttpHandler
13     {
14         public void ProcessRequest(HttpContext context)
15         {
16             context.Response.ContentType = "image/jpeg";
17
18             var check = createVlidate.validation(4);
19             byte[] buffer = createVlidate.drawImg(check);
20
21             context.Response.BinaryWrite(buffer);
22         }
23
24         public bool IsReusable
25         {
26             get
27             {
28                 return false;
29             }
30         }
31     }
32 }

ValidateCode.ashx

登陆用的JS

 1 $(function () {
 2     $.get("checkLogin/Validate.ashx?rand=" + Math.random(0, 1), function (data) {
 3         if (data == "0") {
 4             location.href="/manage/Net/"
 5         }
 6     });
 7
 8     if (top.location != self.location) {
 9         top.location = self.location;
10     }
11
12     var lj = window.location.toString();
13     if (lj.lastIndexOf("?") != -1) {
14         status("info", "请先登录!");
15         $("#userName").focus();
16     }
17
18     $(".login").height(document.documentElement.clientHeight);
19     document.onkeydown = function (e) {
20         var ev = document.all ? window.event : e;
21         if (ev.keyCode == 13) {
22             $("#submit").click();
23         }
24     }
25 });
26 $("#submit").click(function () {
27     //$("#submit").attr("disabled", "true");
28     var userName = $("#userName").val();
29     var passWord = $("#passWord").val();
30     var validateCode = $("#validateCode").val();
31     var remember = $("#remember:checked").val();
32     if (userName != "") {
33         if (passWord != "") {
34             if (validateCode != "") {
35                 if (validateCode.toLowerCase() == getCode()) {
36                     $.post("checkLogin/Validate.ashx", { userName: userName, passWord: passWord, remember: remember }, function (data) {
37                         changeCode();
38                         if (data == "0") {
39                             location.href = "Net/";
40                         } else if (data == "1") {
41                             status("no", "登陆失败,密码错误!");
42                             $("#passWord").focus();
43                             return false;
44                         } else if (data == "2") {
45                             status("no", "登陆失败,账号已被禁止登陆!");
46                             $("#userName").focus();
47                             return false;
48                         } else {
49                             status("no", "登陆失败,账号不存在!");
50                             $("#userName").focus();
51                             return false;
52                         }
53                     });
54                     return false;
55                 }
56                 status("no", "验证码不正确!");
57                 $("#validateCode").focus();
58                 return false;
59             }
60             status("info", "请输入验证码!");
61             $("#validateCode").focus();
62             return false;
63         }
64         status("info", "请输入您的密码!");
65         $("#passWord").focus();
66         return false;
67     }
68     status("info", "请输入您的账号!");
69     $("#userName").focus();
70     return false;
71 });
72 function changeCode() {
73     $("#img").attr("src", $("#img").attr("src") + "?");
74 }
75 function getCode() {
76     var cookies = document.cookie.split(";");
77     for (var i = 0; i < cookies.length; i++) {
78         var validate = cookies[i].split("=");
79         if (validate[0].replace(/(^\s*)|(\s*$)/g, "") == "check") {
80             return validate[1].replace(/(^\s*)|(\s*$)/g, "");
81         }
82     }
83 }

login.js

验证的一般处理程序

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5
 6 namespace UI.manage.checkLogin
 7 {
 8     /// <summary>
 9     /// Validate 的摘要说明
10     /// </summary>
11     public class Validate : IHttpHandler
12     {
13
14         public void ProcessRequest(HttpContext context)
15         {
16             var userName = context.Request["userName"];
17             var passWord = context.Request["passWord"];
18             var remember = context.Request["remember"] == null ? "" : context.Request["remember"];
19             if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(passWord))
20             {
21                 var result = BLL.ManagerInfoBll.login(userName, passWord, remember);
22                 context.Response.Write(result);
23             }
24             else
25             {
26                 if (context.Request.IsAuthenticated)
27                 {
28                     context.Response.Write("0");
29                 }
30             }
31         }
32
33         public bool IsReusable
34         {
35             get
36             {
37                 return false;
38             }
39         }
40     }
41 }

Validate.ashx

最后附上效果图如下:

登陆后使用 Page.User.Identity.Name 获取用户标识。

如下:

获取信息及退出登陆如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using System.Web.Security;
 6 using System.Web.UI;
 7 using System.Web.UI.WebControls;
 8 using BLL;
 9 using Model;
10
11 namespace UI.manage.Net
12 {
13     public partial class _default : System.Web.UI.Page
14     {
15         protected void Page_Load(object sender, EventArgs e)
16         {
17             if (!IsPostBack)
18             {
19                 var userName = Page.User.Identity.Name;
20                 int roleId = ManagerInfoBll.row(userName).mif_lever;
21
22                 this.userId.InnerText = userName;
23                 this.userRole.InnerText = ManagerInfoBll.getRole(roleId);
24             }
25
26             var logout = Request["logout"];
27             if (!string.IsNullOrEmpty(logout))
28             {
29                 FormsAuthentication.SignOut();
30                 Response.Redirect("../index.html");
31             }
32         }
33     }
34 }

default.aspx.cs

最后 在禁止匿名访问的目录下 新增一个web.config 内容如下

<?xml version="1.0"?>
<configuration>
  <system.web>
    <authorization>
      <deny users="?"/>
    </authorization>
  </system.web>
</configuration>

这样,当记住凭证后直接访问登陆或者该目录都可以直接跳转,如果点击退出或过期后,则自动跳出到登陆页面中。至此大功告成~

时间: 2024-11-06 07:07:14

31、三层架构、AJAX+FormsAuthentication实现登陆的相关文章

三层架构下实现用户登陆C#

上篇文章讲到三层.接下来就通过一个实例具体的看怎么用三层实现用户登陆界面. 一.Model实体(LoginModel): namespace LoginModel { //添加类:UserInfo Model实体作用:封装数据,使数据在三层中传输 ,更倾向于业务逻辑层 public class UserInfo { //定义用户属性 public int ID { get; set; } public string UserName { get; set; } public string Pas

[转]C#三层架构登陆实例

很早之前,就听说过三层结构了.当时只知道 三层结构 是把 系统的 界面  跟 数据库操作等不相关的程序分别开来.原来这么简单的实现,确实传说中的 三层结构啊. 首先,先来看一下是哪三层.表示层(UI,User Interface),业务逻辑层(BLL BusinessLogicLayer),数据访问层(DAL Data Access Layer).三层的划分是物理上的划分. 表示层(UI),这个最容易理解,就是用户看到的主界面. 数据访问层(DAL),也不难理解,主要是负责数据的增删改查. 业务

C#三层架构登陆实例

很早之前,就听说过三层结构了.当时只知道 三层结构 是把 系统的 界面  跟 数据库操作等不相关的程序分别开来.原来这么简单的实现,确实传说中的 三层结构啊. 首先,先来看一下是哪三层.表示层(UI,User Interface),业务逻辑层(BLL BusinessLogicLayer),数据访问层(DAL Data Access Layer).三层的划分是物理上的划分. 表示层(UI),这个最容易理解,就是用户看到的主界面. 数据访问层(DAL),也不难理解,主要是负责数据的增删改查. 业务

VB.NET之旅-三层架构之登陆

初接触三层 三层是指显示层,业务逻辑层,数据访问层,是为"高内聚,低耦合"服务的 除了上述三层之外,一个程序中必须要有的还有实体层,我的理解是实体层中的实体是与数据库中的表相对的,而实体的属性是与数据表中字段相对的,大家还可以根据需要加入外观层,数据接口,抽象工厂层这都是后话,要根据程序的需要进行添加.就像我们今天要实现的登陆这个就不需要外观,数据接口,抽象共厂,其实就连业务逻辑层也可以省略,因为这里并没有逻辑运算. 显示层引用业务逻辑层,业务逻辑层引用数据访问层,三层均可根据需要引用

C# 三层架构之系统的登录验证与添加数据的实现

利用三层架构体系,实现学生管理系统中用户的登录与添加班级信息的功能,一下代码为具体实现步骤的拆分过程: 一.用户登录界面功能的实现 1.在数据访问层(LoginDAL)进行对数据库中数据的访问操作 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 //引入命名空间 7 using System

ASP.NET典型三层架构企业级医药行业ERP系统实战

我这里有一套课程和大家分享,我的qq是2059055336,   课程说明: 国内首部完整讲述ERP系统架构.业务逻辑.开发的项目实战课程.考虑到本系统的庞大及复杂性.本课程原价购买学员每人赠送一个U盾设备,U盾可插在任意电脑上进行学习,使用方便,学习灵活!可永久学习! 项目由来: 此项目是讲师亲自参与构架及参与开发的大型ERP项目,此项目已被太阳石药业,九芝堂药业,拜欧药业等多家大中型企业使用,为其创造巨大经济价值.整个项目由10多个研发人员全程打造,项目总价值接近3000万,给企业创造的价值

从MVC和三层架构说到SSH整合开发

相信很多人都认同JavaWeb开发是遵从MVC开发模式的,遵从三层架构进行开发的,是的,大家都这么认同.但是相信大家都会有过这样一个疑问,if(MVC三层模式==三层架构思想)out.println(“请继续观看……”) 1.MVC(MODEL-VIEW-CONTROLLER)设计模式: 首先让我们了解下MVC(Model-View-Controller)的概念: MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写

Aircoinst 三层架构ASP.NET开源

<注意! 本源码为我本人所写,可能有点烂.仅供学习使用,请勿进行商业用途~!> <本源码永久归于MineLSG 及 Aircoinst_慈 所拥有> 使用方法:直接拷贝 一.结构&环境介绍 <数据结构> 如下 BLL 业务逻辑层 DAL 数据交换层 FULL 全局变量 Model 实体类 UI 层为 WebApp 数据库为:SQL SERVER 2008 R2 IDE为:Visual Studio 2019 Pro 层的引用如下所示 BLL →DAL BLL →

用java观察者模式解耦经典三层架构

三层架构是一个很经典的架构模式,依据系统的职责不同.将系统分成了表现层,逻辑层和数据訪问层,而且配合数据实体进行传输数据,能够大大的封装性和复用性. 经典的三层架构图: 我们再深入到架构图内部.看看详细的类图,用简单的登陆举例吧: 这里通过LoginUI.调用了LoginLogService和LoginVerificationService两个类.通过类图能够看得出,U层和Service层(本文把BLL层称为了Service层)直接採用了直接调用的方式. 在面向对象的设计中.一直强调要面向接口编