首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Servlet 實現隨機圖形驗證碼完整教程(含干擾線、Session 驗證、前端整合)

     編輯:Java 相關知識

核心 Servlet:ValidateCodeServlet

package com.servlet;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.*;
import javax.servlet.http.*;

public class ValidateCodeServlet extends HttpServlet {
    private int width = 100;
    private int height = 35;
    private int codeCount = 4;
    private int fontHeight;
    private int codeY;
    private final char[] codeSequence = {
        'A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z',
        '2','3','4','5','6','7','8','9'  // 去除易混淆 0/O, 1/I
    };

    @Override
    public void init() throws ServletException {
        String w = getInitParameter("width");
        String h = getInitParameter("height");
        String c = getInitParameter("codeCount");
        if (w != null) width = Integer.parseInt(w);
        if (h != null) height = Integer.parseInt(h);
        if (c != null) codeCount = Integer.parseInt(c);
        fontHeight = height - 4;
        codeY = height - 6;
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = img.createGraphics();
        Random rand = new Random();

        // 背景
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, width, height);

        // 字體
        Font font = new Font("Fixedsys", Font.BOLD, fontHeight);
        g.setFont(font);

        // 邊框
        g.setColor(Color.BLACK);
        g.drawRect(0, 0, width-1, height-1);

        // 干擾線
        g.setColor(Color.GRAY);
        for (int i = 0; i < 50; i++) {
            int x = rand.nextInt(width);
            int y = rand.nextInt(height);
            int xl = rand.nextInt(12);
            int yl = rand.nextInt(12);
            g.drawLine(x, y, x+xl, y+yl);
        }

        // 生成驗證碼並繪製
        StringBuilder code = new StringBuilder();
        int charWidth = width / (codeCount + 1);
        for (int i = 0; i < codeCount; i++) {
            char c = codeSequence[rand.nextInt(codeSequence.length)];
            code.append(c);
            g.setColor(new Color(rand.nextInt(150), rand.nextInt(150), rand.nextInt(150)));
            g.drawString(String.valueOf(c), (i+1)*charWidth, codeY);
        }

        // 存入 Session
        HttpSession session = req.getSession();
        session.setAttribute("validateCode", code.toString());

        // 防快取
        resp.setHeader("Pragma", "No-cache");
        resp.setHeader("Cache-Control", "no-cache");
        resp.setDateHeader("Expires", 0);
        resp.setContentType("image/jpeg");

        // 輸出
        ServletOutputStream out = resp.getOutputStream();
        ImageIO.write(img, "jpeg", out);
        out.close();
    }
}

web.xml 註冊

<servlet>
    <servlet-name>ValidateCodeServlet</servlet-name>
    <servlet-class>com.servlet.ValidateCodeServlet</servlet-class>
    <init-param>
        <param-name>width</param-name>
        <param-value>120</param-value>
    </init-param>
    <init-param>
        <param-name>height</param-name>
        <param-value>40</param-value>
    </init-param>
    <init-param>
        <param-name>codeCount</param-name>
        <param-value>4</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>ValidateCodeServlet</servlet-name>
    <url-pattern>/validateCode</url-pattern>
</servlet-mapping>

前端整合:login.jsp

<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<script>
function refreshCode() {
    document.getElementById('captchaImg').src = '/validateCode?t=' + Math.random();
}
</script>
</head>
<body>
<form action="/login" method="post">
    用戶名:<input name="username" /><br/>
    密碼:<input type="password" name="password" /><br/>
    驗證碼:
    <img id="captchaImg" src="/validateCode" onclick="refreshCode()" alt="點擊刷新" style="cursor:pointer; vertical-align:middle;" />
    <input name="captcha" size="6" /><br/>
    <input type="submit" value="登入" />
</form>
</body>
</html>

後端驗證邏輯

@PostMapping("/login")
public String login(@RequestParam String username,
                    @RequestParam String password,
                    @RequestParam String captcha,
                    HttpSession session) {
    String realCode = (String) session.getAttribute("validateCode");
    if (realCode == null || !realCode.equalsIgnoreCase(captcha)) {
        model.addAttribute("error", "驗證碼錯誤");
        return "login";
    }
    session.removeAttribute("validateCode"); // 一次性使用
    // 繼續登入邏輯...
    return "redirect:/home";
}

增強建議

  • 干擾點:在干擾線循環中加入 g.fillOval(x, y, 2, 2)。
  • 字符旋轉:g.rotate(theta, cx, cy) 繪製後旋回,大幅提高 OCR 識別難度。
  • 字體隨機:準備多種字體數組隨機選取。
  • 使用成熟庫:kaptcha、simple-captcha、patchca 提供更豐富的干擾策略。
  • 分布式 Session:集群環境需共享 Session(Redis/Memcached)或改用 JWT 存儲驗證碼。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved