博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaWeb使用Session防止表单重复提交
阅读量:6507 次
发布时间:2019-06-24

本文共 5642 字,大约阅读时间需要 18 分钟。

在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交。

 

1.什么是表单重复提交

 

> 在不刷新表单页面的前提下:

        >> 多次点击提交按钮
        >> 已经提交成功, 按 "回退" 之后, 再点击 "提交按钮".
        >> 在控制器响应页面的形式为转发情况下,若已经提交成功, 然后点击 "刷新(F5)"

 

> 注意:

        >> 若刷新表单页面, 再提交表单不算重复提交
        >> 若使用的是 redirect 的响应类型(地址栏发生变化), 已经提交成功后, 再点击 "刷新", 不是表单的重复提交

 

2、客户端利用JavaScript防止表单重复提交

既然存在上述所说的表单重复提交问题,那么我们就要想办法解决,比较常用的方法是采用JavaScript来防止表单重复提交,具体做法如下:

修改form.jsp页面,添加如下的JavaScript代码来防止表单重复提交

 

 

 

<%@ page language="java" contentType="text/html; charset=utf-8"    pageEncoding="utf-8"%>
首页
用户名 :

 

我们看看使用了JavaScript来防止表单提交重复是否可以成功,运行效果如下:

 

后退之后按钮不能点击

另外还有一种做法就是提交表单后,将提交按钮隐藏起来,这种做法和将提交按钮设置为不可用是差不多的,个人觉得将提交按钮隐藏影响到页面布局的美观,并且 可能会让用户误以为是bug(怎么我一点击按钮,按钮就不见了呢?用户可能会有这样的疑问),我个人在开发中用得比较多的是表单提交后,将提交按钮设置为 不可用,反正使用JavaScript防止表单重复提交的做法都是差不多的,目的都是让表单只能提交一次,这样就可以做到表单不重复提交了

三、利用Session防止表单重复提交(常用)

在服务器端解决,在服务器端解决就需要用到session了。

具体的做法:在服务器端生成一个唯一的随机标识号,专业术语称为 Token(令牌),同时在当前用户的Session域中保存这个Token。然后将Token发送到客户端的Form表单中,在Form表单中使用隐藏 域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端,然后在服务器端判断客户端提交上来的Token与服务器端生成的 Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的 Session域中存储的标识号。

  在下列情况下,服务器程序将拒绝处理用户提交的表单请求:

    1. 存储Session域中的Token(令牌)与表单提交的Token(令牌)不同。
    2. 当前用户的Session中不存在Token(令牌)
    3. 用户提交的表单数据中没有Token(令牌)

 

1.产生随机数(令牌)跳转到表单页面的Java

package Session;import java.io.IOException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.Random;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 javax.servlet.http.HttpSession;import sun.misc.BASE64Encoder;@WebServlet("/ServletForm_2")public class ServletForm_2 extends HttpServlet {    private static final long serialVersionUID = 1L;     public ServletForm_2() {        super();            }    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        TokenProcessor tp=TokenProcessor.getTp();        String rand=tp.getToken();        HttpSession session=request.getSession();        session.setAttribute("rand", rand);   //用session将数据带过去        request.getRequestDispatcher("/SecondForm.jsp").forward(request,response);;                    }    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {                doGet(request, response);    }}//令牌处理器,产生一个随机数,单利模式,一个对象产生class TokenProcessor{    //单利模式    /***     * 1.构造方法私有     * 2.创建一个对象       3.公开一份方法暴露对象     */    private  TokenProcessor() {            }        private static TokenProcessor tp=new TokenProcessor();    public static TokenProcessor getTp(){        return tp;    }        public String getToken(){        //token是系统当前时间毫秒数+随机数变为的字符串。长度不同        String token=System.currentTimeMillis()+new Random().nextInt()+"";        //利用MD5摘要算法得到固定长度的字符串        try {            MessageDigest md=MessageDigest.getInstance("md5");            //根据MD5算法得到数据的指纹            byte[] md5=md.digest(token.getBytes());            //BASE64编码,3BYTE变为4byte(每6位前面加2零)            BASE64Encoder encoder=new BASE64Encoder();            String ss=encoder.encode(md5);            return ss;        } catch (NoSuchAlgorithmException e) {            // TODO Auto-generated catch block            throw new RuntimeException(e);         }    }        }

 

表单JSP:

<%@ page language="java" contentType="text/html; charset=utf-8"    pageEncoding="utf-8"%>
Insert title here
用户名:
密码:
">

 

处理表单的Servlet

package Session;import java.io.IOException;import java.io.PrintWriter;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 javax.servlet.http.HttpSession;/** * Servlet implementation class lOGIN2 */@WebServlet("/lOGIN2")public class lOGIN2 extends HttpServlet {    private static final long serialVersionUID = 1L;           /**     * @see HttpServlet#HttpServlet()     */    public lOGIN2() {        super();        // TODO Auto-generated constructor stub    }    /**     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)     */    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        //判断带过的随机数是否有效        boolean isValied=isTokenValid(request);                if(!isValied){System.out.println("无效,请不要重复提交!"); return ;}                        request.getSession().removeAttribute("rand");        System.out.println("正在提交。。。。。。。。。");                            }    private boolean isTokenValid(HttpServletRequest request) {        //服务器端带随机数    String ser_hid=(String) request.getSession().getAttribute("rand");        //客户端带过来带随机数    String cli_hid=request.getParameter("hid");    System.out.println(ser_hid+"         "+cli_hid+"    5");        if(cli_hid==null){
return false;} if(ser_hid==null){
return false;} if(!cli_hid.equals(ser_hid)){
return false;} return true; } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); }}

 

结果:  http://localhost:8080/Servlet/ServletForm_2

查看页面源码:

 

第一次提交:

 

刷新页面:

 

后退后提交:

 

 

 

********: struts的防止表单重复提交比较简单,参考:  

 

转载地址:http://ztwfo.baihongyu.com/

你可能感兴趣的文章
LaPlayer(1)------Service浅析
查看>>
Optional与Mybatis能否一起
查看>>
javascript-window对象的方法和属性文档大全
查看>>
仿QQ大战—服务器的搭建(ServerSocket)
查看>>
下单快发货慢:一个 JOIN SQL 引起 SqlClient 读取数据慢的奇特问题
查看>>
IIS 6.0/7.0/7.5、Nginx、Apache 等Web Service解析漏洞总结
查看>>
Django 模板之组件、静态文件导入
查看>>
DVWA SQL Injection LOW
查看>>
mysql only_full_group_by
查看>>
Dede 查询附加表
查看>>
如何优雅的拔盘?
查看>>
虚拟机网络设置
查看>>
Google - Largest Sum Submatrix
查看>>
高中数学中需要重点关注的函数和图像
查看>>
兄弟我即将离开上海,手上一些书,送给爱书的人!亲要的速度进!本人只送爱读书的人!不读书者请绕道!契约2年内此书必须转让别人...
查看>>
Idea中使用git
查看>>
文本监控 :oninput onchange onpropertychange 的区别
查看>>
javascript中setInterval与setTimeout中this的问题以及对于闭包的一些理解
查看>>
HDU 1086 You can Solve a Geometry Problem too
查看>>
清除Css中select的下拉箭头样式
查看>>