验证码
最近在工作中做到这一部分,所以在这里记录一下。
首先我们整理一下思路。
一开始,我做这个验证码的时候,只是在服务器端生成一个bufferedImage,记录下验证码 的code,并存入到redis中,然后用通过servletResponse写出去。
但是后来却发现多人验证的话,会分不清验证码,因为存入redis里的key是写死的,导致登陆不了。
然后就决定,用每一个ID对应一个验证码,ID作为key将验证码的值存入到redis中。这样多人验证就不会乱了。服务器生成 ID(这里不考虑ID重复的问题)和Image传递给前端。
前端获取ID是为了到服务器取到redis里正确的验证码,来跟用户输入的进行比较。Image是为了展示验证码图片。
这里我引入了kaptcha来生成验证码。
1.在POM文件中引入kaptcha
<dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency>
2.在springmvc里配置验证码的bean
<bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha"> <property name="config"> <bean class="com.google.code.kaptcha.util.Config"> <constructor-arg> <props> <prop key="kaptcha.border">yes</prop> <prop key="kaptcha.border.color">105,179,90</prop> <prop key="kaptcha.textproducer.font.color">blue</prop> <prop key="kaptcha.image.width">125</prop> <prop key="kaptcha.image.height">45</prop> <prop key="kaptcha.textproducer.font.size">45</prop> <prop key="kaptcha.session.key">code</prop> <prop key="kaptcha.textproducer.char.length">4</prop> <prop key="kaptcha.textproducer.font.names">微软雅黑</prop> </props> </constructor-arg> </bean> </property> </bean>
3.编写验证码服务类和实现类
public interface kaptchaService { CaptchaDTO createCaptcha(); }
@Service public class kaptchaServiceImpl implements kaptchaService { private static final int SESSION_TIME = 60*30; @Autowired private Producer captchaProducer; @Override public CaptchaDTO createCaptcha() { String captchaId = UUID.randomUUID().toString().replace("-", ""); String capText = captchaProducer.createText(); BufferedImage bi = captchaProducer.createImage(capText); // 将验证码保存到redis中; RedisUtil.del("captcha_code_"+captchaId); RedisUtil.setex("captcha_code_"+captchaId,capText.toLowerCase(),SESSION_TIME); CaptchaDTO captchaDTO = new CaptchaDTO(); captchaDTO.setCaptchaId(captchaId); captchaDTO.setCode(capText); captchaDTO.setImage(bi); return captchaDTO; } }
4.编写控制器和映射
@Controller public class CodeController { @Autowired private kaptchaService kaptchaService; @ResponseBody @RequestMapping("/captcha") public BizResult getCode(){ // 定义图像buffer CaptchaDTO captchaDTO = kaptchaService.createCaptcha(); try { CaptchaModel captchaModel = new CaptchaModel(); captchaModel.setCaptchaId(captchaDTO.getCaptchaId()); captchaModel.setImage("data:image/.jpg;base64," + imageToBase64(captchaDTO.getImage())); return BizResult.success(captchaModel); } catch (Exception e) { return BizResult.fail("网络异常"); } } /** * 图片进行base64编码 * @param bufferedImage 图片流 * @return string */ private static String imageToBase64(BufferedImage bufferedImage) throws IOException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ImageIO.write(bufferedImage, "jpg", outputStream); String base64 = Base64.getEncoder().encodeToString(outputStream.toByteArray()); return base64.replace("\n", ""); } }
5.前端
<c:set var="ctx" value="${pageContext.request.contextPath}"/>
<h2>验证码</h2> <label> <input style="float: left; margin-right: 10px;" type="text" name="validate" id="validate" class="txt_input3" > </label> <label> <img id="captchaImage" class="txt_input3" src="${ctx}/captcha" onclick="changeImg()"/> </label>
function getValidateCode(url){ $.ajax({ type:"GET", url:"/captcha", success:function (ret){ $("#captchaImage").attr("src",ret.data.image); rediskey = ret.data.captchaId; } }); }