客户端和服务器后退操作防止表单重复提交

       表单重复提交的情况大体有两种:一种是网速卡,造成表单没有提交的假象,用户不停的点击提交。另一种则是用户的故意操作,后退或刷新页面然后重新提交。要做的就是防止这两种情况的表单重复提交。

       防止第一种,我们可以在客户端添加操作防止现象发生,有两种方式,都是通过javascript实现的。第一种方式是在javascript中设置一个变量。初值为false,点击提交按钮之后将变量改为true,并且,在变量为false时按钮有提交作用。代码如下:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>ReapteForm.html</title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <script type="text/javascript">
     var competeSign = false;
     function check() {
       if(!competeSign) {
          competeSign = true;
          return competeSign;
       }else {
          alert("不能重复提交表单");
          return false;
       }
     }
   </script>
  </head>
  
  <body style="background-color: white;">
    <form action="/learnJS/servlet/RepeateFormServlet" method="post" οnsubmit="return check()">
       留言内容:<br/>
       <textarea rows="10" cols="50"></textarea><br/>
       <input type="submit" value="提交"/>
    </form>
  </body>
</html>

javascript的第二种方式是,在按钮点击之后变为不可用,这样就不能再提交啦。代码为:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <script type="text/javascript">
    function dosubmit() {
      var input = document.getElementById("submit");
      input.disabled = 'disabled';
      return true;
    }
    </script>
  </head>
  
  <body style="background-color: white;">
      <form action="/learnJS/servlet/RepeateFormServlet" method="post" οnsubmit="return dosubmit();">
       留言内容:<br/>
       <textarea rows="10" cols="50"></textarea><br/>
       <input type="submit" id="submit" value="提交"/>
       </form>
  </body>
</html>
再有就是在服务器端通过session方式防止表单的重复提交,这样只能防止后退操作,不能防止刷新操作的。思路是,在页面的表单中有一个隐藏项,每一个表单都有一个唯一的标号,同时session中设置一个属性域,通过标号和属性域的比对操作,确定表单是否为重复提交。页面代码为:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@page import="com.you.learn.TokenProcessor"%>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>FormGenerate.jsp</title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <script type="text/javascript">
      function beformsubmit() {
       var p1 = document.getElementById("p1").value;
       if(p1==""){
 			alert("请输入内容!");    
 			return false;  
       }
       return true;
      }
    </script>
  </head>
  
  <body style="background-color: white;">
  <%
    TokenProcessor.getInstance().saveToken(request);
    String token = (String)request.getSession().getAttribute(TokenProcessor.FORM_TOKEN_KEY);
    String name = TokenProcessor.FORM_TOKEN_KEY;
    System.out.println("html:" + token);
   %>
    <form action="/learnJS/servlet/FormDealServlet" method="post" οnsubmit="return beformsubmit();">
    <input type="hidden" name="<%=name %>" value="<%=token %>">
     字段1:<input type="text" name="p1" id="p1"/><br/>
     <input type="submit" value="提交"/>
    </form>
  </body>
</html>

处理页面的servlet页面代码为:

package com.you.servlet;

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;

import com.you.learn.TokenProcessor;

public class FormDealServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		request.getParameter("TokenProcessor.FORM_TOKEN_KEY");
		TokenProcessor tokenProcessor = TokenProcessor.getInstance();
		if(!tokenProcessor.isTokenValid(request)) {
			out.println("这是重复或非法提交!");
			response.sendRedirect("/learnJS/FormGenerate.jsp");
			return;
		}
		String p1 = request.getParameter("p1");
		if(p1 == null || p1.trim().equals("")) {
			out.println("请输入内容!");
		}else {
			out.println("提交内容已被处理!");
			tokenProcessor.resetToken(request);
			
		}

	}

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

		doGet(request, response);
	}

}

还有一个Java工具类,用于生成标号:

package com.you.learn;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import sun.misc.BASE64Encoder;

public class TokenProcessor {
	private long previous;//上次生成表单标识号的时间值
	private static TokenProcessor instance = new TokenProcessor();
	public static String FORM_TOKEN_KEY = "FORM_TOKEN_KEY";
	
	private TokenProcessor() {
		
	}
	
	@SuppressWarnings("unused")
	public static TokenProcessor getInstance() {
		return instance;
	}
	/*
	 * 验证请求消息中的标识号是否有效,如果验证请求消息中的标识号和
	 * 用户session域中的标识号相同,返回结果为true,否则返回false
	 * 
	 */
	public synchronized boolean isTokenValid(HttpServletRequest request) {
		/*
		 * 为避免session对象不存在时创建session对象,
		 * 下面的语句不用request.getSession()
		 */
		HttpSession session = request.getSession(false);
		if(session == null) {
			return false;
		}
		String saved = (String)request.getSession().getAttribute("FORM_TOKEN_KEY");
		System.out.println("Token:" + saved);
		if(saved == null) {
			return false;
		}
		
		String token = request.getParameter("FORM_TOKEN_KEY");
		System.out.println("Token+token:" + token);
		if(token == null) {
			return false;
		}
		System.out.println("equals:" + saved.equals(token));
		return saved.equals(token);
	}
	
	/**
	 * 清除存储在当前用户session中的表单标识号
	 */
	public synchronized void resetToken(HttpServletRequest request) {
		HttpSession session = request.getSession(false);
		if(session == null) {
			return;
		}
		session.removeAttribute(FORM_TOKEN_KEY);
	}
	
	/**
	 * 产生表单标识号,并将保存到当前用户的session中
	 */
	public synchronized void saveToken(HttpServletRequest request) {
		HttpSession session = request.getSession();
		try {
			byte[] id = session.getId().getBytes();
			long current = System.currentTimeMillis();
			if(current == previous) {
				current++;
			} 
			previous = current;
			byte[] now = String.valueOf(current).getBytes();
			//获得随机数摘要(128个字节)
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(id);
			md.update(now);
			//base64编码
			BASE64Encoder encoder = new BASE64Encoder();
			String token = encoder.encode(md.digest());
			session.setAttribute(FORM_TOKEN_KEY, token);
			System.out.println("java:" + session.getAttribute("FORM_TOKEN_KEY"));
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		
	}
	
	
}

这样就完成了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值