核心實作:makeCertPic 驗證碼生成類
package pic;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
import javax.imageio.ImageIO;
public class makeCertPic {
// 可出現的字元集,可自行擴充
private char mapTable[] = {
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r',
's','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9'
};
/**
* 生成彩色驗證碼圖片
* @param width 圖片寬度
* @param height 圖片高度
* @param os 輸出流(直接寫入 HTTP 響應)
* @return 生成的驗證碼字串(需存入 Session 驗證)
*/
public String getCertPic(int width, int height, OutputStream os) {
if (width <= 0) width = 60;
if (height <= 0) height = 20;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
// 背景色
g.setColor(new Color(0xDCDCDC));
g.fillRect(0, 0, width, height);
// 邊框
g.setColor(Color.BLACK);
g.drawRect(0, 0, width - 1, height - 1);
// 隨機生成 4 位驗證碼
StringBuilder strEnsure = new StringBuilder();
for (int i = 0; i < 4; i++) {
strEnsure.append(mapTable[(int) (mapTable.length * Math.random())]);
}
// 繪製驗證碼字元(錯位增加識別難度)
g.setColor(Color.BLACK);
g.setFont(new Font("Atlantic Inline", Font.PLAIN, 18));
String code = strEnsure.toString();
g.drawString(code.substring(0, 1), 8, 17);
g.drawString(code.substring(1, 2), 20, 15);
g.drawString(code.substring(2, 3), 35, 18);
g.drawString(code.substring(3, 4), 45, 15);
// 干擾點
Random rand = new Random();
for (int i = 0; i < 10; i++) {
int x = rand.nextInt(width);
int y = rand.nextInt(height);
g.drawOval(x, y, 1, 1);
}
g.dispose();
try {
ImageIO.write(image, "JPEG", os);
} catch (IOException e) {
return "";
}
return code;
}
}
JSP 整合:makeCertPic.jsp
<%@ page contentType="image/jpeg" %>
<jsp:useBean id="image" scope="page" class="pic.makeCertPic" />
<%
String str = image.getCertPic(0, 0, response.getOutputStream());
// 將驗證碼存入 Session
session.setAttribute("certCode", str);
out.clear();
out = pageContext.pushBody();
%>
前端登入頁:LoginPic.jsp
<%@ page contentType="text/html;charset=GB2312" %>
<script type="text/javascript">
function reloadcode() {
var verify = document.getElementById('code');
verify.setAttribute('src', 'makeCertPic.jsp?it=' + Math.random());
}
</script>
<html>
<head><title>系統登入</title></head>
<body>
<form action="loginCheck.jsp" method="post">
<table>
<tr><td>用戶名:<input type="text" name="username"/></td></tr>
<tr><td>密碼:<input type="password" name="password"/></td></tr>
<tr><td>驗證碼
<img id="code" src="makeCertPic.jsp" onclick="reloadcode()" alt="點擊更換" style="cursor:pointer; vertical-align:middle;">
</td></tr>
<tr><td><input type="submit" value="登入"/></td></tr>
</table>
</form>
</body>
</html>
後端驗證邏輯(loginCheck.jsp 或 Servlet)
String certCode = request.getParameter("certCode");
String sessionCode = (String) session.getAttribute("certCode");
if (certCode != null && certCode.equalsIgnoreCase(sessionCode)) {
out.print("驗證碼輸入正確");
// 繼續登入流程...
} else {
out.print("驗證碼輸入錯誤");
// 返回登入頁提示...
}
進階改進建議
- 安全性:字元集加入大寫字母、特殊符號;增加干擾線、高斯模糊、扭曲變形。
- 可用性:提供語音驗證碼無障礙選項;支援點選/滑動驗證碼替代方案。
- 效能:使用
BufferedImage.TYPE_INT_ARGB 支援透明背景;考慮快取字體物件。
- 現代化替代:Spring Boot 整合 Google reCAPTCHA v3 / hCaptcha / Turnstile,零前端維護、風險評分更精準。