Spring Boot工程集成验证码生成与验证功能教程

🌟 前言

欢迎来到我的技术小宇宙!🌌 这里不仅是我记录技术点滴的后花园,也是我分享学习心得和项目经验的乐园。📚 无论你是技术小白还是资深大牛,这里总有一些内容能触动你的好奇心。🔍

  • 🤖 洛可可白:个人主页

  • 🔥 个人专栏:✅前端技术 ✅后端技术

  • 🏠 个人博客:洛可可白博客

  • 🐱 代码获取:bestwishes0203

  • 📷 封面壁纸:洛可可白wallpaper

CDDN

文章目录

  • Spring Boot工程集成验证码生成与验证功能教程
    • 1. 创建验证码工具类
    • 2. 控制层实现
    • 3. 客户端展示验证码
    • 4. 验证验证码
    • 📌 联系方式
    • 🚀 获取源代码
    • 🎉 结语

Spring Boot工程集成验证码生成与验证功能教程

验证码是一种常见的安全机制,用于防止自动化工具(如爬虫)对网站进行恶意操作。在Web应用中,验证码通常以图像的形式出现,要求用户输入图像中显示的字符。本文将介绍如何在Spring Boot工程中实现一个随机生成验证码的功能。

1. 创建验证码工具类

首先,我们需要创建一个工具类VerifyCodeUtils,用于生成随机验证码并输出为图像。

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Random;

public class VerifyCodeUtils {
    //使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符
    public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
    private static Random random = new Random();


    /**
     * 使用系统默认字符源生成验证码
     *
     * @param verifySize 验证码长度
     * @return
     */
    public static String generateVerifyCode(int verifySize) {
        return generateVerifyCode(verifySize, VERIFY_CODES);
    }

