如何在Java?Web項目中優(yōu)雅地實現(xiàn)驗證碼攔截與校驗
前言
在 Web 開發(fā)中,很多網(wǎng)站都會對敏感頁面或公告信息做 驗證碼攔截,以防止爬蟲或惡意訪問。
比如訪問某些公告詳情頁時,必須先輸入驗證碼才能繼續(xù)瀏覽。
本文將以一個實際的案例為例,演示如何在 Java Web 項目中優(yōu)雅地實現(xiàn) Filter 攔截 + 驗證碼校驗 + 友好頁面展示。
1. 需求分析
假設(shè)我們的系統(tǒng)中有以下目錄需要保護(hù):
xzbgg、zhzzsgg、zhzzbhxr、zhzbjggs、zhzzzgg、 xfzbgg、zhfcghxr、zhfcgjg、zhfzzgg、zhzbxx
攔截邏輯:
/xxx/index.jhtml這樣的首頁不需要攔截;/xxx/12345.jhtml這樣的詳情頁必須輸入驗證碼才能訪問;- 驗證碼通過后,自動跳轉(zhuǎn)回用戶最初請求的頁面。
2. Filter 攔截實現(xiàn)
首先我們定義一個 CaptchaFilter,利用 正則表達(dá)式 精準(zhǔn)攔截需要驗證的頁面:
public class CaptchaFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String uri = req.getRequestURI();
// 定義需要保護(hù)的路徑前綴
String[] protectedPaths = {
"xzbgg", "zhzzsgg", "zhzzbhxr", "zhzbjggs", "zhzzzgg",
"xfzbgg", "zhfcghxr", "zhfcgjg", "zhfzzgg", "zhzbxx"
};
// 匹配 /xxx/數(shù)字.jhtml 的請求
String pattern = MessageFormat.format(".*/(?:{0})/\\d+\\.jhtml$", String.join("|", protectedPaths));
if (uri.matches(pattern)) {
HttpSession session = req.getSession();
Boolean captchaPassed = (Boolean) session.getAttribute("captchaPassed");
// 如果驗證碼已通過,放行并清理標(biāo)記
if (Boolean.TRUE.equals(captchaPassed)) {
chain.doFilter(request, response);
session.removeAttribute("captchaPassed");
return;
}
// 保存目標(biāo) URL,便于校驗成功后跳轉(zhuǎn)回來
session.setAttribute("targetUrl", uri);
// 轉(zhuǎn)發(fā)到驗證碼頁面
req.getRequestDispatcher("/captcha.html").forward(req, resp);
return;
}
// 其他請求直接放行
chain.doFilter(request, response);
}
}
這樣,所有訪問 /xxx/數(shù)字.jhtml 的請求都會被攔截,并跳轉(zhuǎn)到驗證碼頁面。
3. web.xml 配置
接著在 web.xml 中注冊 Filter 和兩個 Servlet:
- 一個生成驗證碼圖片(如
JCaptchaServlet); - 一個校驗驗證碼輸入(我們自定義的
CaptchaCheckServlet)。
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- 驗證碼攔截器 -->
<filter>
<filter-name>CaptchaFilter</filter-name>
<filter-class>com.example.filter.CaptchaFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CaptchaFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 驗證碼圖片生成 Servlet (例如 JCaptcha) -->
<servlet>
<servlet-name>CaptchaServlet</servlet-name>
<servlet-class>com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CaptchaServlet</servlet-name>
<url-pattern>/captcha.svl</url-pattern>
</servlet-mapping>
<!-- 驗證碼校驗 Servlet -->
<servlet>
<servlet-name>CaptchaCheckServlet</servlet-name>
<servlet-class>com.example.servlet.CaptchaCheckServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CaptchaCheckServlet</servlet-name>
<url-pattern>/captcha/check</url-pattern>
</servlet-mapping>
</web-app>
4. CaptchaCheckServlet 校驗邏輯
CaptchaCheckServlet 用來接收用戶輸入的驗證碼,并進(jìn)行校驗。
如果校驗失敗,重定向回 captcha.html?error=1。
public class CaptchaCheckServlet extends HttpServlet {
private ImageCaptchaService captchaService;
@Override
public void init() throws ServletException {
super.init();
WebApplicationContext appCtx =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
captchaService = BeanFactoryUtils.beanOfTypeIncludingAncestors(
appCtx, ImageCaptchaService.class);
if (captchaService == null) {
throw new ServletException("CaptchaService 未初始化,請檢查 Spring 配置");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
HttpSession session = req.getSession();
String captchaId = session.getId();
String inputCode = req.getParameter("code");
boolean passed;
try {
passed = captchaService.validateResponseForID(captchaId, inputCode);
} catch (Exception e) {
passed = false;
}
if (passed) {
// 驗證成功,設(shè)置標(biāo)記并跳轉(zhuǎn)回原頁面
session.setAttribute("captchaPassed", true);
String targetUrl = (String) session.getAttribute("targetUrl");
session.removeAttribute("targetUrl");
if (targetUrl != null) {
resp.sendRedirect(targetUrl);
} else {
resp.sendRedirect(req.getContextPath() + "/");
}
} else {
// 驗證失敗,重定向并附帶錯誤標(biāo)記
resp.sendRedirect(req.getContextPath() + "/captcha.html?error=1");
}
}
}
5. 驗證碼頁面(HTML)
驗證碼頁面保留為 純 HTML,通過 JavaScript 獲取 URL 參數(shù) error 來顯示錯誤提示。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>請輸入驗證碼</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
font-family: "Microsoft YaHei", Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
background: #f4f6f9;
}
.captcha-container {
background: #fff;
padding: 2rem;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
text-align: center;
width: 300px;
}
h2 {
margin-bottom: 1.2rem;
font-size: 1.2rem;
color: #333;
}
.error {
color: red;
margin-bottom: 1rem;
display: none;
}
img {
cursor: pointer;
margin-bottom: 1rem;
border: 1px solid #ddd;
border-radius: 6px;
}
input[type="text"] {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 6px;
font-size: 1rem;
margin-bottom: 1rem;
}
button {
width: 100%;
padding: 10px;
border: none;
border-radius: 6px;
background: #007bff;
color: white;
font-size: 1rem;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
.tip {
margin-top: 0.8rem;
font-size: 0.9rem;
color: #666;
}
</style>
</head>
<body>
<div class="captcha-container">
<h2>請輸入驗證碼</h2>
<div class="error" id="errorMsg">驗證碼錯誤,請重新輸入</div>
<form action="/zhcms/captcha/check" method="post">
<img src="/zhcms/captcha.svl"
onclick="this.src='/zhcms/captcha.svl?'+Math.random()"
alt="驗證碼" title="點擊圖片更換驗證碼"/>
<input type="text" name="code" placeholder="請輸入驗證碼" required/>
<button type="submit">提交</button>
<div class="tip">看不清?點擊圖片刷新驗證碼</div>
</form>
</div>
<script>
// 從 URL 獲取參數(shù)
const params = new URLSearchParams(window.location.search);
if (params.get("error") === "1") {
document.getElementById("errorMsg").style.display = "block";
}
</script>
</body>
</html>
頁面效果如圖所示:

6. 常見問題 Q&A
Q1: 為什么驗證碼頁面用 JSP 會被攔截?
A: 因為 Filter 攔截了 .jhtml 之外的請求時,轉(zhuǎn)發(fā)到 JSP 也會觸發(fā)過濾邏輯,容易形成死循環(huán)。改成 .html 并使用 JavaScript 處理錯誤提示即可。
Q2: 驗證碼圖片不顯示?
A: 檢查 captcha.svl 是否正確映射到 SimpleImageCaptchaServlet。同時確認(rèn)瀏覽器是否緩存了圖片,可以通過 ?Math.random() 動態(tài)刷新。
Q3: 校驗通過后沒有跳轉(zhuǎn)回原頁面?
A: 確保在 Filter 里使用 session.setAttribute("targetUrl", uri) 保存目標(biāo)地址,并在 CaptchaCheckServlet 里取出并重定向。
Q4: 如何擴(kuò)展更多攔截目錄?
A: 只需在 protectedPaths 數(shù)組里新增路徑名即可,例如 "newpath1", "newpath2"。
7. 總結(jié)
通過以上幾個步驟,我們就實現(xiàn)了一個完整的驗證碼攔截機(jī)制:
- Filter 攔截:利用正則表達(dá)式精確攔截
/xxx/數(shù)字.jhtml的請求; - 驗證碼校驗:用戶輸入后由
CaptchaCheckServlet校驗,成功后跳轉(zhuǎn)回原始頁面; - 用戶體驗優(yōu)化:驗證碼頁面保持 HTML,支持錯誤提示,UI 簡潔美觀;
- 常見問題處理:避免死循環(huán),解決驗證碼圖片緩存問題。
這種實現(xiàn)方式簡單清晰、可維護(hù)性強,非常適合需要在項目中批量攔截頁面并加上驗證碼驗證的場景。
到此這篇關(guān)于如何在Java Web項目中優(yōu)雅地實現(xiàn)驗證碼攔截與校驗的文章就介紹到這了,更多相關(guān)Java Web驗證碼攔截與校驗內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java項目開發(fā)命名規(guī)范(動力節(jié)點Java學(xué)院整理)
定義這個規(guī)范的目的是讓項目中所有的文檔都看起來像一個人寫的,增加可讀性,減少項目組中因為換人而帶來的損失。下面給大家分享java開發(fā)命名規(guī)范,一起看看吧2017-03-03
實現(xiàn)了基于TCP的Java Socket編程實例代碼
這篇文章主要介紹了基于TCP的Java Socket編程實例代碼,有需要的朋友可以參考一下2013-12-12
java多線程抓取鈴聲多多官網(wǎng)的鈴聲數(shù)據(jù)
很容易就能發(fā)現(xiàn)通過改變 listId和page就能從服務(wù)器獲取鈴聲的json數(shù)據(jù), 通過解析json數(shù)據(jù), 可以看到都帶有{"hasmore":1,"curpage":1}這樣子的指示,通過判斷hasmore的值,決定是否進(jìn)行下一頁的抓取。 但是通過上面這個鏈接返回的json中不帶有鈴聲的下載地址2016-04-04
springboot創(chuàng)建監(jiān)聽和處理事件的操作方法
這篇文章主要介紹了springboot創(chuàng)建監(jiān)聽和處理事件的操作方法,使用Spring Boot的事件機(jī)制來監(jiān)聽和處理事件有多種優(yōu)勢,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧2024-07-07

