愛上MVC3系(xi)列~無刷新驗(yan)證碼
在MVC中進(jin)行留言,評(ping)論(lun)等功能時(shi)(shi),不可避免會用到(dao)表(biao)單提交(jiao)時(shi)(shi)的驗證碼問題,有時(shi)(shi),我們的作法是(shi),當表(biao)單被(bei)提交(jiao)后,在controller里(li)去(qu)判斷驗證碼的正(zheng)確(que)與否,但我認(ren)為這種用戶體驗是(shi)很(hen)差的,今天(tian)正(zheng)好有后時(shi)(shi)間(jian),把這方(fang)法的東(dong)西總結一(yi)下:
首(shou)先,在公用項目中建立一(yi)個生成圖片驗證碼的類型ValidateCode,代碼如下:
1 /// <summary> 2 /// 生成驗證(zheng)碼對象 3 /// </summary> 4 public class ValidateCode 5 { 6 public ValidateCode() 7 { 8 } 9 ///<summary> 10 /// 驗證碼(ma)的最大長(chang)度 11 ///</summary> 12 public int MaxLength 13 { 14 get { return 10; } 15 } 16 ///<summary> 17 /// 驗證碼的最(zui)小(xiao)長度 18 ///</summary> 19 public int MinLength 20 { 21 get { return 1; } 22 } 23 ///<summary> 24 /// 生(sheng)成(cheng)驗證碼 25 ///</summary> 26 ///<param name="length">指定驗證碼的長度</param> 27 ///<returns></returns> 28 public string CreateValidateCode(int length) 29 { 30 int[] randMembers = new int[length]; 31 int[] validateNums = new int[length]; 32 string validateNumberStr = ""; 33 //生成(cheng)起始序列(lie)值 34 int seekSeek = unchecked((int)DateTime.Now.Ticks); 35 Random seekRand = new Random(seekSeek); 36 int beginSeek = (int)seekRand.Next(0, Int32.MaxValue - length * 10000); 37 int[] seeks = new int[length]; 38 for (int i = 0; i < length; i++) 39 { 40 beginSeek += 10000; 41 seeks[i] = beginSeek; 42 } 43 //生(sheng)成隨機數字 44 for (int i = 0; i < length; i++) 45 { 46 Random rand = new Random(seeks[i]); 47 int pownum = 1 * (int)Math.Pow(10, length); 48 randMembers[i] = rand.Next(pownum, Int32.MaxValue); 49 } 50 //抽取隨機數(shu)字 51 for (int i = 0; i < length; i++) 52 { 53 string numStr = randMembers[i].ToString(); 54 int numLength = numStr.Length; 55 Random rand = new Random(); 56 int numPosition = rand.Next(0, numLength - 1); 57 validateNums[i] = Int32.Parse(numStr.Substring(numPosition, 1)); 58 } 59 //生成驗證碼 60 for (int i = 0; i < length; i++) 61 { 62 validateNumberStr += validateNums[i].ToString(); 63 } 64 return validateNumberStr; 65 } 66 ///<summary> 67 /// 創(chuang)建驗證碼的圖片 68 ///</summary> 69 ///<param name="containsPage">要輸出到的page對象</param> 70 ///<param name="validateNum">驗證(zheng)碼(ma)</param> 71 public byte[] CreateValidateGraphic(string validateCode) 72 { 73 Bitmap image = new Bitmap((int)Math.Ceiling(validateCode.Length * 14.0), 22); 74 Graphics g = Graphics.FromImage(image); 75 try 76 { 77 //生成(cheng)隨機(ji)生成(cheng)器 78 Random random = new Random(); 79 //清空圖片背景色 80 g.Clear(Color.White); 81 //畫圖片的(de)干擾線 82 for (int i = 0; i < 25; i++) 83 { 84 int x1 = random.Next(image.Width); 85 int x2 = random.Next(image.Width); 86 int y1 = random.Next(image.Height); 87 int y2 = random.Next(image.Height); 88 g.DrawLine(new Pen(Color.Silver), x1, y1, x2, y2); 89 } 90 Font font = new Font("Arial", 14, (FontStyle.Bold | FontStyle.Italic)); 91 LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height), 92 Color.Blue, Color.DarkRed, 1.5f, true); 93 g.DrawString(validateCode, font, brush, 3, 2); 94 //畫圖片的(de)前(qian)景干(gan)擾點(dian) 95 for (int i = 0; i < 100; i++) 96 { 97 int x = random.Next(image.Width); 98 int y = random.Next(image.Height); 99 image.SetPixel(x, y, Color.FromArgb(random.Next())); 100 } 101 //畫圖片的(de)邊(bian)框線 102 g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1); 103 //保存圖片(pian)數據 104 MemoryStream stream = new MemoryStream(); 105 image.Save(stream, ImageFormat.Jpeg); 106 //輸(shu)出圖片流 107 return stream.ToArray(); 108 } 109 finally 110 { 111 g.Dispose(); 112 image.Dispose(); 113 } 114 } 115 }
然后,在當前公用(yong)的controller中添加一個返(fan)回(hui)文(wen)件(jian)類型的action,當然也(ye)可以(yi)是所有返(fan)回(hui)類型的基類ActionResult,這個方法用(yong)來返(fan)回(hui)一個圖像對象
1 /// <summary> 2 /// 生成驗證(zheng)碼圖像對象 3 /// </summary> 4 /// <returns></returns> 5 public ActionResult GetValidateCode() 6 { 7 ValidateCode vCode = new ValidateCode(); 8 string code = vCode.CreateValidateCode(4); 9 Session["ValidateCode"] = code; 10 byte[] bytes = vCode.CreateValidateGraphic(code); 11 return File(bytes, @"image/jpeg"); 12 }
再次,需要我(wo)們寫一個返(fan)回當(dang)前驗證(zheng)嗎的方法,這是作無刷新驗證(zheng)碼的關鍵
1 /// <summary> 2 /// 得到當前驗(yan)證碼(ma) 3 /// </summary> 4 /// <returns></returns> 5 public ActionResult GetCurrentValidateCode() 6 { 7 return Content(Session["ValidateCode"].ToString()); 8 }
最(zui)后,就是頁面上的事了,看代碼:
1 <div id="ValidateCodeSpan"> 2 請輸入驗證碼:@Html.TextBox("VCode") 3 <img id="valiCode" style="cursor: pointer;" src="/Common/GetValidateCode" alt="看(kan)不清?請點我" /> 4 @Html.Hidden("ValidateCode") 5 <script type="text/javascript"> 6 $(function () { 7 //首(shou)次加(jia)載 8 $("#valiCode").attr("src","/Common/GetValidateCode?time=" + (new Date()).getTime()); 9 $.get("/Common/GetCurrentValidateCode", function (data) { 10 $("#ValidateCode").val(data); 11 }); 12 //單擊驗(yan)證碼事件 13 $("#valiCode").bind("click", function () { 14 this.src = "/Common/GetValidateCode?time=" + (new Date()).getTime(); 15 $.get("/Common/GetCurrentValidateCode", function (data) { 16 $("#ValidateCode").val(data); 17 }); 18 }); 19 }); 20 </script> 21 </div>