    /**
     * 使用指定源生成验证码
     *
     * @param verifySize 验证码长度
     * @param sources    验证码字符源
     * @return
     */
    public static String generateVerifyCode(int verifySize, String sources) {
        if (sources == null || sources.length() == 0) {
            sources = VERIFY_CODES;
        }
        int codesLen = sources.length();
        Random rand = new Random(System.currentTimeMillis());
        StringBuilder verifyCode = new StringBuilder(verifySize);
        for (int i = 0; i < verifySize; i++) {
            verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1)));
        }
        return verifyCode.toString();
    }

    /**
     * 生成随机验证码文件,并返回验证码值
     *
     * @param w
     * @param h
     * @param outputFile
     * @param verifySize
     * @return
     * @throws IOException
     */
    public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException {
        String verifyCode = generateVerifyCode(verifySize);
        outputImage(w, h, outputFile, verifyCode);
        return verifyCode;
    }

    /**
     * 输出随机验证码图片流,并返回验证码值
     *
     * @param w
     * @param h
     * @param os
     * @param verifySize
     * @return
     * @throws IOException
     */
    public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException {
        String verifyCode = generateVerifyCode(verifySize);
        outputImage(w, h, os, verifyCode);
        return verifyCode;
    }

    /**
     * 生成指定验证码图像文件
     *
     * @param w
     * @param h
     * @param outputFile
     * @param code
     * @throws IOException
     */
    public static void outputImage(int w, int h, File outputFile, String code) throws IOException {
        if (outputFile == null) {
            return;
        }
        File dir = outputFile.getParentFile();
        if (!dir.exists()) {
            dir.mkdirs();
        }
        try {
            outputFile.createNewFile();
            FileOutputStream fos = new FileOutputStream(outputFile);
            outputImage(w, h, fos, code);
            fos.close();
        } catch (IOException e) {
            throw e;
        }
    }

    /**
     * 输出指定验证码图片流
     *
     * @param w
     * @param h
     * @param os
     * @param code
     * @throws IOException
     */
    public static void outputImage(int w, int h, OutputStream os, String code) throws IOException {
        int verifySize = code.length();
        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Random rand = new Random();
        Graphics2D g2 = image.createGraphics();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        Color[] colors = new Color[5];
        Color[] colorSpaces = new Color[]{Color.WHITE, Color.CYAN,
                Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,
                Color.PINK, Color.YELLOW};
        float[] fractions = new float[colors.length];
        for (int i = 0; i < colors.length; i++) {
            colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
            fractions[i] = rand.nextFloat();
        }
        Arrays.sort(fractions);

        g2.setColor(Color.GRAY);// 设置边框色
        g2.fillRect(0, 0, w, h);

        Color c = getRandColor(200, 250);
        g2.setColor(c);// 设置背景色
        g2.fillRect(0, 2, w, h - 4);

        //绘制干扰线
        Random random = new Random();
        g2.setColor(getRandColor(160, 200));// 设置线条的颜色
        for (int i = 0; i < 20; i++) {
            int x = random.nextInt(w - 1);
            int y = random.nextInt(h - 1);
            int xl = random.nextInt(6) + 1;
            int yl = random.nextInt(12) + 1;
            g2.drawLine(x, y, x + xl + 40, y + yl + 20);
        }

        // 添加噪点
        float yawpRate = 0.05f;// 噪声率
        int area = (int) (yawpRate * w * h);
        for (int i = 0; i < area; i++) {
            int x = random.nextInt(w);
            int y = random.nextInt(h);
            int rgb = getRandomIntColor();
            image.setRGB(x, y, rgb);
        }

        shear(g2, w, h, c);// 使图片扭曲

        g2.setColor(getRandColor(100, 160));
        int fontSize = h - 4;
        Font font = new Font("Algerian", Font.ITALIC, fontSize);
        g2.setFont(font);
        char[] chars = code.toCharArray();
        for (int i = 0; i < verifySize; i++) {
            AffineTransform affine = new AffineTransform();
            affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize / 2, h / 2);
            g2.setTransform(affine);
            g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10);
        }

        g2.dispose();
        ImageIO.write(image, "jpg", os);
    }

    private static Color getRandColor(int fc, int bc) {
        if (fc > 255)
            fc = 255;
        if (bc > 255)
            bc = 255;
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }

    private static int getRandomIntColor() {
        int[] rgb = getRandomRgb();
        int color = 0;
        for (int c : rgb) {
            color = color << 8;
            color = color | c;
        }
        return color;
    }

    private static int[] getRandomRgb() {
        int[] rgb = new int[3];
        for (int i = 0; i < 3; i++) {
            rgb[i] = random.nextInt(255);
        }
        return rgb;
    }

    private static void shear(Graphics g, int w1, int h1, Color color) {
        shearX(g, w1, h1, color);
        shearY(g, w1, h1, color);
    }

    private static void shearX(Graphics g, int w1, int h1, Color color) {

        int period = random.nextInt(2);

        boolean borderGap = true;
        int frames = 1;
        int phase = random.nextInt(2);

        for (int i = 0; i < h1; i++) {
            double d = (double) (period >> 1)
                    * Math.sin((double) i / (double) period
                    + (6.2831853071795862D * (double) phase)
                    / (double) frames);
            g.copyArea(0, i, w1, 1, (int) d, 0);
            if (borderGap) {
                g.setColor(color);
                g.drawLine((int) d, i, 0, i);
                g.drawLine((int) d + w1, i, w1, i);
            }
        }

    }

    private static void shearY(Graphics g, int w1, int h1, Color color) {

        int period = random.nextInt(40) + 10; // 50;

        boolean borderGap = true;
        int frames = 20;
        int phase = 7;
        for (int i = 0; i < w1; i++) {
            double d = (double) (period >> 1)
                    * Math.sin((double) i / (double) period
                    + (6.2831853071795862D * (double) phase)
                    / (double) frames);
            g.copyArea(i, 0, 1, h1, 0, (int) d);
            if (borderGap) {
                g.setColor(color);
                g.drawLine(i, (int) d, i, 0);
                g.drawLine(i, (int) d + h1, i, h1);
            }

        }

    }
}

2. 控制层实现

在Spring Boot的控制器中,我们需要提供一个接口来生成验证码并将其发送给客户端。

// VerifyController.java
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class VerifyController {

    @GetMapping("/generateImageCode")
    public void generateImageCode(HttpSession session, HttpServletResponse response) throws IOException {
        //随机生成四位随机数
        String code = VerifyCodeUtils.generateVerifyCode(4);
        //保存到session域中
        session.setAttribute("code", code);
        //根据随机数生成图片,reqponse响应图片
        response.setContentType("image/png");
        ServletOutputStream os = response.getOutputStream();
        VerifyCodeUtils.outputImage(130, 60, os, code);
    }
}

3. 客户端展示验证码

在Web页面中,我们需要添加一个图像标签来展示验证码。

<!-- 在HTML中添加验证码图像 -->
<img src="/generateImageCode" alt="验证码" onclick="this.src='/generateImageCode?'+Math.random();" />

