解决方案
使用javascript 解决
既然存在上述所说的表单重复提交问题,那么我们就要想办法解决,比较常用的方法是采用JavaScript来防止表单重复提交,具体做法如下:
修改form.jsp页面,添加如下的JavaScript代码来防止表单重复提交
代码:
<%@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; //表单是否已经提交标识,默认为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()">
用户名:<inputtype="text"name="userName"> "submit"
value="提交"id="submit">
form>
body>
html>
除了用这种方式之外,经常见的另一种方式就是表单提交之后,将提交按钮设置为不可用,让用户没有机会点击第二次提交按钮,代码如下:
function dosubmit(){
//获取表单提交按钮
var btnSubmit = document.getElementById("submit");
//将表单提交按钮设置为不可用,这样就可以避免用户再次点击提交按钮
btnSubmit.disabled= "disabled";
//返回true让表单可以正常提交
return true;
}
使用后端提交解决
对于【场景二】和【场景三】导致表单重复提交的问题,既然客户端无法解决,那么就在服务器端解决,在服务器端解决就需要用到session了。
具体的做法:在服务器端生成一个唯一的随机标识号,专业术语称为Token(令牌),同时在当前用户的Session域中保存这个Token。然后将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端,然后在服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。 在下列情况下,服务器程序将拒绝处理用户提交的表单请求:
[if !supportLists]1. [endif]存储Session域中的Token(令牌)与表单提交的Token(令牌)不同。
[if !supportLists]2. [endif]当前用户的Session中不存在Token(令牌)。
[if !supportLists]3. [endif]用户提交的表单数据中没有Token(令牌)。
转发代码:
@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);
}
}
转发页面:
<%@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}"> 用户名:<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("已经提交...");
System.out.println("数据已经提交了..");
return;
}
StringuserName = req.getParameter("userName");
try {
Thread.sleep(300);
}catch (Exception e) {
// TODO: handle exception
}
System.out.println("往数据库插入数据...." + 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 也称之为过滤器,它是 Servlet 技术中最实用的技术,Web 开发人员通过 Filter 技术,对 web 服务器管理的所有 web 资源:例如 Jsp,
Servlet, 静态图片文件或静态 html文件等进行拦截,从而实现一些特殊的功能。例如实现 URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
它主要用于对用户请求进行预处理,也可以对HttpServletResponse 进行后处理。使用 Filter的完整流程:Filter 对用户请求进行预处理,接着将请求交给 Servlet 进行处理并生成响应,最后 Filter 再对服务器响应进行后处理。
网友评论