ASP.NET MVC+EF框架+EasyUI實現權限管系列
(開篇) (1):框架搭建 (2):數據庫訪問層的設計Demo (3):面向接口編程 (4 ):業務邏輯層的封裝
(5):前台Jquery easyUI實現 (6):EF上下文實例管理 (7):DBSession的封裝 (8):DBSession線程內唯一
前言:上篇博客我們簡單的說了一下源代碼管理工具(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模版一起說吧。
源碼下載
(1):完整源碼下載
Kencery返回本系列開篇