防止用户重复提交表单
由于没有用jsp,所以在这个实例中用一个servlet来输出表单页面,另一个servlet用来处理表单。具体思路在程序中写出:
/* * 防止表单重复提交 * 思路:程序在生成表单的时候带个随机数,在服务器端检查表单带的随机数与服务器中的随机数是否一致 * 在客户端也可以javascript代码来阻止 * 客户端阻止会减小服务器的压力,不过在开发的时候,客户端和服务器端都需要进行阻止 * 在服务器端阻止的话,该表单需要由某个程序生成,这里用servlet来代替 */ public class FormServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); String token = TokenProcessor.getInstance().makeToken();//获得随机数 request.getSession().setAttribute("token", token);//在服务器端保存随机数 //产生表单 out.println("<form action='/test/servlet/DoFormServlet' method='post'>"); out.println("<input type='hidden' name='token' value='" + token + "'/>");//通过隐藏字段带一个随机数给服务器 out.println("用户名:<input type='text' name='username'/>"); out.println("<input type='submit' value='提交'/>"); out.println("</form>"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } class TokenProcessor { /* * 随机数应该要保证唯一性,所以最好用一个对象来生成。所以该类需要设计成单例的。 * 单例设计模式:(保证类的对象在内存中只有一个) * 1. 把类的构造函数私有 * 2. 自己创建一个类的对象 * 3. 对外提供一个公共方法,返回类的对象 */ private TokenProcessor(){} private static final TokenProcessor instance = new TokenProcessor(); public static TokenProcessor getInstance() { return instance; } //产生一个随机数 public String makeToken() { String token = (System.currentTimeMillis() + new Random().nextInt(9999999)) + ""; /* * 数据指纹:不管数据多大,得到的数据指纹都是相同大小,128位长-16字节 * 拿到数据指纹再反推原始数据是不可能的。 * 我们可以使用md5算法可以得到数据指纹。 */ try { MessageDigest md = MessageDigest.getInstance("md5");//获得md5算法 byte md5[] = md.digest(token.getBytes());//将上面的token转成字节后,获得其指纹,存到字节数组中 /* * 不能像下面这样return,可能会出现乱码 * 因为md5中保存的是字节,new String(md5)的时候会将字节转成字符串,这样就必然要去查码表,如果没指定就查gb2312 * 如果相应的字节在码表中没有那就出现乱码 */ //return new String(md5); /* * base64编码:将任意二进制编码成明文字符。 * 如:把3字节变成4字节,并且把每一个字节的数据变成一个字符串 * 假设有三字节数据: 01010000 01010011 01100101 总共24位 * 变成4字节的话,每个字节存储该数据的6位,剩下2位补0, * 所以base64编码后的数据为: 00 010100 00 00 0101 00 0011 01 00 100101 * 编码后的数据,最小值为0,最大值为63,共有64个数据,故称为base64编码 * 在0-63之间都有字符与之对应,这些字符都是键盘上可以看到的某个字符。 */ BASE64Encoder encoder = new BASE64Encoder();//第一次使用的时候可能无法import包,解决方案如下: /* * 解决方案1(推荐): * 只需要在project build path中先移除JRE System Library,再添加库JRE System Library,重新编译后就一切正常了。 * 解决方案2: * Windows -> Preferences -> Java -> Compiler -> Errors/Warnings -> * Deprecated and trstricted API -> Forbidden reference (access rules): -> 改为warning */ return encoder.encode(md5); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e);//转成运行时异常,这样上面就不需要处理了 //一般情况下,都是将异常转成运行时异常往上抛; //有一种情况:希望上面处理这个异常,那么我们抛编译时异常。 } } }
用户提交后,会交给DoFormServlet去处理,我们看一下DoFormServlet.java:
//处理表单数据 public class DoFormServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); boolean b = isToken(request); // if(b == false) { System.out.println("请不要重复提交!"); return; } //处理提交请求之前,需要先将session中保存的随机数移除掉 request.getSession().removeAttribute("token"); System.out.println("处理用户提交请求!"); } private boolean isToken(HttpServletRequest request) { String clientToken = request.getParameter("token");//客户端token if(clientToken == null) return false; String serverToken = (String)request.getSession().getAttribute("token");//服务器端token if(serverToken == null)//如果已经提交过一次了,服务器会把随机数移除掉,serverToken就变成null了 return false; if(!clientToken.equals(serverToken)) return false; return true; } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
过程是这样的,用户在登陆之前,服务器端会先生成一个token,然后将这个token存到session中,并将其作为隐藏字段打给浏览器让用户登陆,很明显,用户登陆后就会将这个token带过来,服务器端处理请求前会先判断客户端带过来的token和session中保存的是否一样,是的话将session中的token删掉,然后处理请求,这时候session中已经没有这个token了,当用户回退再次提交时,服务器端又会判断,这时候就会返回false了,就提示用户不要重复提交。
$.ajax请求中有一个beforeSend方法,用于在向服务器发送请求前执行一些动作。
$.ajax({ beforeSend: function(){ // Handle the beforeSend event }, complete: function(){ // Handle the complete event } // ...... });
防止重复数据
在实际项目开发中,提交表单时常常由于网络或者其原因,用户点击提交按钮误认为自己没有操作成功,进而会重复提交按钮操作次数,如果页面前端代码没有做一些相应的处理,通常会导致多条同样的数据插入数据库,导致脏数据的增加。要避免这种现象,在$.ajax请求中的beforeSend方法中把提交按钮禁用掉,等到Ajax请求执行完毕,在恢复按钮的可用状态。
// 提交表单数据到后台处理 $.ajax({ type: "post", data: studentInfo, contentType: "application/json", url: "/Home/Submit", beforeSend: function () { // 禁用按钮防止重复提交 $("#submit").attr({ disabled: "disabled" }); }, success: function (data) { if (data == "Success") { //清空输入框 clearBox(); } }, complete: function () { $("#submit").removeAttr("disabled"); }, error: function (data) { console.info("error: " + data.responseText); } });
ajax请求服务器加载数据列表时提示loading(“加载中,请稍后...”),
$.ajax({ type: "post", contentType: "application/json", url: "/Home/GetList", beforeSend: function () { $("loading").show(); }, success: function (data) { if (data == "Success") { // ... } }, complete: function () { $("loading").hide(); }, error: function (data) { console.info("error: " + data.responseText); } });
<script Language='JavaScript'> function formsubmit() { Today = new Date(); var NowHour = Today.getHours(); var NowMinute = Today.getMinutes(); var NowSecond = Today.getSeconds(); var mysec = (NowHour*3600)+ (NowMinute*60)+NowSecond; if((mysec-document.formsubmitf.mypretime.value)>600) //600只是一个时间值,就是5分钟内禁止重复提交,值随你高兴设 { document.formsubmitf.mypretime.value=mysec; } else { alert(' 按一次就够了,请勿重复提交!请耐心等待!谢谢合作!'); return false; } document.forms.formsubmitf.submit(); } </script>
参考:
https://blog.csdn.net/eson_15/article/details/51262736
https://blog.csdn.net/mggwct/article/details/52153591
立志如山 静心求实
浙公网安备 33010602011771号