重复提交:用户在点击提交后,后台程序还未处理完成,用户不知道,等得不耐烦了,又不断的点击提交,导致后台多次操作重复提交的数据,导致数据错误。所以怎样解决这样的问题呢?
解决的途径有两种:
1.前端控制
2.后台session判断
前端控制有两种方法,一个是提交后通过该将提交按钮置灰(这种体验极不好不推荐),一个是通过js控制只提交一次。
下面我们来看看通过js控制只提交一次的方式:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta content="text/html; charset=utf-8">
<title>Form Page</title>
</head>
<body>
<form action="SubmitServlet" method="post" onsubmit = "return isFirstSumbmit()">
<input type = "text" name = "userName" value=""/>
<input type = "submit" value="提交">
</form>
<script type="text/javascript">
//提交标志 true 为已提交,false为未提交
var subFlag = false;
function isFirstSumbmit(){
if(!subFlag){
subFlag = true;
return true;
} else {
return false;
}
}
</script>
</body>
</html>
这种前端控制的方式 缺点是我提交成功过后,点浏览器的返回上一步(没有走后台的servlet),点击提交的话,数据还是会重复提交。
下面来看后端session的方式:
进入表单页面时服务端生成token设置在前端的隐藏域中,每次提交的时候比较前端提交的token是否与服务端的一致,如果一致表明没有重复提交。保存数据成功后将服务端的token置空。如果不一致表示重复提交了(或者是前端伪造了token)。
form表单页面:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta content="text/html; charset=utf-8">
<title>Form Page</title>
</head>
<body>
<form action="SubmitServlet" method="post">
<input type = "hidden" name="token" value="${token}"/>
<input type = "text" name = "userName" value=""/>
<input type = "submit" value="提交">
</form>
</body>
</html>
进入form页面的servlet:
package com.session;
import java.io.IOException;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
// 进入到 form.jsp 的servlet
public class ToFormPageServlet extends HttpServlet{
public String getToken() {
return UUID.randomUUID().toString();
}
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 随机生成token
String tokenValue = getToken();
HttpSession session = req.getSession();
// token 放入session中
session.setAttribute("token", tokenValue);
System.out.println("生成token成功,token值为:"+ tokenValue);
req.getRequestDispatcher("form.jsp").forward(req, resp);
}
}
表单提交的servlet:
package com.session;
import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SubmitServlet extends HttpServlet{
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp){
resp.setContentType("text/html;charset=utf-8");
if(!isFirstSubmit(req)) {
try {
resp.getWriter().write("表单重复提交!");
} catch (IOException e) {
e.printStackTrace();
}
return ;
}
try {
Thread.sleep(3000);
if(isFirstSubmit(req)){
System.out.println("数据入库"+req.getParameter("userName"));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
resp.getWriter().write("数据保存成功!");
} catch (IOException e) {
e.printStackTrace();
}
// 清除token
req.getSession().removeAttribute("token");
}
/**
* 判断是否重复提交
* @param req
* @return
*/
public boolean isFirstSubmit(HttpServletRequest req) {
// 获取表单提交的token
String token = req.getParameter("token");
// 去拿session里的token
String servicToken = (String)req.getSession().getAttribute("token");
// servicToken 为空 重复提交
if(servicToken == null) {
return false;
}
// 表单提交的token 与服务端的不一致 (防止伪造token)
if(!servicToken.equals(token)) {
return false;
}
return true;
}
}