本文目录导读:

我来详细讲解Java验证码的完整开发案例,包括图片验证码和短信验证码两种常见类型。
图片验证码案例
添加依赖(Maven项目)
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Redis(用于存储验证码) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
验证码生成工具类
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.Random;
public class CaptchaUtil {
private static final int WIDTH = 120;
private static final int HEIGHT = 40;
private static final int CODE_LENGTH = 4;
private static final String CHARACTERS = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
/**
* 生成验证码
* @return 包含验证码文本和Base64图片的Map
*/
public static CaptchaResult generateCaptcha() {
Random random = new Random();
// 生成随机验证码
StringBuilder code = new StringBuilder();
for (int i = 0; i < CODE_LENGTH; i++) {
code.append(CHARACTERS.charAt(random.nextInt(CHARACTERS.length())));
}
// 创建图片
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
// 设置背景色
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
// 设置边框
g.setColor(Color.LIGHT_GRAY);
g.drawRect(0, 0, WIDTH - 1, HEIGHT - 1);
// 添加干扰线
g.setColor(Color.GRAY);
for (int i = 0; i < 10; i++) {
int x1 = random.nextInt(WIDTH);
int y1 = random.nextInt(HEIGHT);
int x2 = random.nextInt(WIDTH);
int y2 = random.nextInt(HEIGHT);
g.drawLine(x1, y1, x2, y2);
}
// 绘制验证码
g.setFont(new Font("Arial", Font.BOLD, 24));
for (int i = 0; i < CODE_LENGTH; i++) {
// 随机颜色
g.setColor(new Color(random.nextInt(200), random.nextInt(200), random.nextInt(200)));
// 随机旋转角度
double angle = random.nextDouble() * 0.3 - 0.15;
g.rotate(angle, 15 + i * 25, 25);
g.drawString(String.valueOf(code.charAt(i)), 15 + i * 25, 28);
g.rotate(-angle, 15 + i * 25, 25);
}
g.dispose();
// 转换为Base64
String base64Image = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
byte[] imageBytes = baos.toByteArray();
base64Image = Base64.getEncoder().encodeToString(imageBytes);
} catch (IOException e) {
e.printStackTrace();
}
return new CaptchaResult(code.toString(), base64Image);
}
// 验证码结果类
public static class CaptchaResult {
private String code;
private String base64Image;
public CaptchaResult(String code, String base64Image) {
this.code = code;
this.base64Image = base64Image;
}
public String getCode() {
return code;
}
public String getBase64Image() {
return base64Image;
}
}
}
验证码控制器
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/api/captcha")
public class CaptchaController {
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 获取验证码
*/
@GetMapping("/generate")
public Result generateCaptcha() {
// 生成验证码
CaptchaUtil.CaptchaResult captchaResult = CaptchaUtil.generateCaptcha();
// 生成唯一标识
String captchaId = UUID.randomUUID().toString().replace("-", "");
// 存储到Redis,5分钟有效
redisTemplate.opsForValue().set(
"captcha:" + captchaId,
captchaResult.getCode(),
5,
TimeUnit.MINUTES
);
// 返回结果
Map<String, String> data = new HashMap<>();
data.put("captchaId", captchaId);
data.put("captchaImage", "data:image/png;base64," + captchaResult.getBase64Image());
return Result.success(data);
}
/**
* 验证验证码
*/
@PostMapping("/verify")
public Result verifyCaptcha(@RequestBody VerifyRequest request) {
String redisKey = "captcha:" + request.getCaptchaId();
String storedCode = redisTemplate.opsForValue().get(redisKey);
if (storedCode == null) {
return Result.error("验证码已过期");
}
if (!storedCode.equalsIgnoreCase(request.getCaptchaCode())) {
return Result.error("验证码错误");
}
// 验证成功后删除验证码(一次性使用)
redisTemplate.delete(redisKey);
return Result.success("验证成功");
}
// 验证请求体
static class VerifyRequest {
private String captchaId;
private String captchaCode;
// getter和setter方法
public String getCaptchaId() { return captchaId; }
public void setCaptchaId(String captchaId) { this.captchaId = captchaId; }
public String getCaptchaCode() { return captchaCode; }
public void setCaptchaCode(String captchaCode) { this.captchaCode = captchaCode; }
}
}
统一响应类
public class Result {
private int code;
private String message;
private Object data;
public static Result success(Object data) {
Result result = new Result();
result.code = 200;
result.message = "success";
result.data = data;
return result;
}
public static Result error(String message) {
Result result = new Result();
result.code = 400;
result.message = message;
return result;
}
// getter和setter方法
public int getCode() { return code; }
public void setCode(int code) { this.code = code; }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
public Object getData() { return data; }
public void setData(Object data) { this.data = data; }
}
前端HTML示例
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">验证码示例</title>
</head>
<body>
<div style="margin: 20px;">
<h2>图形验证码示例</h2>
<div>
<input type="text" id="captchaCode" placeholder="请输入验证码">
<img id="captchaImg" src="" onclick="refreshCaptcha()" style="cursor: pointer;">
<button onclick="verifyCaptcha()">验证</button>
</div>
<div id="result" style="margin-top: 10px;"></div>
</div>
<script>
// 获取验证码
function getCaptcha() {
fetch('/api/captcha/generate')
.then(response => response.json())
.then(data => {
if (data.code === 200) {
document.getElementById('captchaImg').src = data.data.captchaImage;
document.getElementById('captchaImg').dataset.captchaId = data.data.captchaId;
}
});
}
// 刷新验证码
function refreshCaptcha() {
getCaptcha();
}
// 验证验证码
function verifyCaptcha() {
const captchaId = document.getElementById('captchaImg').dataset.captchaId;
const captchaCode = document.getElementById('captchaCode').value;
fetch('/api/captcha/verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
captchaId: captchaId,
captchaCode: captchaCode
})
})
.then(response => response.json())
.then(data => {
document.getElementById('result').innerHTML =
data.code === 200 ?
'<span style="color: green;">✓ 验证成功</span>' :
'<span style="color: red;">✗ ' + data.message + '</span>';
});
}
// 页面加载时获取验证码
window.onload = getCaptcha;
</script>
</body>
</html>
短信验证码案例
短信验证码服务
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.Random;
import java.util.concurrent.TimeUnit;
@Service
public class SmsCaptchaService {
@Autowired
private StringRedisTemplate redisTemplate;
// 阿里云短信服务(示例中使用模拟实现)
@Autowired(required = false)
private SmsService smsService;
/**
* 发送短信验证码
*/
public Result sendSmsCaptcha(String phone) {
// 检查发送频率(60秒内不能重复发送)
String rateLimitKey = "sms:rate:" + phone;
if (redisTemplate.hasKey(rateLimitKey)) {
return Result.error("发送过于频繁,请60秒后重试");
}
// 生成6位随机验证码
String captcha = String.format("%06d", new Random().nextInt(999999));
// 存储验证码到Redis(5分钟有效)
String captchaKey = "sms:captcha:" + phone;
redisTemplate.opsForValue().set(captchaKey, captcha, 5, TimeUnit.MINUTES);
// 设置发送频率限制
redisTemplate.opsForValue().set(rateLimitKey, "1", 60, TimeUnit.SECONDS);
// 发送短信(模拟)
boolean sendSuccess = sendSms(phone, captcha);
if (sendSuccess) {
System.out.println("短信验证码发送成功:" + phone + " - " + captcha);
return Result.success("验证码已发送");
} else {
return Result.error("短信发送失败");
}
}
/**
* 验证短信验证码
*/
public Result verifySmsCaptcha(String phone, String captcha) {
String captchaKey = "sms:captcha:" + phone;
String storedCaptcha = redisTemplate.opsForValue().get(captchaKey);
if (storedCaptcha == null) {
return Result.error("验证码已过期");
}
if (!storedCaptcha.equals(captcha)) {
return Result.error("验证码错误");
}
// 验证成功后删除验证码
redisTemplate.delete(captchaKey);
return Result.success("验证成功");
}
/**
* 模拟发送短信
*/
private boolean sendSms(String phone, String captcha) {
// 实际项目中调用短信服务商API
// 阿里云短信、腾讯云短信等
try {
// 模拟发送延迟
Thread.sleep(100);
return true;
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
}
}
短信验证码控制器
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/sms")
public class SmsCaptchaController {
@Autowired
private SmsCaptchaService smsCaptchaService;
/**
* 发送短信验证码
*/
@PostMapping("/send")
public Result sendSmsCaptcha(@RequestBody SendSmsRequest request) {
// 验证手机号格式
if (!isValidPhone(request.getPhone())) {
return Result.error("手机号格式不正确");
}
return smsCaptchaService.sendSmsCaptcha(request.getPhone());
}
/**
* 验证短信验证码
*/
@PostMapping("/verify")
public Result verifySmsCaptcha(@RequestBody VerifySmsRequest request) {
if (!isValidPhone(request.getPhone())) {
return Result.error("手机号格式不正确");
}
if (request.getCaptcha() == null || request.getCaptcha().length() != 6) {
return Result.error("验证码格式不正确");
}
return smsCaptchaService.verifySmsCaptcha(request.getPhone(), request.getCaptcha());
}
/**
* 简单手机号验证
*/
private boolean isValidPhone(String phone) {
return phone != null && phone.matches("^1[3-9]\\d{9}$");
}
// 请求体类
static class SendSmsRequest {
private String phone;
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
}
static class VerifySmsRequest {
private String phone;
private String captcha;
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
public String getCaptcha() { return captcha; }
public void setCaptcha(String captcha) { this.captcha = captcha; }
}
}
配置与启动
application.yml 配置
spring:
redis:
host: localhost
port: 6379
timeout: 5000
# 如果使用阿里云短信服务,配置如下
aliyun:
sms:
access-key-id: your-access-key-id
access-key-secret: your-access-key-secret
sign-name: 您的签名
template-code: SMS_123456789
主启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CaptchaApplication {
public static void main(String[] args) {
SpringApplication.run(CaptchaApplication.class, args);
}
}
使用示例
获取图片验证码
GET /api/captcha/generate
验证图片验证码
POST /api/captcha/verify
Body: {
"captchaId": "生成的captchaId",
"captchaCode": "用户输入的验证码"
}
发送短信验证码
POST /api/sms/send
Body: {
"phone": "13800138000"
}
验证短信验证码
POST /api/sms/verify
Body: {
"phone": "13800138000",
"captcha": "123456"
}
这个案例提供了完整的验证码解决方案,包括:
- 图形验证码的生成与验证
- 短信验证码的发送与验证
- Redis存储验证码(支持过期时间)
- 防刷机制(发送频率限制)
- 前端集成示例
你可以根据实际需求进行扩展,比如添加更复杂的图形验证码(中文、计算题等),或者集成实际的短信服务商API。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播