java使用Hutool工具库实现图形验证码
Hutool工具库简化了Java图形验证码的实现过程。它提供ICaptcha接口和AbstractCaptcha抽象类,封装了验证码生成、校验等核心功能。开发者可快速创建线段、圆圈或扭曲干扰等样式的验证码,并通过集成到Web登录流程,实现包含时效性验证的安全校验机制。
在Ja va开发中,图形验证码是提升系统安全性的常见手段。自己从头实现一套,不仅要处理图形绘制、干扰线生成,还得考虑代码的随机性和安全性,确实费时费力。好在,我们有现成的轮子——Hutool工具库,它能让我们用极简的代码,快速实现专业级的验证码功能。
关于Hutool的介绍
Hutool是一个小而全的Ja va工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Ja va拥有函数式语言般的优雅,让Ja va语言也可以“甜甜的”。
Hutool中的工具方法来自每个用户的精雕细琢,它涵盖了Ja va开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;
Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。
要使用它,首先需要在项目的pom.xml文件中引入依赖:
cn.hutool hutool-all 5.8.26
图形验证码
介绍
验证码功能位于cn.hutool.captcha包中,其核心是一个名为ICaptcha的接口。这个接口定义了几个关键方法,基本上涵盖了一个验证码组件应有的所有行为:
createCode:创建验证码。实现类需要在这里生成随机的验证码字符串和对应的图片。
getCode:获取验证码的文字内容,也就是用户需要识别的那个字符串。
verify:校验用户输入的验证码是否正确。通常建议忽略大小写进行比对。
write:将生成的验证码图片写出到指定的输出流中。
其中,write方法只接收一个OutputStream参数,这样的设计很巧妙,使得实现类可以基于这个方法轻松扩展出写出到文件、响应流等多种方式。
Hutool还提供了一个AbstractCaptcha抽象类作为ICaptcha的基础实现。它已经把验证码文本的生成、忽略大小写的验证、以及写出到流和文件这些通用逻辑都封装好了。作为开发者,我们通常只需要继承这个抽象类,并实现createImage方法来定义具体的图形生成规则即可,大大减少了重复劳动。
LineCaptcha:实现线段干扰的验证码
线段干扰是最经典的验证码样式之一。用Hutool实现起来,简单得超乎想象:
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.lang.Console;
public class DemoController {
public static void main(String[] args) {
// 定义图形验证码的长和宽
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);
// 将图形验证码写出到文件
lineCaptcha.write("d:/line.png");
// 在控制台输出生成的验证码文本,方便调试
Console.log(lineCaptcha.getCode());
// 验证用户输入的“1234”是否正确
lineCaptcha.verify("1234");
// 如果需要,可以重新生成验证码
lineCaptcha.createCode();
lineCaptcha.write("d:/line.png");
// 输出新的验证码
Console.log(lineCaptcha.getCode());
// 再次验证
lineCaptcha.verify("1234");
}
}
运行上面的代码,控制台会输出验证码内容,同时会在D盘根目录生成一张图片。效果如下:

这就是生成的带有线段干扰的图形验证码:

CircleCaptcha:实现圆圈干扰验证码
如果你觉得线段干扰有点普通,想换点花样,圆圈干扰是个不错的选择。它用随机的小圆圈作为干扰元素,同样只需几行代码:
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.core.lang.Console;
public class CircleController {
public static void main(String[] args) {
// 定义图形验证码的长、宽、验证码字符数、干扰元素个数
CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 20);
// 也可以直接new:CircleCaptcha captcha = new CircleCaptcha(200, 100, 4, 20);
// 写出到文件
captcha.write("d:/circle.png");
Console.log(captcha.getCode());
// 进行验证
captcha.verify("1234");
}
}
运行结果:

生成的验证码效果如下,可以看到背景布满了随机圆圈:

ShearCaptcha:实现扭曲干扰验证码
想要进一步增强机器识别的难度?扭曲干扰验证码(ShearCaptcha)会把字符进行一定程度的扭曲和错切,对人眼来说可能稍微费点劲,但对机器识别程序挑战更大。
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ShearCaptcha;
import cn.hutool.core.lang.Console;
public class ShearController {
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");
Console.log(captcha.getCode());
captcha.verify("1234");
}
}
运行结果:

看看生成的效果,字符是不是有了明显的扭曲感?

