在做项目或者做一些小程序开发的过程中,有可能会遇到表单重复提交的问题。那么在什么情况下会出现表单的重复提交的问题呢?第一:刷新页面的时候有可能出现重复提交表单,异步提交不会出现这种问题。第二:页面跳转,也有可能出现重复提交。比如用户新增后再刷新页面,然后,这样就很容易出现重复提交。一旦用户刷新页面,表单就会再次提交。异步提交可以避免表单的重复提交的问题。
当我们刷新页面的时候,就会出现以下这个问题
如何解决表单重复提交的问题呢?在当前用户的Session域中保存Token(令牌),然后将生成的Token发送到客户端的Form表单中。在Form表单中使用隐藏域来存储Token,表单提交的时间连同Token一起提交到服务器端,然后在服务器端判断客户端提交过来的Token与服务器端生成的Token是否一致。如果不一致,那就是Form表单重复提交;如果相同则处理表单提交,处理完后清除当前用户的Session域中储存的Token。
理解图:
在一下的几种情况下,服务器会拒绝处理用户提交的表单请求:
1、 存储Session域中的Token(令牌)与表单提交的Token不同。
2、 当前用户的Session中不存在Token。
3、 用户提交的表单数据中没有Token。
封装的类
package com.gx.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import sun.misc.BASE64Encoder;
public class TokenProccessor {
/*
*单例设计模式(保证类的对象在内存中只有一个)
*1、把类的构造函数私有
*2、自己创建一个类的对象
*3、对外提供一个公共的方法,返回类的对象
*/
private TokenProccessor(){}
private static final TokenProccessor instance = new TokenProccessor();
public static TokenProccessor getInstance(){
return instance;
}
public String makeToken(){ //checkException
// 7346734837483 834u938493493849384 43434384 //获取单前时间再加上随机数
String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
//数据指纹 128位长 16个字节 md5
try {
//java.security.MessageDigest 类用于为应用程序提供信息摘要算法的功能
MessageDigest md = MessageDigest.getInstance("md5");
byte md5[] = md.digest(token.getBytes());
//base64编码--任意二进制编码明文字符 adfsdfsdfsf
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(md5);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
Jsp的核心代码如下:
<body>
<form action="${ctx}/servlet/LoginServlet" method="post">
<!-- 通过EL表达式获取session中的token值 -->
<input type="hidden" name="token" value="${token}"/>
<!-- 通过session表达式获取token的值 -->
<!-- <input type="hidden" name="token" value="<%=session.getAttribute("token") %>"> -->
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="name"/></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"/></td>
</tr>
<tr>
<td>验证码:</td>
<td><input type="text" name="codekey"/></td>
</tr>
<tr>
<td>
<img id="codekey" alt="" src="${ctx}/servlet/IdentityServlet?t=${now}" onclick="refcodekey()"></td>
</tr>
<tr>
<td>
<input type="submit" value="登录"/>
</td>
</tr>
</table>
</form>
<script type="text/javascript">
function refcodekey(){
document.getElementById("codekey").src="${ctx}/servlet/IdentityServlet?t="+new Date();
}
</script>
</body>
Servlet的核心代码:
public void toLogin(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String token = TokenProccessor.getInstance().makeToken();//获取token值
request.getSession().setAttribute("token", token);//把token值保存到session中
request.getRequestDispatcher("/jsp/login.jsp").forward(request, response);//页面跳转
}
public void login(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取页面的值
String name=request.getParameter("name");
String password=request.getParameter("password");
String codekey=request.getParameter("codekey");
String token=request.getParameter("token");
String sessionCodekey=(String) request.getSession().getAttribute("randomString");//验证码
//获取session中的token值
String sessiontoken=(String) request.getSession().getAttribute("token");
if (token!=null && token.equals(sessiontoken)) {
//判断Form表单的token和session中的token是否相等
request.getSession().removeAttribute("token");
if (codekey!=null && codekey.equalsIgnoreCase(sessionCodekey)) {
IUserService userService=new UserSerivceImpl();
UserPo dbUser=userService.login(name);
if (dbUser!=null) {
if (dbUser.getPassword().equals(password)) {
request.getSession().setAttribute("gUser", dbUser);
} else {
request.setAttribute("error", "密码错误");
request.getRequestDispatcher("/jsp/error.jsp").forward(request, response);
}
} else {
request.setAttribute("error", "没有此用户");
request.getRequestDispatcher("/jsp/error.jsp").forward(request, response);
}
} else {
response.sendRedirect("../index.jsp");//重定向页面
}
} else {
System.out.println("重复提交");
response.sendRedirect("../index.jsp");
}
}