最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?Boot使用Hutool快速集成驗證碼的兩種方案

 更新時間:2026年02月10日 09:13:23   作者:???傀儡師  
驗證碼作為一種簡單而有效的身份驗證手段,被廣泛應用于各種在線服務中,這篇文章主要介紹了Spring?Boot使用Hutool快速集成驗證碼的兩種方案,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

驗證碼這件“小事”,其實一點也不小

在登錄、注冊、找回密碼這些看似普通的業(yè)務場景里,驗證碼往往是系統(tǒng)安全的第一道防線。如果沒有它,爬蟲、撞庫腳本、暴力請求可以輕松把你的接口打穿;但如果驗證碼實現(xiàn)得不好,又會帶來代碼冗余、維護困難、樣式僵硬等一系列工程問題。

很多項目都會經(jīng)歷這樣一個過程:

  • 一開始:“不就是個驗證碼嗎?我自己畫!”
  • 后來:干擾線、字體、隨機數(shù)、Session、緩存控制……越寫越多
  • 最終:發(fā)現(xiàn)成熟工具庫早就幫你把坑填平了

這篇文章就圍繞一個核心問題展開:Spring Boot 項目里,驗證碼到底該怎么實現(xiàn),才是又穩(wěn)又省事?

我們會完整對比兩種方案:

  1. 完全自定義實現(xiàn)驗證碼生成邏輯(適合高度定制化需求)
  2. 基于 Hutool 快速集成多種驗證碼類型(絕大多數(shù)項目的最優(yōu)解)

為什么圖形驗證碼幾乎不可或缺?

驗證碼的本質(zhì)不是“折磨用戶”,而是區(qū)分人和程序。

在以下場景中,它幾乎是必選項:

  • 登錄接口防止BL破解
  • 注冊接口防止批量刷號
  • 密碼重置防止惡意撞庫
  • 重要操作前的人機確認

通過 隨機字符 + 干擾元素 的方式,驗證碼能顯著提高腳本攻擊成本,是最基礎、也是最有效的安全措施之一。

實現(xiàn)方式上,常見只有兩條路:

  1. 自己寫一套驗證碼生成邏輯
  2. 直接集成成熟工具庫

下面我們一條一條拆。

方案一:完全手寫一個驗證碼工具類

如果你的項目對驗證碼樣式、字體、干擾規(guī)則有非常強的定制需求,那么手寫一套邏輯是不可避免的。

驗證碼工具類設計思路

我們需要完成幾件事:

  1. 隨機生成驗證碼字符
  2. 繪制背景
  3. 繪制干擾線
  4. 繪制字符
  5. 將驗證碼結(jié)果存入 Session
  6. 將圖片輸出到響應流

項目目錄結(jié)構(gòu)

src/main/java
└── com
    └── icoderoad
        └── common
            └── util
                └── CaptchaCodeUtil.java

自定義驗證碼工具類實現(xiàn)

package com.icoderoad.common.util;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;

public class CaptchaCodeUtil {
    
    public static final String SESSION_KEY = "CAPTCHA_CODE";
    
    private final Random random = new Random();
    private final String codeSource = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    
    private int width = 80;
    private int height = 26;
    private int codeLength = 4;
    private int lineCount = 40;
    
    private Font getFont() {
        return new Font("Fixedsys", Font.PLAIN, 18);
    }
    
    private Color randomColor(int min, int max) {
        min = Math.min(min, 255);
        max = Math.min(max, 255);
        int r = min + random.nextInt(max - min);
        int g = min + random.nextInt(max - min);
        int b = min + random.nextInt(max - min);
        return new Color(r, g, b);
    }
    
    private void drawLine(Graphics g) {
        int x = random.nextInt(width);
        int y = random.nextInt(height);
        int xl = random.nextInt(12);
        int yl = random.nextInt(12);
        g.drawLine(x, y, x + xl, y + yl);
    }
    
    private String drawChar(Graphics g, int index) {
        g.setFont(getFont());
        g.setColor(randomColor(50, 160));
        String ch = String.valueOf(codeSource.charAt(random.nextInt(codeSource.length())));
        g.drawString(ch, 15 * index, 18);
        return ch;
    }
    
