防止表单重复提交

平时,如果网速较慢,用户提交表单后,如果服务器一段时间没有反应,用户很可能会再次点击提交,导致重复提交表单,因此开发中我们必须考虑到这一问题

  • 方法一:在javascript中防止表单重复提交
    <script type="text/javascript">
        var isCommited = false;
        function dosubmit() {
            if (isCommited == false) {
                isCommited = true;
                return true;
            }
            else return false;
        }
    </script>

但是这种方式只能防止“网络延迟”这种情况,其他情况,e.g.用户后退到表单页面重新点击提交 or 提交后点击刷新再次提交 无法被解决

  • 方法二:用session防止表单重复提交
    具体做法:
    1. 在服务器生成一个唯一的随机标识号(token),同时在当前用户的session中保存这个token
    2. 将token发送到客户端的form表单中
    3. 在form中隐藏存储这个token
    4. 表单提交时将这个token**发回给服务器**
    5. 服务器判断发过来的token与服务器端生成的token是否一致,如果不一致就是重复提交,服务器将不予处理;如果一致,则服务器处理,处理完后清除当前用户的session中存储的标识号(token)

    在以下集中情况,服务器对客户端的表单请求不予处理:
    1. 存储session中的token与表单提交的token不一致
    2. 当前用户session中不存在token
    3. 用户提交的表单数据中没有token

FormServlet:用于生成token和跳转到form.jsp
@WebServlet(name = "FormServlet", value="/FormServlet")
public class FormServlet 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 {
        String token = TokenProccessor.getInstance().makeToken();//创建令牌
        System.out.println("生成token: " + token);
        request.getSession().setAttribute("token", token);//在服务器使用session保存token
        request.getRequestDispatcher("/form.jsp").forward(request, response);
    }
}
form.jsp:使用隐藏域存储token
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
    <title>Form表单</title>
</head>

<body>
<form action="${pageContext.request.contextPath}/DoFormServlet"  method="post">
    <%-- 隐藏存储的token --%>
    <%--
    <input type="submit" name="token" value="<%=session.getAttribute("token")%>">
    --%>
        <%-- 使用EL表达式取出存储在session的token --%>
        <input type="hidden" name="token" value="${token}"/>
    用户名:<input type="text" name="username">
    <input type="submit" value="提交" id="submit">
</form>
</body>
</html>
DoFormServlet:处理表单提交
@WebServlet(name = "DoFormServlet", value = "/DoFormServlet")
public class DoFormServlet extends HttpServlet {
    /**
     * 判断客户端提交的token与服务器端的是否一致
     * @param request
     * @return
     *          true: 用户重复提交了表单
     *          false: 用户没有重复提交表单
     */
    private boolean isRepeatSummit(HttpServletRequest request){

        String client_token = request.getParameter("token");

        //1. 如果用户提交的表单数据中没有token,则是重复提交了表单
        if (client_token == null) return true;
        //取出存在session中的token
        String server_token = (String) request.getSession().getAttribute("token");
        //2. 如果用户的session中不存在token,则是重复提交了表单
        if (server_token == null) return true;
        //3. 如果用户存在session中的token与表单提交的token不同,则是重复提交了表单
        if (!server_token.equals(client_token)) return true;
        return false;
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        boolean b = isRepeatSummit(request);
        //判断用户是否提交
        if (b){
            System.out.println("请不要重复提交");
            return;
        }
        //移除session中的token
        request.getSession().removeAttribute("token");
        System.out.println("已处理用户提交请求");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}
TokenProcessor:生成tokend的工具类
public class TokenProccessor {
    /**
     * 使用静态内部类方法实现单例模式
     */
    private TokenProccessor(){

    }

    private static class Holder{
        private static TokenProccessor instance = new TokenProccessor();
    }

    public static TokenProccessor getInstance(){
        return Holder.instance;
    }

    public String makeToken(){
        String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";

        //数据指纹
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance("md5");
            byte[] md5 = messageDigest.digest(token.getBytes());
            //base64编码
            BASE64Encoder encoder = new BASE64Encoder();
            return encoder.encode(md5);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException();
        }
    }
}

学习自博客:
http://www.cnblogs.com/xdp-gacl/p/3859416.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值