上篇文章講了驗證碼的制作,提及到了一個問題,就是表單重複送出的問題,可能在上次那個驗證碼中感覺不是那麼的重要
現在我新寫一個例子,轉錢。通過這個例子你就知道表單重複送出有多恐怖了。
先來簡單的介紹一下表單重複送出的3種現象

我們來一個個的實驗,首先我們寫兩個東東,一個jsp,一個Servlet,jsp寫了就不動了,Servlet會變化,我會在不同的現象下貼出代碼
JSP:
轉賬
轉賬金額: 元
Servlet我們會在不同的現象修改,下面直接看
1.伺服器慢或者網絡延遲,我們使用線程模拟一下
先看Servlet
packagecom.vae.RandomCode;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.io.PrintWriter;
@WebServlet("/transform")public class TransformServlet extendsHttpServlet {
@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter out=resp.getWriter();
String money=req.getParameter("money");try{
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("轉出:" +money);
out.println("轉賬成功");
}
}
運作,如圖:
我點選注冊,其實是轉賬。。。。
然後應該出現一大串的轉賬100,但是不知道怎麼回事,我用線程模拟的情況并沒有出現轉賬多次,是以這裡暫時疑惑
2.已經送出成功,不小心重新整理了頁面
(Servlet代碼删了線程就行了)
我們點選一次
然後我不小心的重新整理了幾次頁面
卧槽???啥情況?我就是不小心重新整理了幾次,就要我多轉出去錢???明顯不合理
3.已經送出成功了,我回退,再次點選送出,我就是這麼的事多.....
我點
我回退
我再點
。。。。。這種情況也是不行的。。。。雖然是使用者自己作死。。。。。但是還是要規避一下。。。。
通過上面3個例子,我們知道了表單重複送出的恐怖,特别是涉及到錢的方面。是以我們要想個辦法來規避這種情況,怎麼辦呢?
想想,我們是不是通過兩次請求就可以實作轉賬了,一次是JSP的按鈕點選,一次是Servlet的擷取資料,那麼我們隻需要保證我們每次的操作,都有這兩次請求就可以了
解決方案:令牌機制
我聽到這個令牌機制就想起了狄仁傑...其實令牌機制就是一個随機數UUID,和我們的驗證碼裡面的那個是一樣的。其原理是
我在JSP頁面點選按鈕發出第一次請求的時候,就把我的令牌(随機數)儲存到Session裡面,并且把令牌傳給Servlet,然後在Servlet裡面判斷兩個是否相等
如果相等,就ok,轉賬,然後立馬銷毀session裡面的令牌,這樣無論你再怎麼重新整理,session裡面已經沒有令牌了,肯定不能轉賬了
話說到此,我們來看看最終的代碼
JSP:
轉賬
//生成一個令牌Stringtoken=UUID.randomUUID().toString();//存放在session中
session.setAttribute("TOKEN_IN_SESSION",token);%>
"> 轉賬金額: 元
Servlet:
packagecom.vae.RandomCode;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.io.PrintWriter;
@WebServlet("/transform")public class TransformServlet extendsHttpServlet {
@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {//表單中的令牌
String tokenInRequest=req.getParameter("token");//session中的令牌
String tokenInSession=req.getSession().getAttribute("TOKEN_IN_SESSION").toString();//比較
if(tokenInRequest.equals(tokenInSession)) {//立馬銷毀session中的令牌再說
req.getSession().removeAttribute("TOKEN_IN_SESSION");//然後幹其他的事
resp.setContentType("text/html;charset=utf-8");
PrintWriter out=resp.getWriter();
String money=req.getParameter("money");
System.out.println("轉出:" +money);
out.println("轉賬成功");
}else{
System.out.println("不讓你轉,重新去頁面轉吧");
}
}
}
運作一下,結果已經ok了,我們使用了令牌機制(就是一個随機數)實作了避免表單的重複送出。