使用session防止表单进行重复提交
我们都知道可以通过js的方法来实现防止表单重复提交,但是js只适用于“在网络延迟的情况下让用户有时间点击多次submit按钮导致表单重复提交” 的情况下进行操作,
那如果碰到“表单提交后用户点击【刷新】按钮导致表单重复提交”和“用户提交表单后,点击浏览器的【后退】按钮回退到表单页面后进行再次提交”的场景下JS就显得心有余而力不足了,这个时候我们可以通过java当中生成token验证token来实现防止表单提交;
先看一下我的项目结构:
我们用到的只有这四个页面,其他的可以忽略
首先先来看一下创建token的servlet,tokenDemo.java:
package session; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(name = "TokenDemo",urlPatterns = {"/session/TokenDemo"}) public class TokenDemo extends HttpServlet { private static final long serialVersionUID = -884689940866074733L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String token = TokenProccessor .getInstance().makeToken();//创建令牌 // System.out.print("生成的令牌token是"+token); request.getSession().setAttribute("token",token); //存到session里面 request.getRequestDispatcher("/token.jsp").forward(request,response); } }
这里面有一个生成token的类,叫做TokenProccessor,接下来我们看看token是怎么生成的,
TokenProccessor .java:
package session; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Random; import sun.misc.BASE64Encoder; public class TokenProccessor { private TokenProccessor() {} ; private static final TokenProccessor instance = new TokenProccessor(); public static TokenProccessor getInstance() { return instance; } //生成token public String makeToken(){ String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + ""; try{ MessageDigest md = MessageDigest.getInstance("md5"); byte md5[] = md.digest(token.getBytes()); BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(md5); }catch(NoSuchAlgorithmException e){ throw new RuntimeException(e); } } }
好,我们现在有了token,我们可以在页面上去使用它:token.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>token</title> </head> <body> <form action="${pageContext.request.contextPath}/session/ResultToken" method="post"> <%--使用隐藏存储生成token--%> <input type="hidden" name="token" value="${token}"> 用户名:<input type="text" name="username"> <input type="submit" value="提交"> </form> </body> </html>
我们接下来应该干嘛呢,对,当然是要进行表单的验证啦,resultToken.java:
package session; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(name = "ResultToken", urlPatterns = {"/session/ResultToken"}) public class ResultToken extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=utf-8"); boolean b = isRepeatSubmit(request); //判断用户是否重复提交; if (b == true) { response.getWriter().println("请不要重复提交"); return; } request.getSession().removeAttribute("token"); response.getWriter().println("处理用户提交请求"); } /*** * 判断用户提交上来的token和服务器生成的token是否一致 * true:重复提交了 *false:没有重复提交 * */ private boolean isRepeatSubmit(HttpServletRequest request) { String client_token = request.getParameter("token"); //如果用户提交的没有token,那么用户则是重复提交了表单 if (client_token == null) { return true; } //取出session中的token String server_token = (String) request.getSession().getAttribute("token"); //如果哦用户的session里面不存在Token,则用户重复提交了表单 if (server_token.equals(client_token)) { return true; } return false; } }
ok,记得写完servlet的时候必须要去web.xml配置一下,不然取不到路径。所有的登录都需要来验证token。