4. 验证验证码

在用户提交表单时,我们需要验证用户输入的验证码是否正确。这通常在后端进行,通过比较用户输入的验证码与Session中保存的验证码。

// 在登录方法中验证验证码
@PostMapping("/login")
public ResponseEntity<?> login(@RequestParam String username, @RequestParam String password, HttpSession session) {
    // 获取用户输入的验证码
    String userInputCode = request.getParameter("code");
    // 获取Session中保存的验证码
    String sessionCode = (String) session.getAttribute("code");
    // 验证验证码
    if (!sessionCode.equals(inputCode)) {
        // 验证码错误
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("验证码错误");
    }
    // 验证码正确,继续登录逻辑
    // ...
}

📌 联系方式

如果您对我们的项目感兴趣,或者有任何技术问题想要探讨,欢迎通过以下方式与我联系。我非常期待与您交流,共同学习,共同进步!🌊💡🤖

  • 邮箱:2109664977@qq.com 📧
  • Gitee:https://gitee.com/bestwishes0203 🐱
  • GitHub:https://github.com/bestwishes0203 🐙
  • CSDN主页:https://blog.csdn.net/interest_ing_/ 📖
  • 个人博客:访问我的博客 🏠

🚀 获取源代码

  • 后端案例:https://gitee.com/bestwishes0203/Front-end-example
  • 前端案例:https://gitee.com/bestwishes0203/Back-end-example

🎉 结语

感谢你的访问,如果你对我的技术文章或项目感兴趣,欢迎通过以上方式与我联系。让我们一起在技术的道路上不断前行!🚀

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/439443.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于springboot的大学生智能消费记账系统的设计与实现(程序+数据库+文档)

** &#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;** 一、研究背景…

1688平台上如何高效一键发布商品?如何接入1688API官方商品

1688平台上发布商品&#xff0c;现在很有优势。很多商品可以直接对接海外&#xff01; 1688平台发布商品的优势在1688平台发布商品的优势主要包括&#xff1a; 产品种类丰富&#xff1a;1688作为国内最大的B2B电商平台&#xff0c;提供的产品种类繁多&#xff0c;覆盖了各个行…

345.反转字符串中的元音字母

题目&#xff1a;给你一个字符串 s &#xff0c;仅反转字符串中的所有元音字母&#xff0c;并返回结果字符串。 元音字母包括 a、e、i、o、u&#xff0c;且可能以大小写两种形式出现不止一次。 class Solution {//画图&#xff0c;好理解点public String reverseVowels(String…

测试点点延迟和带宽的脚本总结

从队列中获取节点名 我们有时候需要从任务队列中取出完整的节点名称&#xff0c;比如cn[8044-8046,8358-8360,8926-8928,9002-9004]&#xff0c;可以给定参数input_str也可以在脚本中直接写死。 import re import subprocess import sysinput_str "cn[7512-7519,7545-75…

尚硅谷SpringBoot3笔记

推荐课程&#xff1a;03.快速入门-示例Demo_哔哩哔哩_bilibili 目录 01--示例demo 01--示例demo 1、在新建项目创建一个Maven 模块 2、引入 spring-boot-starter-parent 和 spring-boot-starter-web 依赖 spring-boot-starter-parent 是 Spring Boot 提供的一个用于构建 Spr…

爬虫实战——巴黎圣母院新闻【内附超详细教程,你上你也行】

文章目录 发现宝藏一、 目标二、简单分析网页1. 寻找所有新闻2. 分析模块、版面和文章 三、爬取新闻1. 爬取模块2. 爬取版面3. 爬取文章 四、完整代码五、效果展示 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不…

四川宏博蓬达法律咨询:专业领航,法治路上的坚实后盾

在法治社会中&#xff0c;法律咨询服务扮演着举足轻重的角色。四川宏博蓬达法律咨询&#xff0c;作为业界的佼佼者&#xff0c;以其正规可靠的服务赢得了广大客户的信赖和好评。今天&#xff0c;我们就来一起了解一下这家在法律服务领域备受赞誉的企业。 一、正规资质&#xff…

数据结构之单链表详解(C语言手撕)

​ &#x1f389;个人名片&#xff1a;&#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生 &#x1f648;个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE &#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN…

Python与Go代码转换库之grumpy使用详解

概要 在软件开发领域,Python 和 Go 是两种备受欢迎的编程语言,它们各自拥有独特的优势和特点。Python 以其简洁、易学和强大的生态系统而闻名,而 Go 则以其高效、并发和简洁的语法而受到广泛青睐。然而,在某些情况下,开发人员可能会希望将 Python 代码转换为 Go 代码,以…

西门子S120故障报警F30003的解决办法总结

西门子S120故障报警F30003的解决办法总结 如下图所示&#xff0c;压机在回程时突然出现报警&#xff0c;故障代码为&#xff1a;30003&#xff0c; 如下图所示&#xff0c;查找手册可以看到F30003的报警分析为&#xff1a;直流母线欠压 如下图所示&#xff0c;本来想测量输入端…

升工作效率,确保公文准确性——爱校对软件的职场革命

在当今快节奏的工作环境中&#xff0c;效率和准确性成为了每个职场人士的追求目标。尤其是在处理官方文件和公文材料时&#xff0c;一点小小的错误都可能造成沟通障碍甚至误解&#xff0c;给工作带来不必要的困扰。这时&#xff0c;一款高效、精准、易用的校对软件就显得尤为重…

Nginx配置http访问转https

场景: 我们通常使用http://www.xxx.com访问自己后台或网站时,浏览器会提示不安全,这就让上层领导看着认为我们做的网站不安全,而通过https访问就没有不会出现这样的问题 配置https前提条件:我们去申请ssl证书, 看自己的域名是在哪个平台购买的 可去 阿里云 或 腾讯云申请免费的…

rocketmq学习笔记(一)安装部署

初次使用rocketmq&#xff0c;记录一下全流程步骤。 1、下载安装包 首先在官网&#xff0c;下载安装包&#xff0c;可也根据官方文档进行部署&#xff0c;但有一些细节没说明&#xff0c;可能会有坑&#xff0c;本文会尽量详细的描述每个步骤&#xff0c;把我踩过的坑填补上。…

P5149 会议座位 题解 归并排序 逆序对

会议座位 传送门 题目背景 话说校长最近很喜欢召开全校教职工大会&#xff0c;让老师们强行听他装逼 题目描述 现在校长在校园网上公布了一份座位表&#xff0c; n n n 位老师从左到右依次排成一行。老师们都对这个座位很满意。 然而到了开会时&#xff0c;校长不小心把座…

开源的前端思维导图库介绍

在开源社区中&#xff0c;有许多优秀的思维导图库可供开发者使用。这些库通常具有丰富的功能和灵活的API&#xff0c;可以满足不同需求的前端开发。以下是一些流行的开源前端思维导图库&#xff0c;以及它们的特点和区别。 1. **MindMap** 特点&#xff1a; - 基于原生…

c1-第三周

文章目录 1月份2.定义一个整形数组arr2.定义整形栈s3.输入一个字符串包括大小写和数字&#xff0c;将其中的大写英文字母改为小写&#xff0c;并且输出数字个数4.根据下面数据&#xff0c;编程实现要求功能&#xff1a; 9月1.编写程序实现以下功能或问题3.完成以下功能4.对运算…

义乌慧鼎思是做什么的?

根据天眼查的信息&#xff0c;我们可以对其进行一番探究。义乌慧鼎思(义乌市慧鼎思商务信息咨询有限公司)成立于2021年&#xff0c;注册地位于我国浙江省义乌市。从其名称来看&#xff0c;“慧鼎思”寓意着智慧、重量和思考&#xff0c;这三个词汇也许能为我们揭示企业的经营理…

基于JAVA+ springboot实现的抗疫物质信息管理系统

基于JAVA springboot实现的抗疫物质信息管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 …

IR 召回测试数据集(中文测试集)——T2Ranking

文章排名包括两个阶段&#xff1a;文章检索和文章重排序&#xff0c;这对信息检索&#xff08;IR&#xff09;领域的学术界和业界来说都是重要而具有挑战性的课题。然而&#xff0c;常用的文章排名数据集通常集中在英语语言上。对于非英语场景&#xff0c;如中文&#xff0c;现…

简单实现微信机器人-接入ChatGPT3.5

前端基于开源项目&#xff1a;wechaty实现微信网页版功能&#xff0c;感兴趣的小伙伴可以自行研究。 前端代码已开源&#xff1a;https://github.com/labi-xiaoxin/wechat-bot-wechat4u.git 本项目搭建愿景&#xff1a; 1、在无法科学上网的情况下&#xff0c;实现ChatGPT对话…