JSP学习之------>客户端防表单重复提交和服务器端session防表单重复提交

1.什么叫表单重复提交:

     所谓表单重复提交,是指用户通过多次点击提交按钮或多次刷新表单提交页面等造成用户表单重复提交的现象

2.表单重复提交有哪些情况:

     (1)用户在程序提交表单的时间段里多次提交表单
     (2)重复刷新提交后的表单
     (3)用户点击浏览器回退按钮,然后再次提交

3.如果解决表单重复提交:

    (1)方法1:客户端防表单重复提交:  一般通过js代码防止第一种情况的发生,对于第二种和第三种的情况很难避免,并且稍微有经验的用户可以通过去掉页面js生成自己的html页面来访问服务器,这样客户端的防表单重复提交只能“防君子不能防小人”,并且可以增强用户体验感。

     (2)方法2:服务器端session防表单重复提交:一般是利用令牌的原理来实现表单重复提交的,具体做法:

           A. 对于用户每一次访问表单页面,均先经过CreateFormServlet的Servlet,其作用是在跳转表单页面之前,由BASE64Encoder类生成一个唯一的字符串,即表单号,并保存在session域中.

           B.然后用户提交表单时,带着表单号,先验证客户端提交过来的表单号和session域中的表单号是否相同,如果不同则证明是重复提交,如果相同,则证明是第一次提交,并将表单号从session域中移除。

4.例子程序:

regist.jsp

[html] view plaincopyprint?

  1. <%@ page language="java"import="java.util.*"pageEncoding="utf-8"%> 
  2.  
  3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
  4. <html> 
  5. <scripttype="text/javascript"> 
  6.     /*虽然客户端防表单重复提交,有很多漏洞,但是为了提高客户体验感,一把是客户端和服务器配合防表单重复提交, 
  7.               客户端防重复提交的漏洞:1.客户复制源代码,去掉此js脚本,生成自己的html页面,然后提交 
  8.                            2.重复刷新提交后的表单 
  9.                            3.用户点击浏览器回退按钮,然后再次提交 
  10.       
  11.              客户端防重复提交的代码: 
  12.        1.方法1: 
  13.          var isCommited =false; 
  14.          function dosubmit(){ 
  15.             if(!isCommited){ 
  16.                 isCommited =
    true; 
  17.                 return true; 
  18.             }else{ 
  19.                 return false; 
  20.             } 
  21.          } 
  22.      */ 
  23.       
  24.      //或者使"注册"按钮点击一次后不可用 
  25.          function dosubmit1(){ 
  26.             var input = document.getElementById("submit"); 
  27.             input.disabled="disabled"; 
  28.             return true; 
  29.          } 
  30.   </script> 
  31.   <body> 
  32.          <formaction="/CookieAndSession/servlet/regist"method="post"onsubmit="return
    dosubmit()"> 
  33.              用户名:<inputtype="text"name="username"value="aaa"><br/> 
  34.              <inputtype="hidden"name="c_token"value="${token}"> 
  35.              <inputid="submit"type="submit"value="注册"> 
  36.          </form> 
  37.    </body> 
  38. </html> 
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <script type="text/javascript">
    /*虽然客户端防表单重复提交,有很多漏洞,但是为了提高客户体验感,一把是客户端和服务器配合防表单重复提交,
              客户端防重复提交的漏洞:1.客户复制源代码,去掉此js脚本,生成自己的html页面,然后提交
                           2.重复刷新提交后的表单
                           3.用户点击浏览器回退按钮,然后再次提交

             客户端防重复提交的代码:
       1.方法1:
	     var isCommited = false;
	     function dosubmit(){
	        if(!isCommited){
	            isCommited = true;
	            return true;
	        }else{
	            return false;
	        }
	     }
     */

     //或者使"注册"按钮点击一次后不可用
	     function dosubmit1(){
	        var input = document.getElementById("submit");
	        input.disabled="disabled";
	        return true;
	     }
  </script>
  <body>
         <form action="/CookieAndSession/servlet/regist" method="post" onsubmit="return dosubmit()">
             用户名:<input type="text" name="username" value="aaa"><br/>
             <input type="hidden" name="c_token" value="${token}">
             <input id="submit" type="submit" value="注册" >
         </form>
   </body>
</html>

CreateFormServlet.java     url-pattern:  /servlet/createform

