下面咱們首先來講一下表單的重複提交問題,咱們知道在真實的網絡環境中可能受網速帶寬的緣由會形成頁面中表單在提交的過程當中出現網絡的延遲等問題,從而形成屢次提交的問題!下面咱們就具體來分析一下形成表單提交的一些常見問題。瀏覽器
下面咱們就來列舉一下重複提交的狀況:緩存
① 、當表單提交數據到一個 Servlet 中,而後 Servlet再經過請求轉發到成功頁面,可是此時的地址欄中的地址是到 Servlet映射中的地址,並無跳轉到成功頁面相關的JSP頁面中,此時刷新頁面會形成再一次提交表單。網絡
② 、當在表單頁面中點擊提交按鈕時,表單頁面沒有當即跳轉到Servlet來進行處理(網絡延遲),而此時用戶就點擊屢次提交按鈕,也會形成重複提交表單!session
③ 、當用戶進行表單數據提交成功後,又經過瀏覽器上的返回按鈕返回到提交表單頁面,(在不進行刷新到條件下)再次進行點擊提交也會形成重複提交表單的狀況!這是由於在不進行刷新的狀況下頁面的表單數據是瀏覽器第一次提交的緩存,故而進行提交的仍是第一次提交的數據。而進行刷新後則是一個新的request請求!框架
對此咱們如何進行防止表單的重複提交呢?下面咱們來進行說一下:jsp
① . 咱們提供一個隱藏域: <input type="hidden" name="token" value="vincent"/>.來進行做爲標記。這時咱們發現當咱們將數據提交到Servlet中時,沒有方法清除固定的請求參數(即:標記).因此該方案是行不通的!學習
② . 把標記放在 request 中.這時雖然咱們能夠經過做用域的removeAttribute(str);方法將標記進行刪除 可是當咱們請求表單頁面時雖然將標記保存到request中, 而咱們點擊提交按鈕時,將會向Servlet從新提交一個新的request,而此時第一個request已經失去了它的做用域(咱們知道request只能在一次請求之間有效!)被銷燬掉,故而沒法在目標Servlet中獲取到第一request設置的屬性(標記),因此該方案也行不通!spa
③. 把標記放在 session 中. 能夠!同時咱們也能夠使用隱藏域來幫助咱們將標記變成一個隨機值。token
> 在原表單頁面, 生成一個隨機值 token圖片
String tokenValue = new Data().getTime() + 「」;
(使用時間來做爲隨機值,還不夠隨機,不過暫時對於咱們學習而言還能夠,切記在工做中使用時間來做爲隨機值,由於在大量的用戶訪問咱們的產品時,時間就不能做爲隨機數了)
> 在原表單頁面, 把 token 值放入 session 屬性中
session.setAttribute(「token」,tokenValue);
> 在原表單頁面, 把 token 值放入到 隱藏域 中.
<input type=」hidden」 name=」token」value=<%=tokenValue%> />
> 在目標的 Servlet 中: 獲取 session 和 隱藏域 中的 token 值
Object token = request.getSession.getAttribute(「token」);
String tokenValue = request.getParameter(「token」);
> 比較兩個值是否一致: 若一致, 受理請求, 且把 session 域中的 token 屬性清除
> 若不一致, 則直接響應提示頁面: "重複提交"
if( token != null && token.equals(tokenValue)){
session.removeAttribute(「token」);
}else{
response.sendRedirect("repeated.jsp");//響應提示頁面: "重複提交"
}
response.sendRedirect("success.jsp");
以上就能夠解決表單重複提交的問題了!此外當咱們在框架中如Struts一、Struts二、SpringMVC中也能夠看到它們也提供了相應的解決方法!
下面咱們來講一下,關於驗證碼的問題:
對於爲何要使用驗證碼的緣由相信你們都知道在此就不在贅述了!其實對於驗證碼來講,和防止表單重複提交同樣的原理同樣。
> 在原表單頁面, 生成一個驗證碼的圖片, 生成圖片的同時, 須要把該圖片中的字符串放入到 session 中.
> 在原表單頁面, 定義一個文本域, 用於輸入驗證碼.
> 在目標的 Servlet 中: 獲取 session 和 表單域 中的 驗證碼的 值
> 比較兩個值是否一致: 若一致, 受理請求, 且把 session 域中的 驗證碼 屬性清除
> 若不一致, 則直接經過重定向的方式返回原表單頁面, 並提示用戶 "驗證碼錯誤"