    public void generate(HttpServletRequest request, HttpServletResponse response) {
        HttpSession session = request.getSession();
        
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();
        
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, width, height);
        
        for (int i = 0; i < lineCount; i++) {
            g.setColor(randomColor(120, 200));
            drawLine(g);
        }
        
        StringBuilder code = new StringBuilder();
        for (int i = 1; i <= codeLength; i++) {
            code.append(drawChar(g, i));
        }
        
        session.setAttribute(SESSION_KEY, code.toString());
        g.dispose();
        
        try {
            ImageIO.write(image, "JPEG", response.getOutputStream());
        } catch (Exception e) {
            throw new RuntimeException("生成驗證碼失敗", e);
        }
    }
}

Controller 中調(diào)用驗證碼工具類

package com.icoderoad.web.controller;

import com.icoderoad.common.util.CaptchaCodeUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@RestController
public class CaptchaController {
    
    @GetMapping("/captcha/custom")
    public void customCaptcha(HttpServletRequest request, HttpServletResponse response) {
        response.setContentType("image/jpeg");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        
        new CaptchaCodeUtil().generate(request, response);
    }
}

?? 這種方式完全可控,但維護成本高、擴展困難

方案二:使用 Hutool 快速集成驗證碼(強烈推薦)

如果你不想把時間浪費在“重復造輪子”上,Hutool 基本就是最優(yōu)解。

引入依賴

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-captcha</artifactId>
    <version>5.8.6</version>
</dependency>

Hutool 四種驗證碼實戰(zhàn)示例

統(tǒng)一 Controller 路徑示例:com/icoderoad/web/controller/HutoolCaptchaController.java

1. 線條干擾驗證碼(LineCaptcha)

@GetMapping("/captcha/line")
public void line(HttpServletResponse response) throws IOException {
    LineCaptcha captcha = CaptchaUtil.createLineCaptcha(130, 38, 5, 5);
    response.setContentType("image/jpeg");
    response.setHeader("Cache-Control", "no-cache");
    captcha.write(response.getOutputStream());
}

2. 圓圈干擾驗證碼(CircleCaptcha)

@GetMapping("/captcha/circle")
public void circle(HttpServletResponse response) throws IOException {
    CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(130, 38, 5, 20);
    response.setContentType("image/jpeg");
    response.setHeader("Cache-Control", "no-cache");
    captcha.write(response.getOutputStream());
}

3. 扭曲驗證碼(ShearCaptcha)

@GetMapping("/captcha/shear")
public void shear(HttpServletResponse response) throws IOException {
    ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(130, 38, 5, 5);
    response.setContentType("image/jpeg");
    response.setHeader("Cache-Control", "no-cache");
    captcha.write(response.getOutputStream());
}

4. GIF 動態(tài)驗證碼(GifCaptcha)

@GetMapping("/captcha/gif")
public void gif(HttpServletResponse response) throws IOException {
    GifCaptcha captcha = CaptchaUtil.createGifCaptcha(130, 38, 5);
    response.setContentType("image/jpeg");
    response.setHeader("Cache-Control", "no-cache");
    captcha.write(response.getOutputStream());
}

自定義驗證碼內(nèi)容(數(shù)字 / 算術)

純數(shù)字驗證碼

@GetMapping("/captcha/number")
public void number(HttpServletResponse response) throws IOException {
    RandomGenerator generator = new RandomGenerator("0123456789", 4);
    LineCaptcha captcha = CaptchaUtil.createLineCaptcha(200, 80);
    captcha.setGenerator(generator);
    captcha.createCode();
    captcha.write(response.getOutputStream());
}

算術驗證碼(推薦)

@GetMapping("/captcha/math")
public void math(HttpServletResponse response, HttpSession session) throws IOException {
    ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(200, 45, 4, 4);
    captcha.setGenerator(new MathGenerator());
    captcha.createCode();
    session.setAttribute("MATH_CODE", captcha.getCode());
    captcha.write(response.getOutputStream());
}

