哈哈好久沒冒泡了,最進看見點選驗證碼有點意思,所以想自己寫一個。
先上效果圖
如果你被這個效果吸引了就請繼續看下去。
貼代碼前先說點思路:
1.要有一個漢字庫,並按字形分類。(我在數據庫裡是安部首分類的)
2.獲取驗證碼(也就是取幾個文字做驗證碼)
3.根據取出來的文字去找形近字
4.排列驗證碼文字和形近字
5.繪制圖片
6.顯示
6.寫個博客分享一下(分享代碼改變世界)
一、獲取字庫
我國文化博大精深,辣麼多的字從哪兒來?當然我不可能手動加進去,於是我就在網上隨便找了一個能查漢字的網站,去抓別人的數據。抓數據的方法請點傳送門。傳送門裡說的只是思路,如果有不明白的請艾特我。我會在下面共享我的字庫。
二、獲取驗證碼
這個就比較簡單了這裡我就直接貼代碼了,下面的代碼就是隨機排序後取4條數據,我這樣寫是為了圖方便。個人覺得先隨機生成ID,然後直接根據ID取數據,這樣查詢速度會比下面這種寫法快。(注意我用的數據庫是MySql)
/// <summary>
/// 獲取驗證碼
/// </summary>
public List<VerificationCode.Model.WenZhi> GetCodeText()
{
const string sql = "SELECT * FROM wenzhi ORDER BY RAND() LIMIT 4";
var dataReader = dbHelper.GetDataReader(sql);
var list = DataReaderToList(dataReader);
dataReader.Close();
return list;
}
三、根據取出來的文字去找形近字
因為第一步的時候我存部首了,所以這裡我直接根據部首取獲取當前部首的形近字。
/// <summary>
/// 獲取答案備選
/// </summary>
/// <param name="buShouCode">部首編碼</param>
/// <param name="id">當前文字ID</param>
/// <param name="number">數量</param>
/// <returns></returns>
public List<VerificationCode.Model.WenZhi> GetAnswer(string buShouCode, int id,int number=1)
{
string sql = $"SELECT * FROM wenzhi where BuShouCode='{buShouCode}' and ID <> {id} ORDER BY RAND() LIMIT "+ number;
var dataReader = dbHelper.GetDataReader(sql);
var list = DataReaderToList(dataReader);
dataReader.Close();
return list;
}
四.排列驗證碼文字和形近字
下面的代碼是先把備選答案和驗證碼放在一個集合裡然後再對集合排序
public Model.Code GetCode() { var wenzlist = _wenZhiDal.GetCodeText(); //獲取驗證碼 var listAnsuwr = new List<Answer>();//實例化備選答案對象 var answerCode = string.Empty;//答案 var result = new Model.Code { Id = Guid.NewGuid().ToString() }; //根據驗證碼獲取備選答案並把添加到答案添加到備選答案集合 foreach (var item in wenzlist) { answerCode += item.ID + ","; result.AnswerValue += item.Text; var answerList = _wenZhiDal.GetAnswer(item.BuShouCode, item.ID); listAnsuwr.Add(new Answer { Id = item.ID.ToString(), Img = GetImage(item.Text) }); listAnsuwr.AddRange(answerList.Select(answer => new Answer { Id = answer.ID.ToString(), Img = GetImage(answer.Text) })); } //如果答案個數不夠就再去取幾個 if (listAnsuwr.Count < 9) { var ran = new Random(); var randKey = ran.Next(0, 4); var item = wenzlist[randKey]; var answerList = _wenZhiDal.GetAnswer(item.BuShouCode, item.ID, 9 - listAnsuwr.Count); listAnsuwr.AddRange(answerList.Select(answer => new Answer { Id = answer.ID.ToString(), Img = GetImage(answer.Text) })); } result.CodeImg = GetImage(result.AnswerValue);//獲取圖片 result.AnswerValue = answerCode.TrimEnd(','); result.Answer = RandomSortList(listAnsuwr);//打亂正確答案與形近字的順序 return result; }
這是對集合排序的代碼
/// <summary>
/// 隨機排列集合
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="listT"></param>
/// <returns></returns>
private static List<T> RandomSortList<T>(IEnumerable<T> listT)
{
var random = new Random();
var newList = new List<T>();
foreach (var item in listT)
{
newList.Insert(random.Next(newList.Count + 1), item);
}
return newList;
}
五、繪制圖片
下面是畫圖的代碼,驗證碼和備選答案對應兩種不同的畫法(裡面注釋寫的還算清楚)。不要擔心文字旋轉x°後人類分不出來,哈哈。代碼最後一句我把圖片轉成了Base64,方便前端調用。
private static string GetImage(string text)
{
Image image;
switch (text.Length)
{
case 1:
image = new Bitmap(50, 40);
break;
case 4:
image = new Bitmap(120, 40);
break;
default:
image = new Bitmap(50, 40);
break;
}
Brush brushText = new SolidBrush(Color.FromArgb(255, 0, 0, 0));
var graphics = Graphics.FromImage(image);
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.Clear(Color.White);
var font = new Font(new FontFamily("華文彩雲"), 20, FontStyle.Regular);
if (text.Length > 1)//畫驗證碼
{
//先來兩條直線做干擾 然後再畫文字
graphics.DrawLine(new Pen(brushText, new Random().Next(1, 3)), new Point(new Random().Next(0, 10), new Random().Next(10, 40)), new Point(new Random().Next(100, 120), new Random().Next(10, 30)));
graphics.DrawLine(new Pen(brushText, new Random().Next(1, 3)), new Point(new Random().Next(20, 50), new Random().Next(0, 10)), new Point(new Random().Next(100, 120), new Random().Next(30, 40)));
graphics.DrawString(text, font, brushText, 0, 10);
}
else//畫備選答案
{
Point middle = new Point(25, 20);
graphics.TranslateTransform(middle.X, middle.Y);
//這裡是360°隨機旋轉
graphics.RotateTransform(new Random().Next(0, 360));
var format = new StringFormat(StringFormatFlags.NoClip)
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
graphics.DrawString(text, font, brushText, 0, 0, format);
}
brushText.Dispose();
graphics.Dispose();
return ImageToBase64(image);
}
六、顯示
直接調用GetCode方法就能返回驗證碼對象
下面是後台代碼,應為正確答案是放在AnswerValue裡的所以我先把取出來放Session裡面,然後把值清空後再通過json返回給浏覽器。
public string GetVerCode()
{
var code = new VerificationCode.Code().GetCode();
Session["VERCODE"] = code.AnswerValue;
code.AnswerValue = "";
return JsonConvert.SerializeObject(code);
}
現在來堆點html代碼
<div class="form-group">
<ul class="vercode">
<li><img src=''/></li>
<li><img src=''/></li>
<li><img src=''/></li>
<li><img src=''/></li>
<li class="delete" onclick="delete_input()"></li>
</ul>
<div>
<img id="code-image"/> <a href="javascript:void(0);" onclick="load_vercode()">看不清?</a>
</div>
<ul class="vercode-anwser">
<li><img /></li>
<li><img /></li>
<li><img /></li>
<li><img /></li>
<li><img /></li>
<li><img /></li>
<li><img /></li>
<li><img /></li>
<li><img /></li>
</ul>
</div>
再來點js代碼,這裡只實現的圖片上的效果,還沒對數據驗證(這裡說說驗證思路:每個圖片對應一個ID,取到選擇圖片的ID用逗號分隔,然後與Session裡的值對比)
<script>
$(function () {
//加載驗證碼
load_vercode();
//綁定驗證碼點擊事件
$(".vercode-anwser").find("img").on("click", null, function () {
$(".vercode").find("img[src='']:eq(0)").attr("src", $(this).attr("src"));
});
});
function load_vercode() {
$(".vercode").find("img").attr("src", "");
$.get("GetVerCode", function (data) {
var result = JSON.parse(data);
$("#code-image").attr("src", "data:image/png;base64," + result.CodeImg);
$(".vercode-anwser").find("img").each(function (index) {
$(this).attr("src", "data:image/png;base64," + result.Answer[index].Img);
});
});
}
//刪除事件
function delete_input() {
$(".vercode").find("img[src!='']:last").attr("src", "");
}
</script>
到這裡代碼就差不多了,以上思路只是單純的個人想法,有興趣的朋友一起來討論吧。
源代碼在這裡-->地址 http://pan.baidu.com/s/1eS5Mn30 密碼:7iud
分享代碼改變世界