目录
前言
一、Hutool工具介绍
1.1 Maven
1.2 介绍
1.3 实现类
二、验证码案例
2.1 需求
2.2 约定前后端交互接口
2.2.1 需求分析
2.2.2 接口定义
2.3 后端生成验证码
2.4 前端接收验证码图片
2.5 后端校验验证码
2.6 前端校验验证码
2.7 后端完整代码
前言
验证码实现方式很多,可以前端实现,也可以后端实现,网上也有比较多的插件或者工具包可以使用,咱们选择使用Hutool提供的小工具来实现。
一、Hutool工具介绍
Hutool是一个Java工具包类库,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种Util工具类。Hutool官网:https://hutool.cn/
1.1 Maven
如果你想在项目中使用Hutool中的某个模块,在项目的pom.xml的dependencies中加入以下内容:
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-captcha</artifactId><version>5.8.22</version>
</dependency>
1.2 介绍
验证码功能位于cn.hutool.captcha包中,核心接口为ICaptcha
,此接口定义了以下方法:
createCode
创建验证码,实现类需同时生成随机验证码字符串和验证码图片getCode
获取验证码的文字内容verify
验证验证码是否正确,建议忽略大小写write
将验证码图片写出到目标流中
其中write方法只有一个OutputStream
,ICaptcha
实现类可以根据这个方法封装写出到文件等方法。
AbstractCaptcha
为一个ICaptcha
抽象实现类,此类实现了验证码文本生成、非大小写敏感的验证、写出到流和文件等方法,通过继承此抽象类只需实现createImage
方法定义图形生成规则即可。
1.3 实现类
LineCaptcha线段干扰的验证码
贴栗子:
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.lang.Console;public class LineCaptchaTest {public static void main(String[] args) {//定义图形验证码的长和宽LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);//图形验证码写出,可以写出到文件,也可以写出到流lineCaptcha.write("d:/line.png");//输出codeConsole.log(lineCaptcha.getCode());//验证图形验证码的有效性,返回boolean值lineCaptcha.verify("1234");//重新生成验证码lineCaptcha.createCode();lineCaptcha.write("d:/line.png");//新的验证码Console.log(lineCaptcha.getCode());//验证图形验证码的有效性,返回boolean值lineCaptcha.verify("1234");}
}
控制台截图生成的验证码:
在写入的路径中查看代码生成的验证码截图:
CircleCaptcha
圆圈干扰验证码
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.core.lang.Console;public class CircleCaptchaTest {public static void main(String[] args) {//定义图形验证码的长、宽、验证码字符数、干扰元素个数CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 20);//CircleCaptcha captcha = new CircleCaptcha(200, 100, 4, 20);//图形验证码写出,可以写出到文件,也可以写出到流captcha.write("d:/circle.png");//输出codeConsole.log(captcha.getCode());//验证图形验证码的有效性,返回boolean值captcha.verify("1234");}
}
控制台截图生成的验证码:
在写入的路径中查看代码生成的验证码截图:
ShearCaptcha
扭曲干扰验证码
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ShearCaptcha;
import cn.hutool.core.lang.Console;public class ShearCaptchaTest {public static void main(String[] args) {//定义图形验证码的长、宽、验证码字符数、干扰线宽度ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(200, 100, 4, 4);//ShearCaptcha captcha = new ShearCaptcha(200, 100, 4, 4);//图形验证码写出,可以写出到文件,也可以写出到流captcha.write("d:/shear.png");//输出codeConsole.log(captcha.getCode());//验证图形验证码的有效性,返回boolean值captcha.verify("1234");}
}
控制台截图生成的验证码:
在写入的路径中查看代码生成的验证码截图:
二、验证码案例
2.1 需求
需求如下:
- 页面生成验证码
- 输入验证码,点击提交,验证用户输入验证码是否正确,正确则进行页面跳转
2.2 约定前后端交互接口
2.2.1 需求分析
后端需要提供两个服务:
- 生成验证码,并返回验证码
- 校验验证码是否正确
2.2.2 接口定义
1、生成验证码:
url:/captcha/get
param:无
return:图片的内容
2、校验验证码
url:/captcha/check
param:inputCode
return:true/false
2.3 后端生成验证码
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.io.IOException;@RestController
@RequestMapping("/captcha")
public class CaptchaController {@RequestMapping("/get")public void getCaptcha(HttpServletResponse response) {//定义图形验证码的长和宽LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);//图像验证码写出,可以写出到文件,也可以写出到流,此处写出到流try {lineCaptcha.write(response.getOutputStream());} catch (IOException e) {throw new RuntimeException(e);}}
}
小技巧:在我们每写完一个后端代码模块时,我们可以进行测试,看是否有错误,避免后续代码量过多发生错误时不知道哪块出错。
根据后端定义的url进行测试截图:
2.4 前端接收验证码图片
<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8"><title>验证码</title><style>#inputCaptcha {height: 30px;vertical-align: middle; }#verificationCodeImg{vertical-align: middle; }#checkCaptcha{height: 40px;width: 100px;}</style>
</head><body><h1>输入验证码</h1><div id="confirm"><input type="text" name="inputCaptcha" id="inputCaptcha"><img id="verificationCodeImg" src="/captcha/get" style="cursor: pointer;" title="看不清?换一张" /><input type="button" value="提交" id="checkCaptcha"></div><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script><script>$("#verificationCodeImg").click(function(){$(this).hide().attr('src', '/captcha/get?dt=' + new Date().getTime()).fadeIn();});$("#checkCaptcha").click(function () {alert("验证码校验");});</script>
</body></html>
验证前端是否有问题:
2.5 后端校验验证码
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.example.demo.model.CaptchaProperties;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.io.IOException;
import java.util.Date;@RestController
@RequestMapping("/captcha")
public class CaptchaController {private final static long session_valid_timeout = 60 * 1000;@Autowiredprivate CaptchaProperties captchaProperties;@RequestMapping("/check")public Boolean check(HttpSession session, String inputCode) {//验证码输入的内容和用户输入的进行比较//从session获取信息if (!StringUtils.hasLength(inputCode)) {return false;}String savedCode = (String) session.getAttribute(captchaProperties.getSession().getKey());Date saveDate = (Date) session.getAttribute(captchaProperties.getSession().getDate());if (inputCode.equalsIgnoreCase(savedCode)) {//判断验证码是否过期if (saveDate != null && System.currentTimeMillis() - saveDate.getTime() < session_valid_timeout) {return true;}return true;}return false;}
}
检查校验验证码是否存在问题:
1、先查看后端生成的验证码
2、根据校验验证的url进行验证
首先先输入错误的验证码观察返回ture或者false,如果返回false证明验证码输入错误或者过期,否则反正true。
先输入错误的验证码1234截图:
再输入正确的验证码截图:
2.6 前端校验验证码
<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8"><title>验证码</title><style>#inputCaptcha {height: 30px;vertical-align: middle; }#verificationCodeImg{vertical-align: middle; }#checkCaptcha{height: 40px;width: 100px;}</style>
</head><body><h1>输入验证码</h1><div id="confirm"><input type="text" name="inputCaptcha" id="inputCaptcha"><img id="verificationCodeImg" src="/captcha/get" style="cursor: pointer;" title="看不清?换一张" /><input type="button" value="提交" id="checkCaptcha"></div><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script><script>$("#verificationCodeImg").click(function(){$(this).hide().attr('src', '/captcha/get?dt=' + new Date().getTime()).fadeIn();});$("#checkCaptcha").click(function () {$.ajax({url: "/captcha/check",type: "post",data: {inputCode: $("#inputCaptcha").val()},success: function(result) {if (result) {location.href = "success.html";} else {alert("验证码错误或者过期");}}})});</script>
</body></html>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>验证成功页</title>
</head>
<body><h1>验证成功</h1>
</body>
</html>
运行截图:
2.7 后端完整代码
package com.example.demo.controller;import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.example.demo.model.CaptchaProperties;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.io.IOException;
import java.util.Date;@RestController
@RequestMapping("/captcha")
public class CaptchaController {private final static long session_valid_timeout = 60 * 1000;@Autowiredprivate CaptchaProperties captchaProperties;@RequestMapping("/get")public void getCaptcha(HttpSession session, HttpServletResponse response) {//定义图形验证码的长和宽LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(captchaProperties.getWidth(), captchaProperties.getHeight());//设置缓存类型response.setContentType("image/jpeg");//禁止缓存response.setHeader("Progma", "No-cache");//图像验证码写出,可以写出到文件,也可以写出到流,此处写出到流try {lineCaptcha.write(response.getOutputStream());//存储sessionsession.setAttribute(captchaProperties.getSession().getKey(), lineCaptcha.getCode());session.setAttribute(captchaProperties.getSession().getDate(), new Date());} catch (IOException e) {throw new RuntimeException(e);}}@RequestMapping("/check")public Boolean check(HttpSession session, String inputCode) {//验证码输入的内容和用户输入的进行比较//从session获取信息if (!StringUtils.hasLength(inputCode)) {return false;}String savedCode = (String) session.getAttribute(captchaProperties.getSession().getKey());Date saveDate = (Date) session.getAttribute(captchaProperties.getSession().getDate());if (inputCode.equalsIgnoreCase(savedCode)) {//判断验证码是否过期if (saveDate != null && System.currentTimeMillis() - saveDate.getTime() < session_valid_timeout) {return true;}}return false;}
}
配置文件:
captcha:width: 200height: 100session:key: captcha_session_keydate: captcha_session_date
captcha配置:
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Component
@ConfigurationProperties(prefix = "captcha")
@Data
public class CaptchaProperties {private Integer width;private Integer height;private Session session;@Datapublic static class Session {private String key;private String date;}
}