接口測試建議(Apifox)

  • 使用 GET 請求訪問驗證碼接口
  • 響應應為圖片而非亂碼
  • 多次刷新驗證碼應變化
  • 若不變化,優(yōu)先檢查緩存頭設置

關鍵實踐建議

  1. 驗證碼值必須存 Session / Redis
  2. 驗證成功后立即清除
  3. 驗證碼接口應限流
  4. 高安全場景可疊加短信 / IP 風控

結(jié)語:驗證碼不是炫技,而是工程取舍

  • 需要極致定制 → 自定義實現(xiàn)
  • 追求效率與穩(wěn)定 → Hutool 一步到位

在真實項目里,99% 的情況你都不需要自己畫驗證碼。把精力留給真正有價值的業(yè)務邏輯,才是成熟工程師的選擇。

到此這篇關于Spring Boot使用Hutool快速集成驗證碼的文章就介紹到這了,更多相關SpringBoot Hutool集成驗證碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • JVM參數(shù)-Xms和-Xmx的作用及說明

    JVM參數(shù)-Xms和-Xmx的作用及說明

    這篇文章主要介紹了JVM參數(shù)-Xms和-Xmx的作用及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • springboot封裝響應實體的實例代碼

    springboot封裝響應實體的實例代碼

    這篇文章主要介紹了springboot封裝響應實體,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • Java指令重排引發(fā)問題及解決方案

    Java指令重排引發(fā)問題及解決方案

    指令重排是JVM在解釋執(zhí)行Java代碼時對指令順序進行重新排列的一種優(yōu)化技術,本文主要介紹了Java指令重排引發(fā)問題及解決方案,感興趣的可以了解一下
    2023-08-08
  • activiti實現(xiàn)員工請假流程解析

    activiti實現(xiàn)員工請假流程解析

    這篇文章主要介紹了activiti實現(xiàn)員工請假流程解析,本文通過實例代碼圖文相結(jié)合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • Java文件分級目錄打包下載zip的實例代碼

    Java文件分級目錄打包下載zip的實例代碼

    這篇文章主要介紹了Java文件分級目錄打包下載zip的實例代碼,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • java基礎之標簽、按鈕和按鈕事件簡介

    java基礎之標簽、按鈕和按鈕事件簡介

    本文給大家?guī)淼氖莏ava圖形界面的基礎知識,簡單介紹了標簽、按鈕和按鈕事件,十分的詳細,有需要的小伙伴可以參考下。
    2015-06-06
  • jdbc結(jié)合dpcp連接池的封裝實例

    jdbc結(jié)合dpcp連接池的封裝實例

    下面小編就為大家?guī)硪黄猨dbc結(jié)合dpcp連接池的封裝實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • @Scheduled注解不能同時執(zhí)行多個定時任務的解決方案

    @Scheduled注解不能同時執(zhí)行多個定時任務的解決方案

    這篇文章主要介紹了@Scheduled注解不能同時執(zhí)行多個定時任務的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • SpringBoot:JPA + AuditingEntityListener時區(qū)設置方式

    SpringBoot:JPA + AuditingEntityListener時區(qū)設置方式

    這篇文章主要介紹了SpringBoot:JPA + AuditingEntityListener時區(qū)設置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • SpringMVC實現(xiàn)數(shù)據(jù)綁定及表單標簽

    SpringMVC實現(xiàn)數(shù)據(jù)綁定及表單標簽

    這篇文章主要為大家詳細介紹了SpringMVC實現(xiàn)數(shù)據(jù)綁定及表單標簽的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03

最新評論

德化县| 文登市| 平安县| 高台县| 屏南县| 蕉岭县| 洪湖市| 英德市| 潢川县| 徐州市| 伊吾县| 青阳县| 萨嘎县| 宜章县| 望谟县| 化德县| 延寿县| 罗田县| 清原| 重庆市| 特克斯县| 陕西省| 武夷山市| 琼海市| 武威市| 苍山县| 和平县| 雷州市| 东至县| 芮城县| 闵行区| 积石山| 花莲市| 海晏县| 犍为县| 安远县| 塘沽区| 资中县| 和林格尔县| 河北区| 珠海市|