转载:http://www.cnblogs.com/xdp-gacl/p/3859416.html
import java.io.IOException;
import java.io.PrintWriter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
/*表单重复提交:1.原因:可能由于网络延迟导致客户点击多次或者刷新是都会导致表单重复提交
* 2.解决办法:(1)对于网络延迟的重复提交可以使用js判断,点击之后将按钮置灰
* (2)可是使用token判断,两次请求的携带的token不一致则提示不可重复提交
* */
public class ServletSession007 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
//客户端是以UTF-8编码传输数据到服务器端的,所以需要设置服务器端以UTF-8的编码进行接收,否则对于中文数据就会产生乱码
/* request.setCharacterEncoding("utf-8");
String userName=request.getParameter("username");
try {
//让当前的线程睡眠2秒钟,模拟网络延迟而导致表单重复提交的现象
Thread.sleep(2*1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
//方法二:使用session防止客户端表单重复提交
boolean b=isRepeatSubmit(request);
if(b==true){
System.out.println("请不要重复提交");
return;
}
request.getSession().removeAttribute("token"); //移除session中的token
}
//判断客户端提交的令牌和服务端生成的令牌是否一致
private boolean isRepeatSubmit(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");
//如果当前用户的Session中不存在Token(令牌),则用户是重复提交了表单
if(server_token==null){
return true;
}
//3、存储在Session中的Token(令牌)与表单提交的Token(令牌)不同,则用户是重复提交了表单
if(!client_token.equals(server_token)){
return true;
}
return false;
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
this.doGet(request, response);
}
//生成token的工具类
class TokenProccessor{
/*
*单例设计模式(保证类的对象在内存中只有一个)
*1、把类的构造函数私有
*2、自己创建一个类的对象
*3、对外提供一个公共的方法,返回类的对象*/
private TokenProccessor(){}
private final TokenProccessor instance=new TokenProccessor();
//返回类的对象
public TokenProccessor getInstance(){
return instance;
}
//生成token
public String makeToken(){
String token =(System.currentTimeMillis())+new Random().nextInt(99999999)+"";
//数据指纹
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);
}
}
}
}
jsp文件:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>form表单重复提交演示</title>
<!-- 利用js防止表单重复提交 -->
<!-- <script type="text/javascript">
var isCommitted=false; //表单是否已经提交标示
function dosubmit(){
if(isCommitted==false){
isCommitted=true; //提交表单后,将表单是否已经提交标识设置为true
return true;
}else
return false; //返回false那么表单将不提交
} -->
</script>
</head>
<body>
<%-- <form action="${pageContext.request.contextPath}/SessionF" οnsubmit="return dosubmit()" method="post">
用户名:<input type="text" name="username"/>
<input type="submit" value="提交" id="submitId"/> </form>--%>
<!-- 方法二:服务器端生成一个唯一的随机标识符token,同事在当前用户的session中保存这个token然后将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端,然后在服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。
在下列情况下,服务器程序将拒绝处理用户提交的表单请求:
1、存储Session域中的Token(令牌)与表单提交的Token(令牌)不同。
2、当前用户的Session中不存在Token(令牌)。
3、用户提交的表单数据中没有Token(令牌)。 -->
<form action="${pageContext.request.contextPath}/SessionF" method="psot">
<!-- 使用隐藏域存储生成的token -->
<input type="hidden" 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="提交">
</form>
</body>
</html>