在 Web 應用開發中,驗證碼是防止惡意註冊、暴力破解密碼等自動化攻擊的關鍵防線。本文將完整分享一套基於 Java Servlet 的圖形驗證碼實現方案,涵蓋後端生成邏輯、前端展示頁面、驗證邏輯處理及項目結構說明,幫助開發者快速掌握核心技術要點。
驗證碼的核心目的是區分人類用戶與機器腳本,常見於登入、註冊、表單提交等場景。實現流程主要分三步:
<img src="logcheck"> 請求圖片,提供輸入框供用戶填寫。package com;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class logcheck extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 設定輸出類型為 JPEG 圖片
response.setContentType("image/jpeg");
HttpSession session = request.getSession();
int width = 60, height = 20;
// 禁止瀏覽器緩存
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
// 建立內存圖片與畫筆
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
// 1. 隨機生成 4 位驗證碼字符
String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char[] rands = new char[4];
for (int i = 0; i < 4; i++) {
int rand = (int) (Math.random() * 36);
rands[i] = chars.charAt(rand);
}
// 2. 繪製背景
g.setColor(new Color(0xDCDCDC));
g.fillRect(0, 0, width, height);
// 3. 繪製 120 個隨機干擾點
for (int i = 0; i < 120; i++) {
int x = (int) (Math.random() * width);
int y = (int) (Math.random() * height);
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
g.setColor(new Color(red, green, blue));
g.drawOval(x, y, 1, 0);
}
// 4. 繪製驗證碼字符(斜體加粗,錯位排列)
g.setColor(Color.BLACK);
g.setFont(new Font(null, Font.ITALIC | Font.BOLD, 18));
g.drawString(String.valueOf(rands[0]), 1, 17);
g.drawString(String.valueOf(rands[1]), 16, 15);
g.drawString(String.valueOf(rands[2]), 31, 18);
g.drawString(String.valueOf(rands[3]), 46, 16);
g.dispose();
// 5. 輸出圖片流
ServletOutputStream sos = response.getOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "JPEG", baos);
byte[] buffer = baos.toByteArray();
response.setContentLength(buffer.length);
sos.write(buffer);
baos.close();
sos.close();
// 6. 存入 Session 供後續驗證
session.setAttribute("checkcode", new String(rands));
}
}
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>驗證碼演示頁面</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<form action="yanzheng" method="post">
<label>請輸入驗證碼:</label>
<input type="text" name="name" size="5" maxlength="4" required>
<a href="index.jsp" title="看不清?點擊刷新">
<img border="0" src="logcheck" alt="驗證碼圖片" style="vertical-align: middle;">
</a>
<br><br>
<input type="submit" value="提交驗證">
</form>
</body>
</html>
package com;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class yanzheng extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String inputCode = request.getParameter("name");
HttpSession session = request.getSession();
String sessionCode = (String) session.getAttribute("checkcode");
String info;
if (sessionCode != null && sessionCode.equalsIgnoreCase(inputCode)) {
info = "驗證碼輸入正確";
} else {
info = "驗證碼輸入錯誤";
}
System.out.println(info);
request.setAttribute("info", info);
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
}
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>驗證結果</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<h3>驗證結果:</h3>
<p style="color: <%= request.getAttribute("info").toString().contains("正確") ? "green" : "red" %>;">
<%= request.getAttribute("info") %>
</p>
<a href="index.jsp">返回重試</a>
</body>
</html>
將上述 4 個文件放入對應的包結構中:
src/com/logcheck.java — 驗證碼生成 Servletsrc/com/yanzheng.java — 驗證邏輯 ServletWebContent/index.jsp — 輸入頁面WebContent/login.jsp — 結果頁面在 web.xml 中配置 Servlet 映射:
<servlet>
<servlet-name>logcheck</servlet-name>
<servlet-class>com.logcheck</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>logcheck</servlet-name>
<url-pattern>/logcheck</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>yanzheng</servlet-name>
<servlet-class>com.yanzheng</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>yanzheng</servlet-name>
<url-pattern>/yanzheng</url-pattern>
</servlet-mapping>
g.drawLine() 繪製隨機直線,提高機器識別難度。本文提供的代碼為教學演示用途,展示了驗證碼的核心實現原理。實際項目中請根據安全等級選擇合適的方案,並注意防止 Session 固定攻擊、驗證碼複用等安全風險。