解決方案
使用javascript 解決
?既然存在上述所說(shuō)的表單重復(fù)提交問(wèn)題,那么我們就要想辦法解決障斋,比較常用的方法是采用JavaScript來(lái)防止表單重復(fù)提交纵潦,具體做法如下:
修改form.jsp頁(yè)面当纱,添加如下的JavaScript代碼來(lái)防止表單重復(fù)提交
代碼:
<%@pagelanguage="java"contentType="text/html; charset=UTF-8"
??? pageEncoding="UTF-8"%>
DOCTYPEhtmlPUBLIC"-//W3C//DTD
? HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Form表單title>
<scripttype="text/javascript">
??? var isFlag = false;?//表單是否已經(jīng)提交標(biāo)識(shí)靶衍,默認(rèn)為false
?
??? function submitFlag() {
?
??????? if (!isFlag) {
??????????? isFlag =true;
??????????? return?true;
??????? }else {
??????????? return?false;
??????? }
?
??? }
script>
head>
?
<body>
??? <formaction="${pageContext.request.contextPath}/DoFormServlet"
??????? method="post"onsubmit="return submitFlag()">
??????? 用戶(hù)名:<inputtype="text"name="userName">?"submit"
??????????? value="提交"id="submit">
??? form>
body>
html>
?除了用這種方式之外,經(jīng)常見(jiàn)的另一種方式就是表單提交之后椅挣,將提交按鈕設(shè)置為不可用遂庄,讓用戶(hù)沒(méi)有機(jī)會(huì)點(diǎn)擊第二次提交按鈕寥院,代碼如下:
function dosubmit(){
? //獲取表單提交按鈕
? var btnSubmit = document.getElementById("submit");
? //將表單提交按鈕設(shè)置為不可用,這樣就可以避免用戶(hù)再次點(diǎn)擊提交按鈕
? btnSubmit.disabled= "disabled";
? //返回true讓表單可以正常提交
? return true;
}
使用后端提交解決
?對(duì)于【場(chǎng)景二】和【場(chǎng)景三】導(dǎo)致表單重復(fù)提交的問(wèn)題涛目,既然客戶(hù)端無(wú)法解決秸谢,那么就在服務(wù)器端解決凛澎,在服務(wù)器端解決就需要用到session了。
? 具體的做法:在服務(wù)器端生成一個(gè)唯一的隨機(jī)標(biāo)識(shí)號(hào)估蹄,專(zhuān)業(yè)術(shù)語(yǔ)稱(chēng)為Token(令牌)塑煎,同時(shí)在當(dāng)前用戶(hù)的Session域中保存這個(gè)Token。然后將Token發(fā)送到客戶(hù)端的Form表單中元媚,在Form表單中使用隱藏域來(lái)存儲(chǔ)這個(gè)Token轧叽,表單提交的時(shí)候連同這個(gè)Token一起提交到服務(wù)器端,然后在服務(wù)器端判斷客戶(hù)端提交上來(lái)的Token與服務(wù)器端生成的Token是否一致刊棕,如果不一致炭晒,那就是重復(fù)提交了,此時(shí)服務(wù)器端就可以不處理重復(fù)提交的表單甥角。如果相同則處理表單提交网严,處理完后清除當(dāng)前用戶(hù)的Session域中存儲(chǔ)的標(biāo)識(shí)號(hào)。? 在下列情況下嗤无,服務(wù)器程序?qū)⒕芙^處理用戶(hù)提交的表單請(qǐng)求:
[if !supportLists]1.????????[endif]存儲(chǔ)Session域中的Token(令牌)與表單提交的Token(令牌)不同震束。
[if !supportLists]2.????????[endif]當(dāng)前用戶(hù)的Session中不存在Token(令牌)。
[if !supportLists]3.????????[endif]用戶(hù)提交的表單數(shù)據(jù)中沒(méi)有Token(令牌)当犯。
轉(zhuǎn)發(fā)代碼:
@WebServlet("/ForwardServlet")
public?class?ForwardServlet?extends? HttpServlet {
???? @Override
???? protected?void doGet(HttpServletRequest
? req, HttpServletResponse resp) throws ServletException, IOException {
???????? req.getSession().setAttribute("sesionToken", TokenUtils.getToken());
???????? req.getRequestDispatcher("form.jsp").forward(req, resp);
???? }
}
轉(zhuǎn)發(fā)頁(yè)面:
<%@pagelanguage="java"contentType="text/html; charset=UTF-8"
????? pageEncoding="UTF-8"%>
DOCTYPEhtmlPUBLIC"-//W3C//DTD
? HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Form表單title>
?
head>
?
<body>
????? <formaction="${pageContext.request.contextPath}/DoFormServlet"
?????????? method="post"onsubmit="return dosubmit()">
?????????? <inputtype="hidden"name="token"value="${sesionToken}"> 用戶(hù)名:<inputtype="text"
???????????????? name="userName">?"submit"value="提交"id="submit">
????? form>
body>
html>
后端Java代碼:
@WebServlet("/DoFormServlet")
public?class?DoFormServlet?extends HttpServlet {
???? @Override
???? protected?void? doPost(HttpServletRequest req,
? HttpServletResponse resp) throws ServletException, IOException {
???????? req.setCharacterEncoding("UTF-8");
???????? boolean?flag = isFlag(req);
???????? if (!flag) {
????????????? resp.getWriter().write("已經(jīng)提交...");
????????????? System.out.println("數(shù)據(jù)已經(jīng)提交了..");
????????????? return;
???????? }
???????? StringuserName = req.getParameter("userName");
???????? try {
????????????? Thread.sleep(300);
???????? }catch (Exception e) {
????????????? // TODO: handle exception
???????? }
???????? System.out.println("往數(shù)據(jù)庫(kù)插入數(shù)據(jù)...." + userName);
???????? resp.getWriter().write("success");
???? }
???? public?boolean? isFlag(HttpServletRequest request) {
???????? HttpSessionsession = request.getSession();
???????? StringsesionToken = (String) session.getAttribute("sesionToken");
???????? Stringtoken = request.getParameter("token");
???????? if (!(token.equals(sesionToken))) {
????????????? return?false;
???????? }
???????? session.removeAttribute("sesionToken");
???????? return?true;
???? }
}
Filter 也稱(chēng)之為過(guò)濾器垢村,它是 Servlet 技術(shù)中最實(shí)用的技術(shù),Web 開(kāi)發(fā)人員通過(guò) Filter 技術(shù)嚎卫,對(duì) web 服務(wù)器管理的所有 web 資源:例如 Jsp,
Servlet, 靜態(tài)圖片文件或靜態(tài) html文件等進(jìn)行攔截嘉栓,從而實(shí)現(xiàn)一些特殊的功能。例如實(shí)現(xiàn) URL級(jí)別的權(quán)限訪問(wèn)控制拓诸、過(guò)濾敏感詞匯侵佃、壓縮響應(yīng)信息等一些高級(jí)功能。
它主要用于對(duì)用戶(hù)請(qǐng)求進(jìn)行預(yù)處理奠支,也可以對(duì)HttpServletResponse 進(jìn)行后處理馋辈。使用 Filter的完整流程:Filter 對(duì)用戶(hù)請(qǐng)求進(jìn)行預(yù)處理,接著將請(qǐng)求交給 Servlet 進(jìn)行處理并生成響應(yīng)倍谜,最后 Filter 再對(duì)服務(wù)器響應(yīng)進(jìn)行后處理迈螟。