[java] view plaincopyprint?

  1. package edu.form; 
  2.  
  3. import java.io.IOException; 
  4. import java.security.MessageDigest; 
  5. import java.security.NoSuchAlgorithmException; 
  6. import java.util.Random; 
  7. import javax.servlet.ServletException; 
  8. import javax.servlet.http.HttpServlet; 
  9. import javax.servlet.http.HttpServletRequest; 
  10. import javax.servlet.http.HttpServletResponse; 
  11. import sun.misc.BASE64Encoder; 
  12.  
  13. public class CreateFormServletextends HttpServlet { 
  14.  
  15.     public void doGet(HttpServletRequest request, HttpServletResponse response) 
  16.             throws ServletException, IOException { 
  17.         //产生表单号 
  18.         String token = TokenProcessor.getInstance().generateToken(); 
  19.         request.getSession().setAttribute("token", token); 
  20.         request.getRequestDispatcher("/regist.jsp").forward(request, response); 
  21.     } 
  22.  
  23.     public void doPost(HttpServletRequest request, HttpServletResponse response) 
  24.             throws ServletException, IOException { 
  25.          doGet(request, response); 
  26.     } 
  27.      
  28. class TokenProcessor{ 
  29.     private static TokenProcessor token =new TokenProcessor(); 
  30.     private TokenProcessor(){} 
  31.     public static TokenProcessor getInstance(){ 
  32.         return token; 
  33.     } 
  34.     public String generateToken(){ 
  35.         String token = System.currentTimeMillis()+new Random().nextInt()+""; 
  36.         try { 
  37.             MessageDigest md = MessageDigest.getInstance("md5"); 
  38.             byte[] md5 = md.digest(token.getBytes()); 
  39.             //base64编码 
  40.             BASE64Encoder encoder = new BASE64Encoder(); 
  41.             return encoder.encode(md5); 
  42.         } catch (NoSuchAlgorithmException e) { 
  43.             throw new RuntimeException(e); 
  44.         } 
  45.     } 
  46.      
package edu.form;

import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import sun.misc.BASE64Encoder;

public class CreateFormServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
        //产生表单号
		String token = TokenProcessor.getInstance().generateToken();
		request.getSession().setAttribute("token", token);
		request.getRequestDispatcher("/regist.jsp").forward(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
         doGet(request, response);
	}

}
class TokenProcessor{
	private static TokenProcessor token = new TokenProcessor();
	private TokenProcessor(){}
	public static TokenProcessor getInstance(){
		return token;
	}
	public String generateToken(){
		String token = System.currentTimeMillis()+new Random().nextInt()+"";
		try {
			MessageDigest md = MessageDigest.getInstance("md5");
			byte[] md5 = md.digest(token.getBytes());
			//base64编码
			BASE64Encoder encoder = new BASE64Encoder();
			return encoder.encode(md5);
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
	}

}

RegistServlet.java     url-pattern:  /servlet/regist

[java] view plaincopyprint?

  1. package edu.form; 
  2.  
  3. import java.io.IOException; 
  4. import java.io.PrintWriter; 
  5. import javax.servlet.ServletException; 
  6. import javax.servlet.http.HttpServlet; 
  7. import javax.servlet.http.HttpServletRequest; 
  8. import javax.servlet.http.HttpServletResponse; 
  9. public class RegistServletextends HttpServlet { 
  10.  
  11.     public void doGet(HttpServletRequest request, HttpServletResponse response) 
  12.             throws ServletException, IOException { 
  13.         response.setCharacterEncoding("utf-8"); 
  14.         response.setContentType("text/html;charset=utf-8"); 
  15.         PrintWriter out = response.getWriter(); 
  16.         boolean isValid = tokenValidate(request);  
  17.         if(!isValid){ 
  18.            out.print("<script>alert('请不要重复提交,程序正在处理!');</script>"); 
  19.            return ;      
  20.         } 
  21.         out.println("正在向数据库注册用户信息!"); 
  22.          
  23.     } 
  24.  
  25.     private boolean tokenValidate(HttpServletRequest request) { 
  26.          String c_token = request.getParameter("c_token"); 
  27.          String s_token = (String) request.getSession().getAttribute("token"); 
  28.          //防止用户自定义html 
  29.          if(c_token==null) 
  30.              return false; 
  31.          if (s_token==null)  
  32.             return false; 
  33.          if (!s_token.equals(c_token))  
  34.             return false; 
  35.          request.getSession().removeAttribute("token"); 
  36.          return true; 
  37.     } 
  38.  
  39.     public void doPost(HttpServletRequest request, HttpServletResponse response) 
  40.             throws ServletException, IOException { 
  41.          doGet(request, response); 
  42.     } 
package edu.form;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RegistServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
        boolean isValid = tokenValidate(request);
        if(!isValid){
           out.print("<script>alert('请不要重复提交,程序正在处理!');</script>");
           return ;
        }
        out.println("正在向数据库注册用户信息!");

	}

	private boolean tokenValidate(HttpServletRequest request) {
         String c_token = request.getParameter("c_token");
         String s_token = (String) request.getSession().getAttribute("token");
         //防止用户自定义html
		 if(c_token==null)
			 return false;
		 if (s_token==null)
			return false;
         if (!s_token.equals(c_token))
			return false;
         request.getSession().removeAttribute("token");
	     return true;
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
         doGet(request, response);
	}
}

程序不能直接进入regist.jsp页面,只能通过http://localhost:8080/CookieAndSession/servlet/createform进入CreateFormServlet.java通过此Servlet跳转至注册页面

此时http://localhost:8080/CookieAndSession/servlet/createform页面原代码如下:

这样就可以解决以上三种可能出现的表单重复提交问题!

时间: 2024-10-30 02:21:13

JSP学习之------&gt;客户端防表单重复提交和服务器端session防表单重复提交的相关文章

《Servlet和JSP学习指南》一1.10 处理HTML表单

1.10 处理HTML表单 每个Web应用程序中几乎都会包含一个或者多个HTML表单,用来接收用户输入.你可以轻松地将一个HTML表单从Servlet发送到浏览器.当用户提交表单时,在表单元素中输入的值会被当作请求参数发送到服务器. HTML输入域(文本域.隐藏域或密码域)或者文本域的值被当作一个字符串发送到服务器.对于空白的输入域或者文本域将发送一条空白的字符串.因此,带有一个输入域名称的ServletRequest.getParameter将永远不会返回null. HTML的select元素

jsp使用ajax加载子页面,使用ajax提交子页面的表单没反应,提交按钮点击不了

问题描述 jsp使用ajax加载子页面,使用ajax提交子页面的表单没反应,提交按钮点击不了 子页面相关js代码如下: $(function(){ $("#chaxun_btn").click(function(){ var rightitem=$("#chaxun_btn").parent("right-item"); var url=$("#chaxun_btn").attr("url"); $.aja

常识之外:全表扫描为何产生大量 db file sequential read 单块读?

原创 2016-07-05 熊军 Oracle   编辑手记:在理解Oracle技术细节时,我们不仅应该读懂概念,还要能够通过测试验证细节,理解那些『功夫在诗外』的部分,例如全表扫描和单块读. 开发人员在进行新系统上线前的数据校验测试时,发现一条手工执行的 SQL 执行了超过1小时还没有返回结果.SQL 很简单: 下面是这条 SQL 的真实的执行计划: 很显然,在这个表上建 billing_nbr 和 start_date 的复合索引,这条 SQL 就能很快执行完(实际上最后也建了索引).但是这

JAVA/JSP学习系列之八(改写MySQL翻页例子)

js|mysql|翻页 一.前言 其实,改写后的JDBC Data-Source是运行在Servlet中的,通过JNDI去查找数据源.我用Orion试的,将本站<JAVA/JSP学习系列之六(MySQL翻页例子) > 简单改写了一下. 二.配置 (1)JDBC 需要将用到的JDBC驱动Copy到[ORION]/lib目录下 (2)data-source 在[ORION]/config/data-sources.xml文件中加入如下: 〈data-source class="com.e

服务器-一个关于学习的android客户端上面加入讨论功能。想部署到虚拟主机上。

问题描述 一个关于学习的android客户端上面加入讨论功能.想部署到虚拟主机上. 但是不知道后台服务器后与数据库之间怎么编写.大家有没类似的demo..现在不会ssh和php.如果有合适的方法.十分乐意愿意花时间学习.![![![![ 解决方案 你把程序写好,当然可以部署了,只是你至少要会PHP或者jsp,不然你怎么写后台?淘宝买的虚拟主机估计限制很大,这个要看你自己的需求了. 解决方案二: 用web service做后端,前端做一个界面就可以了. 解决方案三: 这个问题比较复杂,上百度查

JSP学习之Java Web中的安全控制实例详解_JSP编程

本文实例讲述了JSP学习之Java Web中的安全控制.分享给大家供大家参考.具体如下: 一.目标: ① 掌握登录之后的一般处理过程: ② 能够为每个页面添加安全控制: ③ 能够共享验证代码: ④ 使用过滤器对权限进行验证: ⑤ 能够对文件的局部内容进行验证: ⑥ 掌握安全验证码的基本实现方式: ⑦ 通过异常处理增强安全性. 二.主要内容: ① 通过修改前面的登录功能,分别对管理员和普通用户的登录进行处理: ② 为管理员才能访问的页面添加控制: ③ 共享各个页面中的控制代码,使用专门的文件,然后

js表单中选择框值的获取及表单的序列化_javascript技巧

本文特意为js表单中选择框值的获取及表单的序列化做了下总结,写成了一个对象,分享给大家,欢迎大家学习. var formUtil = { // 获取单选按钮的值,如有没有选的话返回null // elements为radio类的集合的引用 getRadioValue:function(elements) { var value = null; // null表示没有选中项 // 非IE浏览器 if(elements.value != undefined && elements.value

JSP学习之Servlet用法分析_JSP编程

本文讲述了JSP学习之Servlet用法.分享给大家供大家参考.具体分析如下: Servlet是使用JavaServlet应用程序设计接口编写的Java程序,源于请求/响应模式,可以接受来自客户端浏览器的Http请求,产生一个响应并返回客户端. Applet JSP JavaBean 和Servlet的区别和联系 Applet和Servlet中都没有main()方法,只有一些特定的方法,用于启动执行和退出,但是Servlet不提供用户界面,运行在服务器端,而Applet提供用户界面,运行在客户端

JAVA/JSP学习系列之六(MySQL翻页例子)_JSP编程

一.运行前准备 下载了mysql的jdbc驱动(一个jar文件)并加载在CLASSPATH(方法见<JAVA/JSP学习系列之一(JDK安装) >) (如果找不到,请从本站下载) 建一个MySQL数据库test 数据库中有一个表:note,字段为:name(varchar) 二.下载,安装 <%@ page contentType="text/html;charset=gb2312" %> <% java.sql.Connection sqlCon; //