在 Spring Boot 中生成图形验证码并校验其正确性,通常包括以下步骤:
- 生成验证码图片和对应的验证码值。
- 将验证码值存储到
Session
或其他存储中(如 Redis)。- 将验证码图片返回给客户端。
- 客户端提交表单时,校验用户输入的验证码是否正确。
一、添加依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
二、生成验证码工具类
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Random;public class CaptchaUtil {// 验证码字符集private static final String CHAR_SET = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz";private static final int WIDTH = 120; // 图片宽度private static final int HEIGHT = 40; // 图片高度private static final int FONT_SIZE = 30; // 字体大小private static final int CODE_LENGTH = 4; // 验证码长度private static final int LINE_COUNT = 5; // 干扰线数量private static final int NOISE_COUNT = 30; // 噪点数量// 生成随机验证码public static String generateCaptchaCode() {Random random = new Random();StringBuilder captcha = new StringBuilder();for (int i = 0; i < CODE_LENGTH; i++) {captcha.append(CHAR_SET.charAt(random.nextInt(CHAR_SET.length())));}return captcha.toString();}// 生成验证码图片public static BufferedImage generateCaptchaImage(String captchaCode) {BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);Graphics2D g = image.createGraphics();// 设置背景色(随机浅色)g.setColor(getRandomLightColor());g.fillRect(0, 0, WIDTH, HEIGHT);// 设置字体(随机选择字体)g.setFont(getRandomFont());g.setColor(getRandomDarkColor());// 绘制验证码字符for (int i = 0; i < CODE_LENGTH; i++) {// 随机旋转字符角度double theta = Math.toRadians(new Random().nextInt(30) - 15);g.rotate(theta, i * (WIDTH / CODE_LENGTH) + 10, HEIGHT / 2 + 10);g.drawString(String.valueOf(captchaCode.charAt(i)), i * (WIDTH / CODE_LENGTH) + 10, HEIGHT / 2 + 10);g.rotate(-theta, i * (WIDTH / CODE_LENGTH) + 10, HEIGHT / 2 + 10);}// 绘制干扰线g.setColor(getRandomDarkColor());Random random = new Random();for (int i = 0; i < LINE_COUNT; 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);}// 绘制噪点for (int i = 0; i < NOISE_COUNT; i++) {int x = random.nextInt(WIDTH);int y = random.nextInt(HEIGHT);image.setRGB(x, y, getRandomDarkColor().getRGB());}g.dispose();return image;}// 将图片转换为字节数组public static byte[] imageToBytes(BufferedImage image) throws IOException {ByteArrayOutputStream baos = new ByteArrayOutputStream();ImageIO.write(image, "PNG", baos);return baos.toByteArray();}// 获取随机浅色private static Color getRandomLightColor() {Random random = new Random();return new Color(random.nextInt(100) + 155, random.nextInt(100) + 155, random.nextInt(100) + 155);}// 获取随机深色private static Color getRandomDarkColor() {Random random = new Random();return new Color(random.nextInt(100), random.nextInt(100), random.nextInt(100));}// 获取随机字体private static Font getRandomFont() {String[] fontNames = { "Arial", "Verdana", "Georgia", "Times New Roman", "Courier New" };Random random = new Random();return new Font(fontNames[random.nextInt(fontNames.length)], Font.BOLD, FONT_SIZE);}
}
三、验证码控制器
import com.example.demo.util.CaptchaUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
@RestController
public class CaptchaController {// 生成验证码图片@GetMapping("/captcha")public ResponseEntity<byte[]> generateCaptcha(HttpSession session) throws IOException {// 生成验证码String captchaCode = CaptchaUtil.generateCaptchaCode();// 将验证码存储到Sessionsession.setAttribute("captcha", captchaCode);// 生成图片BufferedImage image = CaptchaUtil.generateCaptchaImage(captchaCode);// 将图片转换为字节数组byte[] imageBytes = CaptchaUtil.imageToBytes(image);// 返回图片return ResponseEntity.ok().header(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_PNG_VALUE).body(imageBytes);}// 校验验证码@PostMapping("/verify")public String verifyCaptcha(@RequestParam String userCaptcha, HttpSession session) {// 获取Session中存储的验证码String storedCaptcha = (String) session.getAttribute("captcha");// 清除Session中的验证码,避免重复使用session.removeAttribute("captcha");// 校验用户输入的验证码if (storedCaptcha != null && storedCaptcha.equalsIgnoreCase(userCaptcha)) {return "验证码正确";} else {return "验证码错误";}}
}
四、测试验证码功能
http://localhost:8080/captcha
实际开发中,验证码通常存储于 Redis 中,设置五分钟后自动过期。或验证通过之后进行删除。实际开发还有更高级的验证码功能(如滑动验证码、点选验证码)可自行研究哈。