表單重複提交是 Web 開發常見問題,可能導致重複訂單、重複扣款等嚴重後果。Struts 內建的 Token(令牌)機制提供簡單有效的解決方案。本文深入解析 Token 原理、核心 API 使用、實戰整合範例與基礎類封裝技巧。
<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="...">| 方法 | 用途 |
|---|---|
saveToken(request) | 在請求/Session 中產生並儲存新 Token,同時輸出至表單隱藏欄位 |
isTokenValid(request, true) | 驗證 Token 有效性,true 表示驗證後重置 Token |
resetToken(request) | 手動重置 Session 中的 Token |
public class SubjectAction extends BaseDispatchAction {
// 步驟 1:進入新增頁面時產生 Token
public ActionForward add(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
saveToken(request); // 關鍵:必須在 forward 到 JSP 前呼叫
return mapping.findForward("add"); // 轉向 subjectAdd.jsp
}
// 步驟 2:提交表單時驗證 Token
public ActionForward insert(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
if (isTokenValid(request, true)) {
// 正常提交:執行資料庫插入
// saveData(...);
return mapping.findForward("success");
} else {
// 重複提交:記錄日誌、顯示錯誤訊息
saveToken(request); // 重置 Token 讓使用者可再次嘗試
log.error("重複提交!");
saveError(request, new ActionMessage("error.repeatSubmit"));
return mapping.findForward("error");
}
}
}
<html:form action="subjectForm.do?method=insert">
<html:text property="title" />
<html:textarea property="content" />
<html:submit property="發表" />
<html:reset property="重填" />
</html:form>
若 Action 執行了 saveToken(request),產生的 HTML 會自動包含隱藏欄位:
<input type="hidden" name="org.apache.struts.taglib.html.TOKEN"
value="6aa35341f25184fd996c4c918255c3ae">
在實際專案中,建議將 Token 控制邏輯封裝於基礎 Action 類別,避免重複程式碼:
public abstract class BaseDispatchAction extends BaseAction {
protected ActionForward perform(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
String methodName = request.getParameter(mapping.getParameter());
if (methodName == null) methodName = "list";
// 統一控制:add 產生 Token,insert 驗證 Token
if ("add".equals(methodName)) {
saveToken(request);
} else if ("insert".equals(methodName)) {
if (!isTokenValid(request, true)) {
resetToken(request);
saveError(request, new ActionMessage("error.repeatSubmit"));
log.error("重複提交!");
return mapping.findForward("error");
}
}
return dispatchMethod2(mapping, form, request, response, methodName);
}
}
Struts Token 機制以「伺服器端產生、客戶端攜帶、比對驗證、動態更新」的簡潔流程,有效解決重複提交問題。配合基礎類封裝,可將防重複邏輯從業務代碼中剝離,實現乾淨、可維護的防禦性程式設計。