zoukankan      html  css  js  c++  java
  • 1_MVC+EF+Autofac(dbfirst)轻型项目框架_core层(以登陆为例)

    前言

      在上一篇0_MVC+EF+Autofac(dbfirst)轻型项目框架_基本框架中,我已经介绍了这个轻型框架的层次结构,在下面的这篇文章中,我将以教师登陆功能为例,具体来扩充下我的core层的代码。

      在这之前,我想先补充讨论下是否有必要添加server层,因为看过不少别人的框架都有这一层。首先,server层在不同地方有着不同的解释。有个常听的词叫MVSC,这里所指的S虽然也是server的意思,但实现的功能更有点类似于我框架中的core,主要存放也是业务逻辑。但我看了别人框架上的server层,有些甚至已经直接继承自Controller类,一开始很不解,这样做让web层中的Controller颜面何存。但在深入了解了mvc的一些机制后觉得这样做也有道理(mvc在注册控制器时是遍历文件夹中的dll来的),把视图和控制器存放在了不同的程序集里,便于团队开发。但有些server层的作用更像是单纯为了给web(view)和core解耦或者说是改变依赖关系。具体我还真的没能力来讨论这么做有没有必要,别人这么做必然有别人的出发点和目的,但在我的轻量架构中还是没有引入server这个层,因为在一定程度上它只会增加框架整体的复杂性,“轻”还是主基调。

      同样,文中有问题的地方欢迎批评指正!谢谢!

    创建过程

      1.首先数据表结构如下图

      

      表中ID是教师的GUID,TID才是用来登陆的唯一标示,PID是权限的标示,接下去讲权限判断时将会提到它。

      2.根据数据库生成edmx在Model层的Entity中

      3.在ICore中创建教师类接口,在Core中创建教师类

      接口中很简单,就一句话,定义了教师类的接口。

    public partial interface ITeacher{}

      在Core中创建一个类用来实现ITeacher接口

        public partial class Teacher : BaseCore<Entity.Teacher>, ICore.ITeacher
        {
            public Teacher(DbContext dbContext)
            {
                db = dbContext;
            }
        }

      BaseCore是什么?不要惊慌。在上一篇中,我谈到了我将不引入DAL层来再次封装EF,但在EF中,有些操作比较复杂,例如修改删除等。如果每次使用时都要先查找再修改,要写很多重复代码,我的BaseCore是对这些方法的一些封装,虽然会造成一些代码的污染,但着实可以少写不少重复代码。也许会有人提出异议,这样的行为是否可以理解成是对EF的封装?我也不能完全否认,但我更愿意把它理解成业务层对于操作EF的帮助类:

        第一,相对于单独做一层来看,这样更“轻”

        第二,这样做放在业务上也更加合适,例如不需要去考虑“分页该不该放在DAL?”这类永远讨论不出正确答案的问题

        第三,维护更简单

        第四,既然是帮助类,那就提供了不用它的可能,觉得不爽不用它就是

      以下是BaseCore的代码,有点长。帮助类中借鉴了部分他人分享的代码,实在找不到出处了,这里表示感谢!

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Data.Entity;
      4 using System.Data.Entity.Infrastructure;
      5 using System.Linq;
      6 using System.Linq.Expressions;
      7 using System.Reflection;
      8 using System.Text;
      9 
     10 namespace EDUA_Core
     11 {
     12     /// <summary>
     13     /// 业务帮助父类
     14     /// </summary>
     15     /// <typeparam name="T">之类类型</typeparam>
     16     public class BaseCore<T> where T : class,new()
     17     {
     18         /// <summary>
     19         /// EF上下文对象
     20         /// </summary>
     21         protected DbContext db { get; set; }
     22 
     23         #region 1.0新增实体 + void Add(T model)
     24         /// <summary>
     25         /// 新增实体
     26         /// </summary>
     27         /// <param name="model">新增的实体</param>
     28         protected void Add(T model)
     29         {
     30             db.Set<T>().Add(model);
     31         }  
     32         #endregion
     33 
     34         #region 1.0.1新增实体并保存 + int AddAndSave(T model)
     35         /// <summary>
     36         /// 新增实体并保存
     37         /// </summary>
     38         /// <param name="model">新增的实体</param>
     39         /// <returns>受影响的行数</returns>
     40         protected int AddAndSave(T model)
     41         {
     42             Add(model);
     43             return db.SaveChanges();
     44         } 
     45         #endregion
     46 
     47         #region 2.0删除实体 + void Del(T model)
     48         /// <summary>
     49         /// 删除实体
     50         /// </summary>
     51         /// <param name="model">删除的实体</param>
     52         protected void Del(T model)
     53         {
     54             db.Set<T>().Attach(model);
     55             db.Set<T>().Remove(model);
     56         } 
     57         #endregion
     58 
     59         #region 2.0.1删除实体并保存 + int DelAndSave(T model)
     60         /// <summary>
     61         /// 删除实体并保存
     62         /// </summary>
     63         /// <param name="model">删除的实体</param>
     64         /// <returns>受影响的行数</returns>
     65         protected int DelAndSave(T model)
     66         {
     67             Del(model);
     68             return db.SaveChanges();
     69         } 
     70         #endregion
     71 
     72         #region 2.1根据条件删除 + void DelBy(Expression<Func<T, bool>> delWhere)
     73         /// <summary>
     74         /// 根据条件删除
     75         /// </summary>
     76         /// <param name="delWhere">条件</param>
     77         protected void DelBy(Expression<Func<T, bool>> delWhere)
     78         {
     79             //3.1查询要删除的数据
     80             List<T> listDeleting = db.Set<T>().Where(delWhere).ToList();
     81             //3.2将要删除的数据 用删除方法添加到 EF 容器中
     82             listDeleting.ForEach(u =>
     83             {
     84                 db.Set<T>().Attach(u);//先附加到 EF容器
     85                 db.Set<T>().Remove(u);//标识为 删除 状态
     86             });
     87         } 
     88         #endregion
     89 
     90         #region 2.1.1根据条件删除并保存 + int DelByAndSave(Expression<Func<T, bool>> delWhere)
     91         /// <summary>
     92         /// 根据条件删除并保存
     93         /// </summary>
     94         /// <param name="delWhere">条件</param>
     95         /// <returns>受影响的行数</returns>
     96         protected int DelByAndSave(Expression<Func<T, bool>> delWhere)
     97         {
     98             DelBy(delWhere);
     99             return db.SaveChanges();
    100         } 
    101         #endregion
    102 
    103         #region 3.0修改实体 + void Modify(T model, params string[] proNames)
    104         /// <summary>
    105         /// 修改,如:
    106         /// T u = new T() { uId = 1, uLoginName = "asdfasdf" };
    107         /// this.Modify(u, "uLoginName");
    108         /// </summary>
    109         /// <param name="model">要修改的实体对象</param>
    110         /// <param name="proNames">要修改的 属性 名称</param>
    111         protected void Modify(T model, params string[] proNames)
    112         {
    113             //4.1将 对象 添加到 EF中
    114             DbEntityEntry entry = db.Entry<T>(model);
    115             //4.2先设置 对象的包装 状态为 Unchanged
    116             entry.State = (System.Data.Entity.EntityState)System.Data.EntityState.Unchanged;
    117             //4.3循环 被修改的属性名 数组
    118             foreach (string proName in proNames)
    119             {
    120                 //4.4将每个 被修改的属性的状态 设置为已修改状态;后面生成update语句时,就只为已修改的属性 更新
    121                 entry.Property(proName).IsModified = true;
    122             }
    123         } 
    124         #endregion
    125 
    126         #region 3.0.1修改和保存 + int ModifyAndSave(T model, params string[] proNames)
    127         /// <summary>
    128         /// 修改和保存,如:
    129         /// T u = new T() { uId = 1, uLoginName = "asdfasdf" };
    130         /// this.Modify(u, "uLoginName");
    131         /// </summary>
    132         /// <param name="model">要修改的实体对象</param>
    133         /// <param name="proNames">要修改的 属性 名称</param>
    134         /// <returns>受影响的行数</returns>
    135         protected int ModifyAndSave(T model, params string[] proNames)
    136         {
    137             Modify(model, proNames);
    138             return db.SaveChanges();
    139         } 
    140         #endregion
    141 
    142         #region 3.1批量修改 + void ModifyBy(T model, Expression<Func<T, bool>> whereLambda, params string[] modifiedProNames)
    143         /// <summary>
    144         /// 批量修改
    145         /// </summary>
    146         /// <param name="model">要修改的实体对象</param>
    147         /// <param name="whereLambda">查询条件</param>
    148         /// <param name="proNames">要修改的 属性 名称</param>
    149         protected void ModifyBy(T model, Expression<Func<T, bool>> whereLambda, params string[] modifiedProNames)
    150         {
    151             //4.1查询要修改的数据
    152             List<T> listModifing = db.Set<T>().Where(whereLambda).ToList();
    153 
    154             //获取 实体类 类型对象
    155             Type t = typeof(T); // model.GetType();
    156             //获取 实体类 所有的 公有属性
    157             List<PropertyInfo> proInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList();
    158             //创建 实体属性 字典集合
    159             Dictionary<string, PropertyInfo> dictPros = new Dictionary<string, PropertyInfo>();
    160             //将 实体属性 中要修改的属性名 添加到 字典集合中 键:属性名  值:属性对象
    161             proInfos.ForEach(p =>
    162             {
    163                 if (modifiedProNames.Contains(p.Name))
    164                 {
    165                     dictPros.Add(p.Name, p);
    166                 }
    167             });
    168 
    169             //4.3循环 要修改的属性名
    170             foreach (string proName in modifiedProNames)
    171             {
    172                 //判断 要修改的属性名是否在 实体类的属性集合中存在
    173                 if (dictPros.ContainsKey(proName))
    174                 {
    175                     //如果存在,则取出要修改的 属性对象
    176                     PropertyInfo proInfo = dictPros[proName];
    177                     //取出 要修改的值
    178                     object newValue = proInfo.GetValue(model, null); //object newValue = model.uName;
    179 
    180                     //4.4批量设置 要修改 对象的 属性
    181                     foreach (T usrO in listModifing)
    182                     {
    183                         //为 要修改的对象 的 要修改的属性 设置新的值
    184                         proInfo.SetValue(usrO, newValue, null); //usrO.uName = newValue;
    185                     }
    186                 }
    187             }
    188         } 
    189         #endregion
    190 
    191         #region 3.1.1批量修改并保存 + int ModifyByAndSave(T model, Expression<Func<T, bool>> whereLambda, params string[] modifiedProNames)
    192         /// <summary>
    193         /// 批量修改并保存
    194         /// </summary>
    195         /// <param name="model">要修改的实体对象</param>
    196         /// <param name="whereLambda">查询条件</param>
    197         /// <param name="proNames">要修改的 属性 名称</param>
    198         /// <returns>受影响的行数</returns>
    199         protected int ModifyByAndSave(T model, Expression<Func<T, bool>> whereLambda, params string[] modifiedProNames)
    200         {
    201             ModifyBy(model, whereLambda, modifiedProNames);
    202             return db.SaveChanges();
    203         } 
    204         #endregion
    205 
    206         #region 4.0根据条件获取记录条数 + int GetCountBy(Expression<Func<T, bool>> whereLambda)
    207         /// <summary>
    208         /// 根据条件获取记录条数
    209         /// </summary>
    210         /// <returns>总记录条数</returns>
    211         protected int GetCountBy(Expression<Func<T, bool>> whereLambda)
    212         {
    213             return db.Set<T>().Where(whereLambda).Count();
    214         } 
    215         #endregion
    216 
    217         #region 5.0获取所有记录 + List<T> GetAllList()
    218         /// <summary>
    219         /// 获取所有记录
    220         /// </summary>
    221         /// <returns>返回的集合</returns>
    222         protected List<T> GetAllList()
    223         {
    224             return db.Set<T>().ToList();
    225         } 
    226         #endregion
    227 
    228         #region 5.1根据条件查询 + List<T> GetListBy(Expression<Func<T, bool>> whereLambda)
    229         /// <summary>
    230         /// 根据条件查询
    231         /// </summary>
    232         /// <param name="whereLambda">条件Lambda表达式</param>
    233         /// <returns>返回的集合</returns>
    234         protected List<T> GetListBy(Expression<Func<T, bool>> whereLambda)
    235         {
    236             return db.Set<T>().Where(whereLambda).ToList();
    237         } 
    238         #endregion
    239 
    240         #region 5.2根据条件 排序 和查询 + List<T> GetListBy<TKey>(Expression<Func<T, bool>> whereLambda, Expression<Func<T, TKey>> orderLambda, bool IsDes = false)
    241         /// <summary>
    242         /// 根据条件 排序 和查询
    243         /// </summary>
    244         /// <typeparam name="TKey">排序字段类型</typeparam>
    245         /// <param name="whereLambda">查询条件 lambda表达式</param>
    246         /// <param name="orderLambda">排序条件 lambda表达式</param>
    247         /// // <param name="IsDes">是否逆序</param>
    248         /// <returns>返回的集合</returns>
    249         protected List<T> GetListBy<TKey>(Expression<Func<T, bool>> whereLambda, Expression<Func<T, TKey>> orderLambda, bool IsDes = false)
    250         {
    251             if(IsDes)
    252                 return db.Set<T>().Where(whereLambda).OrderByDescending(orderLambda).ToList();
    253             return db.Set<T>().Where(whereLambda).OrderBy(orderLambda).ToList();
    254         } 
    255         #endregion
    256 
    257         #region 5.3分页查询 + List<T> GetPagedList<TKey>(int pageIndex, int pageSize, Expression<Func<T, bool>> whereLambda, Expression<Func<T, TKey>> orderBy, bool IsDes = false)
    258         /// <summary>
    259         /// 分页查询
    260         /// </summary>
    261         /// <param name="pageIndex">页码</param>
    262         /// <param name="pageSize">页容量</param>
    263         /// <param name="whereLambda">条件 lambda表达式</param>
    264         /// <param name="orderBy">排序 lambda表达式</param>
    265         /// <param name="IsDes">是否逆序</param>
    266         /// <returns>返回的集合</returns>
    267         protected List<T> GetPagedList<TKey>(int pageIndex, int pageSize, Expression<Func<T, bool>> whereLambda, Expression<Func<T, TKey>> orderBy, bool IsDes = false)
    268         {
    269             if (IsDes)
    270                 return db.Set<T>().Where(whereLambda).OrderByDescending(orderBy).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
    271             return db.Set<T>().Where(whereLambda).OrderBy(orderBy).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
    272         } 
    273         #endregion
    274 
    275     }
    276 }
    View Code

       可以看出,在上面的代码中,我提供了增删改查的大部分方法,对于写入性的操作,我提供了是否立刻SaveChange的选择,如果立刻save,可以调用类似于AddAndSave()这样的方法,如果想多次调用后统一保存以提高性能,可以调用Add()这类方法,在所有操作结束后,再调用saveChange的方法。这个帮助类中存在一个DbContext类型的属性,它用来存放ef上下文,在teacher的实现类中,提供了它的构造方法,将dbcontext传入。帮助类中几乎所有的操作都依赖于这个DbContext。

      上面teacher的接口和实现都是有partial修饰,是一个部分类(接口),这样做的目的是为了便于管理,例如日后需要添加一个学生类时可以这样

     1     public partial class Student : BaseCore<Entity.Student>, ICore.IStudent
     2     {
     3         public Student(DbContext dbContext)
     4         {
     5             db = dbContext;
     6         }
     7     }
     8 
     9     public partial class Teacher : BaseCore<Entity.Teacher>, ICore.ITeacher
    10     {
    11         public Teacher(DbContext dbContext)
    12         {
    13             db = dbContext;
    14         }
    15     }

      这些代码是重复的,可将它们写在同一个cs中,如果有需要可以用T4模板自动生成,但事实上并不是每张表都需要生成对应的实体,所以我选择手动来添加它们。教师和学生具体的登陆的逻辑可能不同,将它们放在另一个partial类中会更加合理。

      4.创建教师的部分接口和部分类

      接口如下 

     1     public partial interface ITeacher
     2     {
     3         #region 教师登录 + ReturnVal Login(string tid, string pwd); 
     4         /// <summary>
     5         /// 教师登录
     6         /// </summary>
     7         /// <param name="tid">教师id</param>
     8         /// <param name="pwd">密码</param>
     9         /// <returns>约定返回类型</returns>
    10         ReturnVal Login(string tid, string pwd); 
    11         #endregion
    12     }

      实现如下

     1 public partial class Teacher
     2     {
     3 
     4         #region 教师登录操作 + WebModel.ReturnVal Login(string tid, string pwd)
     5         /// <summary>
     6         /// 教师登录操作
     7         /// </summary>
     8         /// <param name="tid">教师登录名</param>
     9         /// <param name="pwd">密码</param>
    10         /// <returns>约定返回类</returns>
    11         public WebModel.ReturnVal Login(string tid, string pwd)
    12         {
    13             int iTID = Convert.ToInt32(tid);
    14             Entity.Teacher teacher = this.GetListBy(t => (t.TID == iTID) && (t.IsDel == false)).ToList().FirstOrDefault();
    15             if (teacher == null)
    16             {
    17                 return new ReturnVal(ReturnStatu.Failure, "用户不存在");
    18             }
    19             else
    20             {
    21                 if (EDUA_Util.EncrypHelper.MD5(pwd) == teacher.Password)
    22                 {
    23                     return new ReturnVal(ReturnStatu.Success, "登陆成功", WebModel.Teacher.ToWebModel(teacher));
    24                 }
    25                 else
    26                 {
    27                     return new ReturnVal(ReturnStatu.Failure, "密码错误");
    28                 }
    29             }
    30         }  
    31         #endregion
    32     }

      很简单,首先判断用户是否存在,接下去判断密码是否正确。

      第13行,这里我使用了我的basecore里的方法,如果不想用也很简单。

      返回值类型为ReturnVal,这是我自己的类,原因是不能简单地用一个bool值来传递登陆成功与否,如果登陆成功了需要将对象返回保存在cookie,session中,以保证状态的维持。ReturnVal也会被用在其他core与web传递数据的过程中。ReturnVal类如下

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace WebModel
     8 {
     9     /// <summary>
    10     /// 返回值约定
    11     /// 从core 到 web 返回内容的封装
    12     /// </summary>
    13     public class ReturnVal
    14     {
    15         #region 属性
    16         /// <summary>
    17         /// 返回的状态
    18         /// </summary>
    19         public ReturnStatu Statu { get; set; }
    20         /// <summary>
    21         /// 返回的消息
    22         /// </summary>
    23         public string Message { get; set; }
    24         /// <summary>
    25         /// 返回的数据
    26         /// </summary>
    27         public object Data { get; set; } 
    28         #endregion
    29 
    30         #region 构造方法
    31         /// <summary>
    32         /// 构造方法
    33         /// </summary>
    34         /// <param name="statu">状态</param>
    35         public ReturnVal(ReturnStatu statu)
    36         {
    37             this.Statu = statu;
    38         }
    39         /// <summary>
    40         /// 构造方法
    41         /// </summary>
    42         /// <param name="statu">状态</param>
    43         /// <param name="message">消息</param>
    44         public ReturnVal(ReturnStatu statu, string message)
    45             : this(statu)
    46         {
    47             this.Message = message;
    48         }
    49         /// <summary>
    50         /// 构造方法
    51         /// </summary>
    52         /// <param name="statu">状态</param>
    53         /// <param name="message">消息</param>
    54         /// <param name="data">数据</param>
    55         public ReturnVal(ReturnStatu statu, string message, object data)
    56             : this(statu, message)
    57         {
    58             this.Data = data;
    59         } 
    60         #endregion
    61     }
    62 
    63 
    64     /// <summary>
    65     /// 状态枚举
    66     /// </summary>
    67     public enum ReturnStatu
    68     {
    69         /// <summary>
    70         /// 成功
    71         /// </summary>
    72         Success,
    73         /// <summary>
    74         /// 失败
    75         /// </summary>
    76         Failure,
    77         /// <summary>
    78         /// 错误
    79         /// </summary>
    80         Err
    81     }
    82 }
    View Code

      ReturnVal在WebModel程序集下,同样在该程序集下的还有上面用到的WebModel.Teacher。按照常理,EF和View之间存在着Core层,故View不可直接依赖于EF,所以它们之间需要一层WebModel来传递。WebModel的存在类似于DTO,它可以剥离那些上层中用不到的字段,以下是我的WebModel中的Teacher类,为了方便,里面提供了将实体类转换为WebModel类的静态方法,也是上面所用到的。

     1 namespace WebModel
     2 {
     3     public class Teacher
     4     {
     5         #region 属性
     6         /// <summary>
     7         /// guid
     8         /// </summary>
     9         public System.Guid ID { get; set; }
    10         /// <summary>
    11         /// 学号
    12         /// </summary>
    13         public int TID { get; set; }
    14         /// <summary>
    15         /// 姓名
    16         /// </summary>
    17         public string Name { get; set; }
    18         /// <summary>
    19         /// 权限列表
    20         /// </summary>
    21         public List<Authority> AuthorityList { get; set; }
    22         #endregion
    23 
    24         #region 转化为视图类的teacher + static Teacher ToWebModel(Entity.Teacher et)
    25         /// <summary>
    26         /// 转化为视图类的teacher
    27         /// </summary>
    28         /// <param name="es">实体类</param>
    29         /// <returns>视图类</returns>
    30         public static Teacher ToWebModel(Entity.Teacher et)
    31         {
    32             List<Entity.AuthorityToPower> Listatp = et.Power.AuthorityToPowers.ToList();
    33             List<Authority> ListAut = new List<Authority>();
    34             Listatp.ForEach(au => {
    35                 ListAut.Add(Authority.ToWebModel(au.Authority));
    36             });
    37             return new Teacher()
    38             {
    39                 Name = et.Name,
    40                 TID = et.TID,
    41                 ID = et.ID,
    42                 AuthorityList = ListAut
    43             };
    44         }
    45         #endregion
    46     }

      上面还用到了类似于EDUA_Util.EncrypHelper.MD5这类MD5加密算法,我将它们放到工具类中。它们在不同的项目中可以完全复用,类似这样的方法还有加密解密cookie,生随机数(封装过),生成验证码,导入导出Excel等等。将它们统统放到Util中还可以将很多第三方的引用添加到这个程序集中,保证上层程序集的整洁,它们是整个项目的Infrastructure(基础设施)。

      5.在ICoreSession,CoreSession中分别创建Teacher类

      上一篇中提到过,在web中的控制器中可以调用到iCoreSession,所以想要在web层调用core中teacher的login方法,就需要在ICoreSession中存在teacher对象。故接口中的代码如下

    1     public interface ICoreSession
    2     {
    3         ITeacher ITeacher { get; }
    4     }

      CoreSession中的代码如下,这样保证了在一次请求中teacher的单例,通过构造方法将db对象传入到teacher类中。

     1     public class CoreSession:EDUA_ICore.ICoreSession
     2     {
     3 
     4         #region 属性
     5         private DbContext db { get; set; }
     6         #endregion
     7 
     8         #region 构造方法
     9         public CoreSession()
    10         {
    11             db = new Entity.EDUAEntities();
    12         }  
    13         #endregion
    14 
    15         #region 保存 + int SaveChanges()
    16         /// <summary>
    17         /// 保存修改
    18         /// </summary>
    19         /// <returns>受影响的行数</returns>
    20         public int SaveChanges()
    21         {
    22             return db.SaveChanges();
    23         } 
    24         #endregion
    25 
    26         ITeacher iTeacher;
    27         public ITeacher ITeacher
    28         {
    29             get
    30             {
    31                 if (iTeacher == null)
    32                 {
    33                     iTeacher = new Teacher(db);
    34                 }
    35                 return iTeacher;
    36             }
    37         }
    38     }

       6.创建Login页面

      控制器

    #region 1.0 登陆界面
    [HttpGet]
    public ActionResult Login()
    {
        return View();
    } 
    #endregion

      页面为强类型页面,使用了微软的数据验证,所以需要导入微软所提供的js @Scripts.Render("~/Scripts/mvcAjax")  使用App_Statr中的BundleConfig进行了绑定。

      

      视图中的类型类为WebModel.LoginUser,它同样放在webmodel程序集下的,我单独创建了ViewModel文件夹用来存放这些类,其实将它们放在web层也是合理的。对应的代码以及页面如下。

     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel.DataAnnotations;
     4 using System.Linq;
     5 using System.Web;
     6 
     7 namespace WebModel
     8 {
     9 
    10     /// <summary>
    11     /// 登陆视图 模型
    12     /// </summary>
    13     public class LoginUser
    14     {
    15         /// <summary>
    16         /// 用户名
    17         /// </summary>
    18         [Required(ErrorMessage = "用户名不能为空")]
    19         public int LoginName { get; set; }
    20         /// <summary>
    21         /// 密码
    22         /// </summary>
    23         [Required(ErrorMessage = "密码不能为空")]
    24         public string Pwd { get; set; }
    25         /// <summary>
    26         /// 验证码
    27         /// </summary>
    28         [Required(ErrorMessage = "请输入验证码")]
    29         public string VCode { get; set; }
    30         /// <summary>
    31         /// 身份 1 为教师 0为学生
    32         /// </summary>
    33         [Required(ErrorMessage = "请输选择身份")]
    34         public int Degree { get; set; }
    35         /// <summary>
    36         /// 是否记住
    37         /// </summary>
    38         public bool IsAlways { get; set; }
    39     }
    40 
    41 }
    @model WebModel.LoginUser
    @{
        Layout = null;
    }
    <html>
    <head>
        <title>登陆</title>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width" />
        @Scripts.Render("~/Scripts/mvcAjax")
        <style type="text/css">
            .p_main {
                margin-left: auto;
                margin-right: auto;
                width: 400px;
                margin-top: 45px;
            }
    
            .SingleLine {
                padding-top: 10px;
            }
    
            .alert {
                color: red;
            }
    
            #divMsg {
                display: none;
            }
        </style>
        <script type="text/javascript">
            $(function () {
                $("#img_Vcode").click(function () {
                    newVcode();
                });
            });
            //请求一个新的验证码
            function newVcode() {
                $("#img_Vcode").attr("src", "/helper/VCode/" + Math.round(Math.random() * 100000));
            }
    
            function Success(jsDate) {
                if (jsDate.Statu == "err") {
                    $("#td_msg").html(jsDate.Msg);
                    newVcode();
                }
                else if (jsDate.Statu == "ok") {
                    window.location.href = jsDate.BackUrl;
                }
            }
        </script>
    </head>
    <body>
        <div class="p_main">
                <div class="div_main">
                    @using (Ajax.BeginForm(new AjaxOptions()
        {
            HttpMethod = "post",
            OnSuccess = "Success",
            LoadingElementId = "divMsg"
        }))
                    {
                        <div class="SingleLine">
                            <div style="float:left;80px;font-size:15px">登陆身份:</div>
                            <div>
                                <input type="radio" name="Degree" id="Degree0" value="0"><label for="Degree0">学生</label>
                                <input type="radio" name="Degree" id="Degree1" value="1" checked="checked"><label for="Degree1">教师</label>
                            </div>
                        </div>
                        <div style="clear:both"></div>
                        <div class="SingleLine">
                            <div style="float:left;80px;font-size:15px">用户名:</div>
                            <div style="float:left">@Html.TextBoxFor(u => u.LoginName)</div>
                            <div style="float:left" class="alert">@Html.ValidationMessageFor(u => u.LoginName)</div>
                        </div>
                        <div style="clear:both"></div>
                        <div class="SingleLine">
                            <div style="float:left;80px;font-size:15px">密码:</div>
                            <div style="float:left">@Html.PasswordFor(u => u.Pwd)</div>
                            <div style="float:left" class="alert">@Html.ValidationMessageFor(u => u.Pwd)</div>
                        </div>
                        <div style="clear:both"></div>
    
                        <div class="SingleLine">
                            <div style="float:left;80px;font-size:15px">验证码:</div>
                            <div style="float:left">@Html.TextBoxFor(u => u.VCode)</div>
                            <div style="float:left"><img id="img_Vcode" src="/helper/VCode"></div>
                            <div style="float:left" class="alert">@Html.ValidationMessageFor(u => u.VCode)</div>
                        </div>
                        <div style="clear:both"></div>
                        
                        <div class="SingleLine">
                            <div style="float:left;padding-right:100px;">@Html.CheckBoxFor(u => u.IsAlways) <span>两小时内免登陆</span></div>
                            <div style="float:left"><input type="submit" value="登陆" />
                            <div id="divMsg">登陆中~~~</div></div> 
                            <div id="td_msg" class="alert"></div>                    
                        </div>
                    }
                </div>
        </div>
    </body>
    </html>

      实际的项目中,在登录时选择登陆身份,有教师或学生可选,它们公用一个登陆入口,在控制器中根据页面传回来的信息选择调用teacher的login方法或者是student的login方法。前台我用了EasyUI。

      7.控制器中的登陆处理

      在控制器中,通过调用ICoreSession中teacher的login方法来进行。

        a.判断验证码是否正确,如果错误直接返回验证码错误的json给页面

        b.判断用户所选择的登陆身份(学生的没有写)

        c.调用core中teacher的登陆方法,传入用户名和密码

        d.根据返回的ReturnVal判断登陆的状态,如果成功写入Session

        e.判断是否需要写入cookie,如有需要,则写入

        f.跳转到对应的页面

     1         #region 1.1 登录操作
     2         [HttpPost]
     3         public ActionResult Login(WebModel.LoginUser userInfo)
     4         {
     5             //判断验证码 为方便测试用0可跳过
     6             OperateHelper.BussinessHelper h = new OperateHelper.BussinessHelper(iCoreSession);
     7             if (((h.Vcode).ToLower() != (userInfo.VCode).ToLower()) && (userInfo.VCode != "0"))
     8             {
     9                 return WebModel.JsonModel.AjaxMsgModel.RedirectAjax("err", "验证码错误", "", "");
    10             }
    11             else
    12             {
    13                 //学生
    14                 if (userInfo.Degree == 0)
    15                 {
    16                    //里面是对应学生的登陆操作
    17                 }
    18                 //教师
    19                 else if (userInfo.Degree == 1)
    20                 {
    21                     ReturnVal rv = iCoreSession.ITeacher.Login(userInfo.LoginName.ToString(), userInfo.Pwd);
    22                     if (rv.Statu == ReturnStatu.Success)
    23                     {
    24                         h.TeacherSession = rv.Data as WebModel.Teacher;
    25                         //保存cookie
    26                         if (userInfo.IsAlways)
    27                         {
    28                             h.TeacherTIDCookie = (rv.Data as WebModel.Teacher).ID.ToString();
    29                         }
    30                         else
    31                         {
    32                             h.TeacherTIDCookie = "";
    33                         }
    34                         return WebModel.JsonModel.AjaxMsgModel.RedirectAjax("ok", rv.Message, "", "/teacher/teacherhome/index");
    35                     }
    36                     else
    37                     {
    38                         return WebModel.JsonModel.AjaxMsgModel.RedirectAjax("err", rv.Message, "", "");
    39                     }
    40                 }
    41                 else
    42                 {
    43                     return null;
    44                 }
    45             } 
    46         #endregion

    写在最后

      至此,登陆功能算是完成了,但没有对用户访问权限的过滤,登陆操作就没有任何意义。所以在下一篇中,我将会通过AuthorizeAttribute来实现用户权限的过滤。这样,一个最基本的架构才算形成。

    转载请注明出处 huhuhuo的博客园

    地址:http://www.cnblogs.com/linhan/p/4298971.html

  • 相关阅读:
    MOF编译器无法连接VMI服务器。原因可能是语义错误的解决方案
    【原】Sql Server 2008---安装时卸载Visual Studio
    SQL SERVER 删除前判断指定的表或者存储过程是否存在
    NPOI 表头、页眉页脚重复设置
    在vs2010中显示代码的行数
    【summary】JQuery 相关css、ajax、数据操作函数或方法
    CSS自适应的占位符效果
    NPOI 生成 excel基本设置
    JavaSE——转换流和缓冲流
    javaSE——字符流
  • 原文地址:https://www.cnblogs.com/linhan/p/4298971.html
Copyright © 2011-2022 走看看