表單重復提交


一:使用JavaScript來防止表單重復提交

有三種場景:1:在網絡延遲的情況下讓用戶有時間點擊多次submit導致重復提交

  2:表單提交后點擊“刷新”按鈕導致重復提交

  3:提交后,點擊瀏覽器的后退然后再次提交

  <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
  <head>
    <title>Form表單</title>
        <script type="text/javascript">
        var isCommitted = false;//表單是否已經提交標識,默認為false
        function dosubmit(){
            if(isCommitted==false){
                isCommitted = true;//提交表單后,將表單是否已經提交標識設置為true
                return true;//返回true讓表單正常提交
            }else{
                return false;//返回false那么表單將不提交
            }
        }
    </script>
  </head>
 
  <body>
      <form action="${pageContext.request.contextPath}/servlet/DoFormServlet" onsubmit="return dosubmit()" method="post">
        用戶名:<input type="text" name="username">
        <input type="submit" value="提交" id="submit">
    </form>
  </body>
</html>

另一種方式:將提交按鈕設置為不可用。

  function dosubmit(){
    //獲取表單提交按鈕
    var btnSubmit = document.getElementById("submit");
    //將表單提交按鈕設置為不可用,這樣就可以避免用戶再次點擊提交按鈕
    btnSubmit.disabled= "disabled";
    //返回true讓表單可以正常提交
    return true;
}

js只能解決問題1,但是2,3解決不了。

利用session解決2和3:在服務器端解決

  做法:在服務器端生成一個唯一的隨機標識號,專業術語:Token(令牌)。同時在當前用戶的Session中保存這個Token。然后將Token發送到客戶端的Form表單中

在表單中使用隱藏域來存儲這個Token。表單提交的時候連同這個Token一起提交到服務器端。然后在服務器端判斷客戶端提交上來的Token與服務器生成的是否一樣。不一樣就是重復提交了,此時服務器就不可以處理重復提交的表單。處理完后清除當前用戶的Session中存儲的標識號。

  在下列情況中,服務器程序將拒絕處理

  1:存儲session中的Token與表單提交的Token不同。

  2:當前用戶的session中不存在token

  3:用戶提交的表單數據中沒有Token

form.jsp頁面

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<html>
  <head>
   <title>Form表單</title>
 
  </head>
 
  <body>
    <form action="${pageContext.request.contextPath }/demo02" method="post">
    <%--使用EL表達式取出存儲在session中的token--%>
       <input type="hidden" name="token" value="${token}"/>
        用戶名:<input type="text" name="username">
            <input type="submit" value="提交">
    </form>
  </body>
</html>
業務處理

protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
     boolean b = isRepeatSubmit(request);//判斷用戶是否是重復提交
              if(b==true){
                   System.out.println("請不要重復提交");
                     return;
                }
                 request.getSession().removeAttribute("token");//移除session中的token
                System.out.println("處理用戶提交請求!!");
           }
            
             /**
              * 判斷客戶端提交上來的令牌和服務器端生成的令牌是否一致
             * @param request
             * @return
            *         true 用戶重復提交了表單
             *         false 用戶沒有重復提交表單
             */
           private boolean isRepeatSubmit(HttpServletRequest request) {
                String client_token = request.getParameter("token");
                //1、如果用戶提交的表單數據中沒有token,則用戶是重復提交了表單
                if(client_token==null){
                    return true;
                }
                //取出存儲在Session中的token
                String server_token = (String) request.getSession().getAttribute("token");
             //2、如果當前用戶的Session中不存在Token(令牌),則用戶是重復提交了表單
                if(server_token==null){
                     return true;
                }
                 //3、存儲在Session中的Token(令牌)與表單提交的Token(令牌)不同,則用戶是重復提交了表單
                if(!client_token.equals(server_token)){
                     return true;
                }
                
                return false;
             }

服務器端保存:

protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String token=TokenProccessor.getInstance().makeToken();
        System.out.println("在FormServlet中生成的token:"+token);
        request.getSession().setAttribute("token", token);//在服務器端保存
        request.getRequestDispatcher("/form.jsp").forward(request, response);
    }

生成token的工具類:

/*
 * 生成Token的工具類
 */
public class TokenProccessor {
    /*
     * 單例設計模式(保證類的對象在內存中只有一個)
     * 1:把類的構造函數私有
     * 2:自己創建一個類的對象
     * 3:對外提供一個公共的方法,返回類的對象
     */
    private TokenProccessor(){}
    private static final TokenProccessor instance = new TokenProccessor();
    public static TokenProccessor getInstance(){
           return instance;
        }
    
     public String makeToken(){  //checkException
                 //  7346734837483  834u938493493849384  43434384
                String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
                 //數據指紋   128位長   16個字節  md5
                  try {
                     MessageDigest md = MessageDigest.getInstance("md5");
                    byte md5[] =  md.digest(token.getBytes());
                    //base64編碼--任意二進制編碼明文字符   adfsdfsdfsf
                     BASE64Encoder encoder = new BASE64Encoder();
                     return encoder.encode(md5);
                 } catch (NoSuchAlgorithmException e) {
                      throw new RuntimeException(e);
                 }
             }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM