在 Web 應用開發中,圖片驗證碼是防止機器人惡意註冊、暴力破解登入的常用手段。本文將詳細介紹一個基於 Java Servlet 的完整驗證碼生成方案,包含核心 Servlet、工具類實現以及 web.xml 配置說明。
AuthImage 繼承自 HttpServlet,負責處理驗證碼圖片的生成與輸出。其核心邏輯在 service 方法中:
package hh.com.util;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class AuthImage extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
static final long serialVersionUID = 1L;
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 禁用快取
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
// 生成隨機驗證碼
String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
// 存入 Session
HttpSession session = request.getSession(true);
session.setAttribute("rand", verifyCode.toLowerCase());
// 生成圖片
int w = 200, h = 80;
VerifyCodeUtils.outputImage(w, h, response.getOutputStream(), verifyCode);
}
}
VerifyCodeUtils 封裝了驗證碼生成的所有核心邏輯,包括字符源定義、隨機字串生成、圖片繪製、干擾線、噪點、扭曲變形等反 OCR 技術。
預設字符源排除易混淆字符(1,0,i,o),僅包含大寫字母與數字:
public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"; private static Random random = new Random();
提供兩個重載方法生成指定長度驗證碼,支援自定義字符源。
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 = { 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.dispose();
ImageIO.write(image, "jpg", os);
}
getRandColor(fc, bc):生成指定範圍內的隨機顏色getRandomIntColor() / getRandomRgb():生成隨機 RGB 整數值shear/shearX/shearY:實現圖片的水平與垂直正弦波扭曲將 AuthImage 映射至 /authImage 路徑,前端可通過 <img src="/authImage" /> 獲取驗證碼圖片。
<servlet>
<servlet-name>AuthImage</servlet-name>
<servlet-class>hh.com.util.AuthImage</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AuthImage</servlet-name>
<url-pattern>/authImage</url-pattern>
</servlet-mapping>