一个小例子,模拟银行转账,在转账的页面,点击转账,就可以向对方账户进行转账
但是转账成功之后,如果刷新页面,就会弹出一条提示,如果点击继续,就会重复提交,再转账一次,不断刷新,也就会不断转账,那么如何解决表单重复提交的问题呢?
可以使用一个标志,在服务器端存储一个标志(令牌),然后在客户端也存储一个,通过匹配两个令牌,来判断是否可以转账
在第一次请求转账页面的时候会创建令牌,然后在转账后(无论成功与否)删除服务器端的令牌,这样下次刷新后再请求转账,就会出现令牌不匹配的情况,也就无法再次转账了,这样就解决了表单重复提交的问题
使用JavaWeb工程,JSP+Servlet技术
在工具类中创建一个令牌的工具类
两个方法:
创建令牌:将令牌存储到session中,创建时也就是存储在服务器端(实际上令牌就是一个随机数)删除令牌:删除session中存储的令牌 package com.robot.utils; import javax.servlet.http.HttpServletRequest; /** * 令牌工具类。 * * @author 张宝旭 */ public class TokenUtils { /** * 创建令牌 */ public static void makeToken(HttpServletRequest request, String tokenName) { String token = String.valueOf(System.currentTimeMillis() + Math.random() * 9999); request.getSession().setAttribute(tokenName, token); } /** * 删除令牌 */ public static void removeToken(HttpServletRequest request, String tokenName) { request.getSession().removeAttribute(tokenName); } }在转账的jsp页面中先获取服务器端的令牌
<% TokenUtils.makeToken(request, "serverToken"); String serverToken = (String) session.getAttribute("serverToken"); %>然后在表单中跟随转账账号和金额一同提交给Servlet,使用hidden="hidden"表示隐藏此输入框,就是为了提交到Servlet,所以不用显示
<input type="text" name="clientToken" value="${serverToken}" hidden="hidden">在处理转账的Servlet中创建一个方法,用以判断令牌的状态,如果发现表单重复提交,就返回true
public boolean isRepeat(HttpServletRequest request) { // 获取服务器端令牌 Object serverToken = request.getSession().getAttribute("serverToken"); // 获取客户端令牌 String clientToken = request.getParameter("clientToken"); // 判断 if (serverToken == null || clientToken == null) { return true; } if (!serverToken.equals(clientToken)) { return true; } return false; }再在doGet或doPost方法中添加判断之后的处理,如果发生表单重复提交,就转发到另一个提示的页面,显示“页面已失效”,如果没有发生表单重复提交,就将令牌删除掉,防止表单重复提交,然后就正常执行后面的处理转账的语句
if (isRepeat(request)) { request.setAttribute("msg", "页面已失效"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; } TokenUtils.removeToken(request, "serverToken");演示
在转账成功后,刷新页面,会提示是否重复提交表单,然后点击继续,则跳转到指定页面
说明已经成功解决了表单重复提交的问题
如果想要再次转账,那么点击返回,也是不行的,因为令牌是在请求jsp页面的时候创建的,所以需要在返回到转账页面之后,再刷新一下,也就是重新请求一次,就可以再正常转账了。