版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qiyongkang520/article/details/54918151
验证码想必大家都经常遇到,今天就给大家介绍一个比较简单的图片验证码的实现。
要实现验证码主要分生成和验证两步。首先生成,就是指某个用户看到验证码后台立马生成的,然后把这个生成图片的字符串保存放在session或者内存中;要验证用户输入的字符串与生成的验证码是否一致,就是取出这个session中保存的字符串与用户输入的验证码进行比对即可。
一、html代码
笔者写了一个很简单的html界面,来简单模拟下过程,代码如下:
<!DOCTYPE html>
<html>
<head>
<title>图片验证码</title>
<meta charset="utf-8"/>
</head>
<body>
<input type="number" class="ui input row-1" placeholder="请输入验证码" id="yzm">
<a href="javascript:void(0)" class="refresh_yzm"><img src="" id="randomImg"></a>
<button type="button" id="save_btn">提交</button>
<script src="/m/plugins/zepto/zepto.min.js" type="text/javascript"></script>
<script src="../../scripts/captcha/imageCode.js" type="text/javascript"></script>
</body>
</html>
页面展示如下:
二、js代码
交互逻辑代码如下,比较简单,所以也用不着做啥介绍:
/**
* 图片验证码
*/
var mobileKey = '';
$(function() {
console.log('图片验证码。。。');
getTicketImg();
//点击验证码图片
$('#randomImg').click(function() {
getTicketImg();
});
//提交
$('#save_btn').click(function() {
//获取输入框的验证码
var code = $('#yzm').val();
console.log('code:' + code + ', mobileKey:' + mobileKey);
var param = {
code: code,
mobileKey: mobileKey
};
$.post('/sys/captcha/validateImageCode.do', param, function(data) {
console.log('data:', data);
getTicketImg();
});
});
});
/**
* 获取图片验证码
*/
function getTicketImg() {
var ticket_key = Math.floor(Math.random() * 1000000);
mobileKey = ticket_key;
$("#yzm").val("");
var randomImg = "/sys/captcha/generateImageCode.do?mobileKey=" + ticket_key;
$("#randomImg").attr("src", randomImg);
}
三、后台验证码图片生成以及验证
验证码图片生成的代码还是挺多的,这里使用的是patchca这个插件,版本是0.5.0的,大家可以在网上去下载,上传到自己私服的第三方库。
代码如下:
/**
* Project Name:qyk_testSpringMVC
* File Name:CaptchaController.java
* Package Name:com.qiyongkang.sys.controller
* Date:2017年2月7日上午9:49:30
* Copyright (c) 2017, Thinkive(http://www.thinkive.com/) All Rights Reserved.
*
*/
package com.qiyongkang.sys.controller;
import java.awt.Color;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.patchca.color.ColorFactory;
import org.patchca.filter.predefined.CurvesRippleFilterFactory;
import org.patchca.filter.predefined.DiffuseRippleFilterFactory;
import org.patchca.filter.predefined.DoubleRippleFilterFactory;
import org.patchca.filter.predefined.MarbleRippleFilterFactory;
import org.patchca.filter.predefined.WobbleRippleFilterFactory;
import org.patchca.service.ConfigurableCaptchaService;
import org.patchca.utils.encoder.EncoderHelper;
import org.patchca.word.RandomWordFactory;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.qiyongkang.sys.Constants;
import com.qiyongkang.sys.dto.ExtJsObject;
/**
* ClassName:CaptchaController <br/>
* Function: 验证码. <br/>
* Date: 2017年2月7日 上午9:49:30 <br/>
*
* @author qiyongkang
* @version
* @since JDK 1.6
* @see
*/
@Controller
@RequestMapping
public class CaptchaController {
/**
* 日志类
*/
private static Logger logger = LogManager.getLogger(CaptchaController.class);
private static ConfigurableCaptchaService cs = new ConfigurableCaptchaService();
private static int MAX_LENGTH = 4;
private static int MIN_LENGTH = 4;
private static Random random = new Random();
private static Map<String, String> vcodeMap = new HashMap<String, String>();
public static void saveVcode(String key, String vcode) {
vcodeMap.put(key, vcode);
}
public static String getVcode(String key) {
return vcodeMap.get(key);
}
public static void removeVcode(String key) {
vcodeMap.remove(key);
}
public static void emptyAllVcode() {
vcodeMap.clear();
}
static {
cs.setColorFactory(new ColorFactory() // 随机生成颜色
{
public Color getColor(int x) {
int[] c = new int[3];
int i = random.nextInt(c.length);
for (int fi = 0; fi < c.length; fi++) {
if (fi == i) {
c[fi] = random.nextInt(71);
} else {
c[fi] = random.nextInt(256);
}
}
return new Color(c[0], c[1], c[2]);
}
});
RandomWordFactory wf = new RandomWordFactory();
wf.setCharacters("123456789");// 设置验证码的内容
wf.setMaxLength(MAX_LENGTH);
wf.setMinLength(MIN_LENGTH);
cs.setWordFactory(wf);
}
/**
*
* generateImageCode: 生成图片验证码. <br/>
*
* @author qiyongkang
* @param request
* @param response
* @since JDK 1.6
*/
@RequestMapping
public void generateImageCode(HttpServletRequest request, HttpServletResponse response) {
switch (random.nextInt(5)) {// 随机生成不同形式验证码
case 0:
cs.setFilterFactory(new CurvesRippleFilterFactory(cs.getColorFactory()));// 取现波纹
break;
case 1:
cs.setFilterFactory(new MarbleRippleFilterFactory());// 大理石波纹
break;
case 2:
cs.setFilterFactory(new DoubleRippleFilterFactory());// 双波纹
break;
case 3:
cs.setFilterFactory(new WobbleRippleFilterFactory());// 摆波纹
break;
case 4:
cs.setFilterFactory(new DiffuseRippleFilterFactory());// 双波纹
break;
}
setResponseHeader(response); // 设置响应头
HttpSession session = request.getSession(true);
OutputStream os = null;
String codeStr = "";
try {
os = response.getOutputStream();
codeStr = EncoderHelper.getChallangeAndWriteImage(cs, "png", os);
} catch (IOException e) {
logger.error("生成验证码图片异常", e);
} finally {
if (os != null) {
try {
os.flush();
os.close();
} catch (IOException e) {
logger.error("关闭流异常", e);
}
}
}
logger.info("当前的SessionID=" + session.getId() + ", 验证码:" + codeStr);
String key = request.getParameter("mobileKey");
if (key == null) {
key = "";
}
//保存到map中
saveVcode(key, codeStr);
//放在session中
session.setAttribute(Constants.TICKET + key, codeStr);
}
/**
*
* validateImageCode: 校验图片验证码. <br/>
*
* @author qiyongkang
* @since JDK 1.6
*/
@RequestMapping
@ResponseBody
public ExtJsObject validateImageCode(HttpServletRequest request) {
ExtJsObject extJsObject = new ExtJsObject();
//code
String code = request.getParameter("code");
//mobileKey
String mobileKey = request.getParameter("mobileKey");
if (StringUtils.isEmpty(code) || StringUtils.isEmpty(mobileKey)) {
extJsObject.setSuccess(false);
extJsObject.setMsg("验证码不能为空");
} else {
//判断验证码是否正确, 两重判断,session中和map集合中的
HttpSession session = request.getSession();
if (code.equalsIgnoreCase(session.getAttribute(Constants.TICKET + mobileKey).toString())
&& code.equalsIgnoreCase(CaptchaController.getVcode(mobileKey))) {
CaptchaController.removeVcode(mobileKey);
extJsObject.setSuccess(true);
extJsObject.setMsg("验证码正确");
} else {
extJsObject.setSuccess(false);
extJsObject.setMsg("验证码错误");
}
}
return extJsObject;
}
/**
* 设置输出流响应头
*/
private void setResponseHeader(HttpServletResponse response) {
response.setContentType("image/png");
response.setHeader("cache", "no-cache");
response.setContentType("image/png");
response.setHeader("Cache-Control", "no-cache, no-store");
response.setHeader("Pragma", "no-cache");
long time = System.currentTimeMillis();
response.setDateHeader("Last-Modified", time);
response.setDateHeader("Date", time);
response.setDateHeader("Expires", time);
}
}
这里因为在前端会带一个随机码参数过来,所以做了双重验证,更加安全;另外,大家还可以写一个定时任务,每天清一次map中的所有key,防止占用过多的内存;好了,就简单介绍到这儿了,大家可以去试一试!