解決表單重複提交的問題

wtopps發表於2017-07-20

現象描述

最近在開發的時候,遇見這樣的問題,當我們在網路狀況不太好的情況、或者一個業務的後臺業務邏輯執行時間較長的時候,使用者可能會點選多次提交或重新整理多次頁面,導致表單資料被提交了多次,導致了可能出現莫名其妙的問題,解決這個問題,我們可以使用session加token的方式進行解決。

方案

JSP程式碼:

<%@ page import="java.util.UUID" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ page contentType="text/html;charset=UTF-8" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>test jsp</title>
</head>
<body>
<%
        String token = UUID.randomUUID().toString().replaceAll("-","");
        session.setAttribute("token",token);
%>

<form id="form1" method="post" action="/user/doSomething.do">
    username : <input type="text" id="username" value=""/>
    password : <input type="text" id="password" value=""/>
    <input type="hidden" name="formtoken" value="<%=token%>" >
    <input type="submit" value="submit"/>
</form>
</body>
</html>

Controller層:

@Controller
@RequestMapping(value="user")
public class UserController {

    @RequestMapping(value="doSomething.do")
    public String doSometing(String username, String password, HttpServletRequest request, RedirectAttributes attr) {
        String formToken = request.getParameter("formtoken");
        HttpSession session = request.getSession();
        String token = (String)session.getAttribute("token");
        if (formToken.equals(token)) {
            session.removeAttribute("token");
        } else {
            attr.addFlashAttribute("msg", "請不要重複提交!");
            return "redirect:error";
        }
    }
}

如果有多個Controller的方法都需要進行校驗,可以寫一個單獨的校驗方法,使用@ModelAttribute註解,這樣讓它在所有方法執行之前執行,校驗是否表單重複提交了

@Controller
@RequestMapping(value="user")
public class UserController {

    @ModelAttribute
    public void checkForm(HttpServletRequest request, Model model) {
            String formToken = request.getParameter("formtoken");
            HttpSession session = request.getSession();
            String token = (String)session.getAttribute("token");
            if (formToken.equals(token)) {
                session.removeAttribute("token");
                model.addAttribute("checkResult", "success");
            } else {
                model.addAttribute("checkResult", "fail");
        }
    }   

    @RequestMapping(value="doSomething.do")
    public String doSometing(@ModelAttribute String checkResult, String username, String password, RedirectAttributes attr) {
        if (checkResult != null && checkResult.equals("success")) 
        {
            doSomething(username, password);    
        } else {
            attr.addFlashAttribute("msg","請不要重複提交");
            return "redirect:error";
        }
    }
}

原理

當多次提交的時候,session中的token已經更新,但是form中的token沒有變化,因此可以用此進行校驗。

相關文章