ASP.NET MVC+EF框架+EasyUI实现权限管理系列(11)-验证码实现和底层修改

  1. 云栖社区>
  2. 博客>
  3. 正文

ASP.NET MVC+EF框架+EasyUI实现权限管理系列(11)-验证码实现和底层修改

杰克.陈 2015-01-21 08:50:00 浏览1367
展开阅读全文
原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(11)-验证码实现和底层修改

   ASP.NET MVC+EF框架+EasyUI实现权限管系列

  

   (开篇)   (1):框架搭建    (2):数据库访问层的设计Demo    (3):面向接口编程   (4 ):业务逻辑层的封装 

   (5):前台Jquery easyUI实现    (6):EF上下文实例管理    (7):DBSession的封装   (8):DBSession线程内唯一  

   (9):TT摸版的学习   (10):VSS源代码管理

  前言:上篇博客我们简单的说了一下源代码管理工具(VSS)的使用,相信大家看完之后都能够会使用VSS源代码管理工具,在源代码管理工具中VSS算是最简单的,没有什么难度,就是重点理解签入,签出和回滚的含有以及如何操作。那么这篇博客我们开始讲述如何实现用户的登录以及对前面博友们的评论提出修改底层的东西进行了一次修改还有验证码的使用。那么下面我首先要说的是前面网友提出的一个小的修改。

1.Func<T, bool>和Expression<Func<T, bool>>的使用区别

  (1)在前面我写ASP.NET MVC+EF框架+EasyUI实现权限管理系列(4)-业务逻辑曾的封装(http://www.cnblogs.com/hanyinglong/archive/2013/04/09/3011119.html)这篇博客的时候,有一位博友(@Qlin)提出了我在项目底层些查询的时候为什么不用Expression<Func<T,bool>>,因为当时我实现的代码是Func<T,bool> wherelambda来定义的,当时的代码如下:

 1         //实现对数据库的查询  --简单查询
 2         IQueryable<T> LoadEntities(Func<T, bool> whereLambda);
 3 
 4         /// <summary>
 5         /// 实现对数据的分页查询
 6         /// </summary>
 7 
 8         /// <typeparam name="S">按照某个类进行排序</typeparam>
 9 
10         /// <param name="pageIndex">当前第几页</param>
11 
12         /// <param name="pageSize">一页显示多少条数据</param>
13 
14         /// <param name="total">总条数</param>
15 
16         /// <param name="whereLambda">取得排序的条件</param>
17 
18         /// <param name="isAsc">如何排序,根据倒叙还是升序</param>
19 
20         /// <param name="orderByLambda">根据那个字段进行排序</param>
21 
22         /// <returns></returns>
23 
24         IQueryable<T> LoadPageEntities<S>(int pageIndex, int pageSize, out int total, Func<T, bool> whereLambda,  bool isAsc, Func<T, S> orderByLambda);

  (2)那么根据那位博友提出来的意见,我查看资料,发现他们还真的有很大的区别,这里我就简单的说一下他们的区别,并且非常感谢博友们能提出这样的问题,希望广大博友们能真心的提出来项目中的问题,我将虚心接受。

  (3)那么他们有什么区别呢?网上的资料是这样说的,Func<T,bool>本身就是一个委托(delegate),而Expression<Func<T,bool>>确实一个表达式,只有在编译之后才会变成委托,那么在EF中到底使用哪一个呢?又是为什么呢?其实如果我们写成Func<T,bool>类型的便来那个如果作为参数传递给where方法进行Linq查询时,Entity FrameWork将会产生全表查询,将整个数据库表忠的数据加载到内存中,然后再内存中根据where中的条件进一步查询,而Expression<Func<t,bool>>只是查询出来你where条件中的数据,不用去进行全表查询,所以我们修改后的代码是:   

 1  //实现对数据库的查询  --简单查询
 2 
 3         IQueryable<T> LoadEntities(Expression<Func<T, bool>> whereLambda);
 4 
 5         /// <summary>
 6 
 7         /// 实现对数据的分页查询
 8 
 9         /// </summary>
10 
11         /// <typeparam name="S">按照某个类进行排序</typeparam>
12 
13         /// <param name="pageIndex">当前第几页</param>
14 
15         /// <param name="pageSize">一页显示多少条数据</param>
16 
17         /// <param name="total">总条数</param>
18 
19         /// <param name="whereLambda">取得排序的条件</param>
20 
21         /// <param name="isAsc">如何排序,根据倒叙还是升序</param>
22 
23         /// <param name="orderByLambda">根据那个字段进行排序</param>
24 
25         /// <returns></returns>
26 
27         IQueryable<T> LoadPageEntities<S>(int pageIndex, int pageSize, out int total, Expression<Func<T, bool>> whereLambda,
28 
29                                           bool isAsc, Expression<Func<T, S>> orderByLambda);

  (4)上面我们简单的介绍了一下Func<T, bool>和Expression<Func<T, bool>>的使用区别,我查到了就这些资料,如果那位博友还能够详细的说明的话,真心希望你在下面留言,我将非常的感谢你们。我参考的资料是:http://www.cnblogs.com/dudu/archive/2012/04/01/enitity_framework_func.html

  (5)综上所述的话,这时候我们就要对我们项目中数据库访问层,数据库访问接口层,业务逻辑层和业务逻辑接口层的查询方法都进行修改,这里就不多说了,和上面的基本差不多。

2.登录页面的设计

  (1)首先我们到网上下载一个登录页面的Demo,然后经过修改之后放到我们MVC4的项目里面。

  (2)然后我们在项目中添加一个LoginController控制器,然后再在Index上面添加一个空视图,最后我们将我们前面下载的Demo中的代码部署到Index.cshtml页面之上,最后生成的静态页面如图所示:

   

  (3)这时候我们就把静态页面设计好了,这里静态页面的代码我就不往出来贴了,在后面我会把主要的代码写出来的并且共享整个项目的,那么下来我们看到了我们的验证码没有实现,只是一个假的图标在哪里,这时候我们开始着手验证码的设计。

3.如何设计验证码的实现

  (1)通过上图我们看到现在我们已经实现了页面的展示,那么我们的验证码还没有,现在开始我们设计验证码,首先看我前台验证码这里的代码是:

 1 <ul>
 2 
 3    <li class="user_main_text">验证码: </li>
 4 
 5    <li class="user_main_input">
 6 
 7        <input type="text" class="TxtPasswordCssClass" id="Code" name="Code">
 8 
 9    </li>
10 
11 </ul>
12 
13 <ul>
14 
15    <li class="user_main_text">验证码: </li>
16 
17    <li class="user_main_input">
18 
19 <img src="/Login/CheckCode?ID=1" id="imgCode" alt="单击可刷新" onclick="ClickRemoveChangeCode()"  />
20 
21 <a href="javascript:void(0)" onclick="ClickRemoveChangeCode();return false;">看不清</a>
22 
23     </li>
24 
25 </ul>

  (2)首先我们看到我们绑定验证码的这里是这样写的,<img src=”/Login/CheckCode?ID=1”>,那么前面的src绑定的地址什么意思呢?他的意思就是我们在Login控制器下面含有一个CheckCode方法来实现验证码的读取。

  (3)我们要实现验证码,首先我们就要写一个生成验证码的类,没什么难度,网上一搜一大推,下面就是我封装的生成验证码的类,首先我们在LYZJ.UserLimitMVC.Common类库下面新建一个KenceryValidateCode.cs类来存放生成验证码的代码,在这里我们需要给类库引入命名空间System.Drawing。最终的代码如下:

  1 namespace LYZJ.UserLimitMVC.Common
  2 
  3 {
  4 
  5     public class KenceryValidateCode
  6 
  7     {
  8 
  9         /// <summary>
 10 
 11         /// 验证码的最大长度
 12 
 13         /// </summary>
 14 
 15         public int MaxLength
 16 
 17         {
 18 
 19             get { return 10; }
 20 
 21         }
 22 
 23  
 24 
 25         /// <summary>
 26 
 27         /// 验证码的最小长度
 28 
 29         /// </summary>
 30 
 31         public int MinLength
 32 
 33         {
 34 
 35             get { return 1; }
 36 
 37         }
 38 
 39  
 40 
 41         /// <summary>
 42 
 43         /// 生成验证码
 44 
 45         /// </summary>
 46 
 47         /// <param name="length">指定验证码的长度</param>
 48 
 49         /// <returns></returns>
 50 
 51         public string CreateValidateCode(int length)
 52 
 53         {
 54 
 55             int[] randMembers = new int[length];
 56 
 57             int[] validateNums = new int[length];
 58 
 59             string validateNumberStr = "";
 60 
 61             //生成起始序列值
 62 
 63             int seekSeek = unchecked((int) DateTime.Now.Ticks);
 64 
 65             Random seekRand = new Random(seekSeek);
 66 
 67             int beginSeek = (int) seekRand.Next(0, Int32.MaxValue - length*10000);
 68 
 69             int[] seeks = new int[length];
 70 
 71             for (int i = 0; i < length; i++)
 72 
 73             {
 74 
 75                 beginSeek += 10000;
 76 
 77                 seeks[i] = beginSeek;
 78 
 79             }
 80 
 81             //生成随机数字
 82 
 83             for (int i = 0; i < length; i++)
 84 
 85             {
 86 
 87                 Random rand = new Random(seeks[i]);
 88 
 89                 int pownum = 1*(int) Math.Pow(10, length);
 90 
 91                 randMembers[i] = rand.Next(pownum, Int32.MaxValue);
 92 
 93             }
 94 
 95             //抽取随机数字
 96 
 97             for (int i = 0; i < length; i++)
 98 
 99             {
100 
101                 string numStr = randMembers[i].ToString();
102 
103                 int numLength = numStr.Length;
104 
105                 Random rand = new Random();
106 
107                 int numPosition = rand.Next(0, numLength - 1);
108 
109                 validateNums[i] = Int32.Parse(numStr.Substring(numPosition, 1));
110 
111             }
112 
113             //生成验证码
114 
115             for (int i = 0; i < length; i++)
116 
117             {
118 
119                 validateNumberStr += validateNums[i].ToString();
120 
121             }
122 
123             return validateNumberStr;
124 
125         }
126 
127  
128 
129         //C# MVC 升级版
130 
131         /// <summary>
132 
133         /// 创建验证码的图片
134 
135         /// </summary>
136 
137         /// <param name="containsPage">要输出到的page对象</param>
138 
139         /// <param name="validateNum">验证码</param>
140 
141         public byte[] CreateValidateGraphic(string validateCode)
142 
143         {
144 
145             Bitmap image = new Bitmap((int) Math.Ceiling(validateCode.Length*12.0), 22);
146 
147             Graphics g = Graphics.FromImage(image);
148 
149             try
150 
151             {
152 
153                 //生成随机生成器
154 
155                 Random random = new Random();
156 
157                 //清空图片背景色
158 
159                 g.Clear(Color.White);
160 
161                 //画图片的干扰线
162 
163                 for (int i = 0; i < 25; i++)
164 
165                 {
166 
167                     int x1 = random.Next(image.Width);
168 
169                     int x2 = random.Next(image.Width);
170 
171                     int y1 = random.Next(image.Height);
172 
173                     int y2 = random.Next(image.Height);
174 
175                     g.DrawLine(new Pen(Color.Silver), x1, y1, x2, y2);
176 
177                 }
178 
179                 Font font = new Font("Arial", 12, (FontStyle.Bold | FontStyle.Italic));
180 
181                 LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height),
182 
183                                                                     Color.Blue, Color.DarkRed, 1.2f, true);
184 
185                 g.DrawString(validateCode, font, brush, 3, 2);
186 
187                 //画图片的前景干扰点
188 
189                 for (int i = 0; i < 100; i++)
190 
191                 {
192 
193                     int x = random.Next(image.Width);
194 
195                     int y = random.Next(image.Height);
196 
197                     image.SetPixel(x, y, Color.FromArgb(random.Next()));
198 
199                 }
200 
201                 //画图片的边框线
202 
203                 g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1);
204 
205                 //保存图片数据
206 
207                 MemoryStream stream = new MemoryStream();
208 
209                 image.Save(stream, ImageFormat.Jpeg);
210 
211                 //输出图片流
212 
213                 return stream.ToArray();
214 
215             }
216 
217             finally
218 
219             {
220 
221                 g.Dispose();
222 
223                 image.Dispose();
224 
225             }
226 
227         }
228 
229  
230 
231         /// <summary>
232 
233         /// 得到验证码图片的长度
234 
235         /// </summary>
236 
237         /// <param name="validateNumLength">验证码的长度</param>
238 
239         /// <returns></returns>
240 
241         public static int GetImageWidth(int validateNumLength)
242 
243         {
244 
245             return (int) (validateNumLength*12.0);
246 
247         }
248 
249  
250 
251         /// <summary>
252 
253         /// 得到验证码的高度
254 
255         /// </summary>
256 
257         /// <returns></returns>
258 
259         public static double GetImageHeight()
260 
261         {
262 
263             return 22.5;
264 
265         }
266 
267     }
268 
269 }

  (4)那么现在我们的验证码生成的类已经完成了,这时候我们根据<img src=”/Login/CheckCode?ID=1”>所知,我们要到Login控制器下面去创建CheckCode方法来实现能够从View层读取验证码显示出来,那么必然在我们项目当中women就要用到刚才定义的获取验证码的类,那么这时候women就要添加LYZJ.UserLimitMVC.Common的引用,这时候在Login控制器下面的读取验证码的方法代码如下:

 1        /// <summary>
 2 
 3         /// 验证码的实现
 4 
 5         /// </summary>
 6 
 7         /// <returns></returns>
 8 
 9         public ActionResult CheckCode()
10 
11         {
12 
13             //首先实例化验证码的类
14 
15             KenceryValidateCode validateCode = new KenceryValidateCode();
16 
17             //生成验证码指定的长度
18 
19             string code = validateCode.CreateValidateCode(5);
20 
21             //将验证码赋值给Session变量
22 
23             Session["ValidateCode"] = code;
24 
25             //创建验证码的图片
26 
27             byte[] bytes = validateCode.CreateValidateGraphic(code);
28 
29             //最后将验证码返回
30 
31             return File(bytes, @"image/jpeg");
32 
33         }

  (5)根据上面的代码,我们就实现了能够在前台显示验证码的功能,这里我就不详细的解释代码了,我在代码里面写了大量的注释,相信大家能够很容易的明白代码的意思,效果如图所示:

         

  (6)那么这时候我们就有一个问题出现了,我们的验证码有时候可能看不清,当我们要单击”验证码本身”或者”看不清,换一张”的时候要能够动态的变化,下面我就简单介绍一下动态的变化验证码。

4.单击验证码的时候验证码随机获取

  (1)当我们想要单击”验证码本身”或者”看不清,换一张”的字眼的时候我们就要实施的刷新一下验证码,那么我们看到我们在页面的HTML代码中就有一个javaScript的Clieck事件,<img src="/Login/CheckCode?ID=1" id="imgCode" alt="单击可刷新" onclick="ClickRemoveChangeCode()"  /> ,最后我们只要使用JavaScript实现onClick事件的ClickRemoveChangeCode()方法,使用JavaScript实现此事件的方法如下:

 1      @*引用Jquery文件的JS脚本*@
 2 
 3         <script src="~/Scripts/jquery-1.7.1.min.js"></script>
 4 
 5         <script type="text/javascript">
 6 
 7             //单击重新改变验证码
 8 
 9             function ClickRemoveChangeCode() {
10 
11                 //首先我们获取到验证码的路径
12 
13                 var code = $("#imgCode").attr("src");
14 
15                 //然后重新给验证码的路径赋值
16 
17                 $("#imgCode").attr("src", code + "1");
18 
19             }
20 
21         </script>

  (2)这样我们的验证码就实现了,当然还有一些小样式的修改我就不说了,比如当鼠标移动上去的时候能够变成小手等。

  (3)那么下篇博客我们将实现用户的登录,越往后面的话我会越说的简单,这些东西都不怎么难,如果大家不太清楚的话,可以留言或者加QQ群,我将很高兴为我们解决问题。

  (4)最后在秀一下今天完成的验证码的功能,本来打算把登录一起写的,可是就验证码写了这么多,想想还是把登录放后面和写T4模版一起说吧。

     

  

  Kencery返回本系列开篇

  

网友评论

登录后评论
0/500
评论
杰克.陈
+ 关注