验证码想必大家都经常遇到,今天就给大家介绍一个比较简单的图片验证码的实现。 要实现验证码主要分生成和验证两步。首先生成,就是指某个用户看到验证码后台立马生成的,然后把这个生成图片的字符串保存放在session或者内存中;要验证用户输入的字符串与生成的验证码是否一致,就是取出这个session中保存的字符串与用户输入的验证码进行比对即可。
笔者写了一个很简单的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>页面展示如下:
交互逻辑代码如下,比较简单,所以也用不着做啥介绍:
/** * 图片验证码 */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@RequestMappingpublic 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,防止占用过多的内存;好了,就简单介绍到这儿了,大家可以去试一试!
新闻热点
疑难解答