将线段干扰验证码集成到登录流程
了解了基本用法,我们来看一个实战场景:如何把验证码集成到一个Web登录流程中。整个过程可以分为前端和后端协同工作:
1. 前端发起请求:用户打开登录页,前端首先向后端发起一个请求,获取图形验证码图片。
2. 后端生成并存储:后端接收到请求后,调用Hutool生成验证码图片和对应的正确文本。将图片流返回给前端的同时,必须把验证码文本和生成时间存入当前用户的Session中。
3. 用户输入并提交:用户在前端页面看到验证码图片,输入识别出的字符,连同账号密码一起提交。
4. 后端校验:后端收到提交后,先判断验证码输入是否为空。然后从当前Session中取出之前存储的正确验证码和生成时间。
5. 双重验证:校验分两步:第一,比对用户输入的验证码(忽略大小写)与Session中存储的是否一致;第二,检查当前时间与验证码生成时间的时间差,是否在允许的有效期内(比如60秒)。
6. 返回结果:只有两步验证都通过,后端才返回成功;否则返回失败。前端根据结果决定是跳转到成功页面,还是提示验证码错误或过期。
后端代码实现
首先,我们在application.yml中配置验证码的参数,这样以后修改尺寸或Session键名会非常方便:
captcha:
width: 200
height: 100
session:
key: captcha_session_key
date: captcha_session_date
配置属性类:CaptchaProperties
创建一个属性类来映射配置文件中的值:
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;
@Data
public static class Session{
private String key;
private String date;
}
}
核心控制器:CaptchaController
这个控制器提供两个核心接口:一个是获取验证码图片,一个是校验用户输入的验证码。
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.lang.Console;
import com.wmh.captcha.model.CaptchaProperties;
import jakarta.servlet.http.HttpServletRequest;
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 ja va.io.IOException;
import ja va.util.Date;
@RequestMapping("/captcha")
@RestController
public class DCaptchaController {
// 设置验证码有效期为60秒
private final static long session_valid_timeout = 60 * 1000;
@Autowired
private CaptchaProperties captchaProperties;
@RequestMapping("/get")
public void getCaptcha(HttpSession session, HttpServletResponse response){
// 1. 使用配置的宽高创建线段验证码
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(captchaProperties.getWidth(), captchaProperties.getHeight());
// 2. 设置响应头,告诉浏览器这是张图片
response.setContentType("image/jpeg");
response.setHeader("Progma", "No-cache"); // 禁止缓存,保证每次都是新验证码
Console.log(lineCaptcha.getCode()); // 控制台输出,便于调试
// 3. 将图片写入HTTP响应流
try {
lineCaptcha.write(response.getOutputStream());
// 4. 将验证码文本和生成时间存入Session
session.setAttribute(captchaProperties.getSession().getKey(), lineCaptcha.getCode());
session.setAttribute(captchaProperties.getSession().getDate(), new Date());
response.getOutputStream().close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@RequestMapping("/check")
public Boolean check(String inputCode, HttpSession session){
// 1. 检查输入是否为空
if (!StringUtils.hasLength(inputCode)){
return false;
}
// 2. 从Session中取出之前存储的正确信息
String sa vedCode = (String) session.getAttribute(captchaProperties.getSession().getKey());
Date sa veDate = (Date) session.getAttribute(captchaProperties.getSession().getDate());
// 3. 进行比对(忽略大小写)并检查是否过期
if (inputCode.equalsIgnoreCase(sa vedCode)){
if (sa veDate != null && System.currentTimeMillis() - sa veDate.getTime() < session_valid_timeout){
return true; // 验证通过
}
}
// 4. 任何一步不满足则返回失败
return false;
}
}
前端代码实现
前端页面主要负责展示验证码图片、提供输入框,并处理与后端的交互。
index.html (主页面)
验证码
输入验证码
success.html (成功页面)
验证成功页
验证成功
最终运行效果
启动Spring Boot应用,访问首页,你会看到如下验证码输入界面:

输入正确的验证码并提交后,页面会跳转到成功提示页:

至此,一个完整的、带有验证码的Web登录校验流程就搭建完成了。整个过程借助Hutool,后端代码非常简洁,而验证码的生成、存储、比对和过期校验等核心安全逻辑都已涵盖其中。
Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。
极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。
















