首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Spring MVC 閃電戰:RedirectAttributes 實現 POST-Redirect-GET 防重複提交

     編輯:Java 綜合教學

Spring MVC 閃電戰:RedirectAttributes 實現 POST-Redirect-GET 防重複提交

表單重複提交是 Web 開發經典痛點。Spring MVC 提供 RedirectAttributes 配合 PRG 模式,以零 Session 開銷優雅解決數據傳遞與重複提交問題。

核心原理:PRG 模式 + Flash 屬性

用戶提交 POST → Controller 處理 → 
RedirectAttributes 存入 FlashMap (請求域,重定向後自動清除) → 
302 重定向至 GET 頁面 → 
GET 處理器從 Model 讀取 Flash 屬性 → 渲染視圖

關鍵優勢: Flash 屬性僅在重定向鏈路中生存一次,刷新頁面不會重複提交,無需手動清理 Session。

標準實現模板

@PostMapping("/login")
public String login(@Valid UserForm form, BindingResult bindingResult, 
                    RedirectAttributes redirectAttributes) {
    
    // 1. 驗證失敗:攜帶錯誤信息與表單數據重定向回登錄頁
    if (bindingResult.hasErrors()) {
        redirectAttributes.addFlashAttribute("error.password.error", "密碼格式不正確");
        redirectAttributes.addFlashAttribute("user", form); // 回顯表單數據
        return "redirect:/login"; // PRG 核心:重定向而非 forward
    }

    // 2. 業務處理...
    try {
        userService.authenticate(form.getUsername(), form.getPassword());
    } catch (AuthenticationException e) {
        redirectAttributes.addFlashAttribute("error.auth", "用戶名或密碼錯誤");
        return "redirect:/login";
    }

    // 3. 成功重定向至首頁
    return "redirect:/dashboard";
}

GET 處理器自動接收 Flash 屬性

@GetMapping("/login")
public String showLoginForm(Model model) {
    // 無需額外代碼,Spring 自動將 FlashMap 合併到 Model
    // 模板中直接使用 ${error.password.error} ${user.username}
    return "login";
}

Thymeleaf 模板回顯示例

<form method="post" th:action="@{/login}" th:object="${user}">
    <div class="form-group">
        <label>用戶名</label>
        <input type="text" th:field="*{username}" class="form-control" 
               th:classappend="${#fields.hasErrors('username') ? 'is-invalid' : ''}" />
        <div class="invalid-feedback" th:errors="*{username}"></div>
    </div>
    
    <div th:if="${error.password.error}" class="alert alert-danger" 
         th:text="${error.password.error}"></div>
    <div th:if="${error.auth}" class="alert alert-danger" th:text="${error.auth}"></div>
    
    <button type="submit" class="btn btn-primary">登錄</button>
</form>

進階:雙重防護機制

  1. 客戶端: 提交後禁用按鈕 btn.disabled = true
  2. 服務端: 關鍵業務引入 冪等性 Key(如 Redis SETNX idempotent:order:{orderId} EX 300)
@PostMapping("/orders")
public String createOrder(OrderDTO dto, RedirectAttributes ra) {
    String idempotentKey = "idempotent:order:" + dto.getClientToken();
    if (!redisTemplate.opsForValue().setIfAbsent(idempotentKey, "1", 5, TimeUnit.MINUTES)) {
        ra.addFlashAttribute("error", "請勿重複提交訂單");
        return "redirect:/orders/new";
    }
    try {
        orderService.create(dto);
    } finally {
        redisTemplate.delete(idempotentKey); // 或由異步任務清理
    }
    return "redirect:/orders/success";
}

常見誤區避坑

誤區後果正確做法
用 addAttribute 而非 addFlashAttribute參數拼接在 URL,暴露敏感信息,刷新仍存在敏感/臨時數據必用 Flash 屬性
驗證失敗用 forward: 而非 redirect:瀏覽器地址欄仍為 POST URL,刷新重複提交永遠 redirect: 實現 PRG
Flash 屬性存放大對象默認存 Session,佔用內存僅存錯誤碼、ID 等輕量數據

RedirectAttributes + PRG 是 Spring MVC 表單處理的標準範式:零 Session 污染、自動生命周期管理、天然防重複提交。配合冪等性 Key 構建雙重防線,徹底解決業務層面重複提交。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved