当前位置: 首页 > news >正文

Java 绘制图形验证码

在 Spring Boot 中生成图形验证码并校验其正确性,通常包括以下步骤:

  1. 生成验证码图片和对应的验证码值。
  2. 将验证码值存储到 Session 或其他存储中(如 Redis)。
  3. 将验证码图片返回给客户端。
  4. 客户端提交表单时,校验用户输入的验证码是否正确。

    一、添加依赖

    <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();
            // 将验证码存储到Session
            session.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 中,设置五分钟后自动过期。或验证通过之后进行删除。实际开发还有更高级的验证码功能(如滑动验证码、点选验证码)可自行研究哈。

    相关文章:

  1. 浏览器对一个资源设置了缓存,如何清除缓存,且后续请求不命中缓存
  2. docker删除容器不成功问题
  3. Matlab 多输入系统极点配置
  4. python+MySQL+HTML实现产品管理系统
  5. 打印模板公司名称动态实现自动匹配打印
  6. 基于YOLO目标检测 识别 APP页面点击跳转页面加载时间,视频拆帧统计应用场景,场景数获取时间差,前端性能测试和统计
  7. ChatGPT推理模型通用模型大解析!
  8. 如何管理需求
  9. 从零开始的python学习(六)P81+P82+P83+P84+P85
  10. Vitis HLS中的hls::vector详解 矢量数据类型 单指令流多数据流 (SIMD)
  11. python2和python3的区别
  12. 基于SpringBoot+Vue+uniapp的高校招聘小程序+LW参考示例
  13. 二叉树的层序遍历
  14. Implementing SAP BPC Embedded - 2nd Edition
  15. 【unity】GPU顶点动画
  16. 【推理】大模型ReasonGraph:推理路径的可视化论文及代码分析
  17. 神聖的綫性代數速成例題3. 矩陣列數的極限、矩陣範數、行列式的計算
  18. 【Agent】OpenManus 项目架构分析
  19. LLMs之CoD:《Chain of Draft: Thinking Faster by Writing Less》翻译与解读
  20. springboot+vue如何前后端联调,手搓前后端分离项目
  21. 美乌签署协议建立美乌重建投资基金
  22. 美国务院宣布新一轮与伊朗相关的制裁
  23. 国务院安委办、应急管理部进一步调度部署“五一”假期安全防范工作
  24. 水利部将联合最高检开展黄河流域水生态保护专项行动
  25. 马上评丨上热搜的协和“4+4”模式,如何面对舆论审视
  26. 国台办:提醒相关人员不要假借去第三地名义绕道赴台