springboot使用hutool captcha +vue实现图形验证码
一、效果
使用hutool captcha实现简单的图形验证码,可以参考官网概述 | Hutool
二、实现步骤
1、导入依赖
<!--hutool包-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
2、后端代码
@RestController
@RequestMapping()
public class CaptchaController {
private static final String REDIS_KEY = "captcha";
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("/lineCaptcha")
public Result createLineCaptcha() {
//创建一个线性验证码图片,并将其输出到浏览器
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(100, 40, 4, 9);
//设置验证码内容,并输出到浏览器
String code = lineCaptcha.getCode();
//redis存储验证码内容
//设置验证码有效期为1分钟
redisTemplate.opsForValue().set(REDIS_KEY, code, 60, TimeUnit.SECONDS);
//获取验证码图片的Base64编码数据
String imageBase64Data = lineCaptcha.getImageBase64Data();
// // 设置正确的 MIME 类型
// response.setContentType("image/png");
// lineCaptcha.write(response.getOutputStream());
// //将验证码内容保存到响应头中,供客户端验证使用
// response.setHeader("REDIS_KEY", code);
return Result.success(imageBase64Data);
}
@GetMapping("/circleCaptcha")
public Result createCircleCaptcha() {
CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(100, 40, 4, 9);
String code = circleCaptcha.getCode();
//redis存储验证码内容
//设置验证码有效期为1分钟
redisTemplate.opsForValue().set(REDIS_KEY, code, 60, TimeUnit.SECONDS);
//获取验证码图片的Base64编码数据
String imageBase64Data = circleCaptcha.getImageBase64Data();
return Result.success(imageBase64Data);
}
@GetMapping("/shearCaptcha")
public Result createShearCaptcha() {
ShearCaptcha shearCaptcha = CaptchaUtil.createShearCaptcha(100, 40, 4, 9);
String code = shearCaptcha.getCode();
//redis存储验证码内容
//设置验证码有效期为1分钟
redisTemplate.opsForValue().set(REDIS_KEY, code, 60, TimeUnit.SECONDS);
//获取验证码图片的Base64编码数据
String imageBase64Data = shearCaptcha.getImageBase64Data();
return Result.success(imageBase64Data);
}
@GetMapping("/gifCaptcha")
public Result createGifCaptcha() {
GifCaptcha gifCaptcha = CaptchaUtil.createGifCaptcha(100, 40, 4);
//redis存储验证码内容
String code = gifCaptcha.getCode();
//设置验证码有效期为1分钟
redisTemplate.opsForValue().set(REDIS_KEY, code, 60, TimeUnit.SECONDS);
//获取验证码图片的Base64编码数据
String imageBase64Data = gifCaptcha.getImageBase64Data();
return Result.success(imageBase64Data);
}
@GetMapping("/diyCharCaptcha")
public Result createDiyCharCaptcha() {
// 定义图形验证码的长、宽、验证码字符数、干扰线宽度
//ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(100, 40, 4, 4);
LineCaptcha captcha = CaptchaUtil.createLineCaptcha(100, 40, 4, 4);
// 自定义纯数字的验证码(随机4位数字,可重复)
RandomGenerator randomGenerator = new RandomGenerator("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 4);
// 自定义验证码内容为随机4位字符
captcha.setGenerator(randomGenerator);
//redis存储验证码内容
String code = captcha.getCode();
System.out.println("随机4位字符验证码:" + code);
String imageBase64Data = captcha.getImageBase64Data();
return Result.success(imageBase64Data);
}
@GetMapping("/diyComputeCaptcha")
public Result createDiyComputeCaptcha() {
// 定义图形验证码的长、宽、验证码字符数、干扰线宽度
LineCaptcha captcha = CaptchaUtil.createLineCaptcha(100, 40, 4, 4);
/**
* 自定义验证码内容为四则运算方式
* numberLength默认为2,即生成的计算式为两个两位数的计算 88+11=
*/
MathGenerator mathGenerator = new MathGenerator(1);
captcha.setGenerator(mathGenerator);
//redis存储验证码内容
String code = captcha.getCode();
System.out.println("四则运算验证码:" + code);
// 验证用户输入是否正确
String userInputCode = "10";
boolean isCorrect = mathGenerator.verify(code, userInputCode);
System.out.println("用户输入:" + userInputCode + ",是否正确:" + isCorrect);
String imageBase64Data = captcha.getImageBase64Data();
return Result.success(imageBase64Data);
}
}
3、前端代码
api
import request from "@/utils/request";
/**
* 获取验证码
*
* @returns 验证码图片
*/
export const getLineCaptcha = () => {
return request({
url: "/lineCaptcha",
method: "get",
// responseType: "blob",
});
};
export const getCircleCaptcha = () => {
return request({
url: "/circleCaptcha",
method: "get",
});
};
export const getShearCaptcha = () => {
return request({
url: "/shearCaptcha",
method: "get",
});
};
export const getGifCaptcha = () => {
return request({
url: "/gifCaptcha",
method: "get",
});
};
export const getDiyCharCaptcha = () => {
return request({
url: "/diyCharCaptcha",
method: "get",
});
};
export const getDiyComputeCaptcha = () => {
return request({
url: "/diyComputeCaptcha",
method: "get",
});
};
vue页面
<template>
<div class="captcha">
<h1>验证码</h1>
<div class="hutoll">
<h3>hutool工具</h3>
<span>
LineCaptcha:
<img :src="LineCaptcha" alt="验证码" @click="changeCaptchaImg('Line')"
/></span>
<span>
CircleCaptcha:
<img
:src="CircleCaptcha"
alt="验证码"
@click="changeCaptchaImg('Circle')"
/></span>
<span>
ShearCaptcha:
<img
:src="ShearCaptcha"
alt="验证码"
@click="changeCaptchaImg('Shear')"
/></span>
<span>
GifCaptcha:
<img :src="GifCaptcha" alt="验证码" @click="changeCaptchaImg('Gif')"
/></span>
<span>
DiyCharCaptcha:
<img
:src="DiyCharCaptcha"
alt="验证码"
@click="changeCaptchaImg('DiyChar')"
/></span>
<span>
DiyComputeCaptcha:
<img
:src="DiyComputeCaptcha"
alt="验证码"
@click="changeCaptchaImg('DiyCompute')"
/></span>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";
import {
getLineCaptcha,
getCircleCaptcha,
getShearCaptcha,
getGifCaptcha,
getDiyCharCaptcha,
getDiyComputeCaptcha,
} from "@/api/captcha/index";
import { ElMessage } from "element-plus";
const LineCaptcha = ref("");
const CircleCaptcha = ref("");
const ShearCaptcha = ref("");
const GifCaptcha = ref("");
const DiyCharCaptcha = ref("");
const DiyComputeCaptcha = ref("");
const captchaRefs = {
Line: LineCaptcha,
Circle: CircleCaptcha,
Shear: ShearCaptcha,
Gif: GifCaptcha,
DiyChar: DiyCharCaptcha,
DiyCompute: DiyComputeCaptcha,
};
const getCaptcha = async (captchaType) => {
try {
let res;
switch (captchaType) {
case "Line":
res = await getLineCaptcha();
break;
case "Circle":
res = await getCircleCaptcha();
break;
case "Shear":
res = await getShearCaptcha();
break;
case "Gif":
res = await getGifCaptcha();
break;
case "DiyChar":
res = await getDiyCharCaptcha();
break;
case "DiyCompute":
res = await getDiyComputeCaptcha();
break;
default:
throw new Error("Invalid captcha type");
}
captchaRefs[captchaType].value = res.data;
} catch (error) {
console.error(`获取 ${captchaType} 验证码时出错:`, error);
ElMessage.error(`获取 ${captchaType} 验证码时出错,请稍后再试`);
}
};
const changeCaptchaImg = async (captchaType) => {
await getCaptcha(captchaType);
};
const revokeCaptchaUrls = () => {
for (const captchaType in captchaRefs) {
if (captchaRefs[captchaType].value) {
URL.revokeObjectURL(captchaRefs[captchaType].value);
}
}
};
onMounted(async () => {
await Promise.all([
getCaptcha("Line"),
getCaptcha("Circle"),
getCaptcha("Shear"),
getCaptcha("Gif"),
getCaptcha("DiyChar"),
getCaptcha("DiyCompute"),
]);
});
onBeforeUnmount(() => {
revokeCaptchaUrls();
});
</script>
<style lang="scss" scoped></style>