用户在提交表单的过程中,由于网络等原因,可能重复点击提交按钮,向数据库重复写入或者读取数据,为了防止这种情况发生。
解决方式:
1.客户端防表单重复提交,在前端使用javascript限制。但是在前端并不能完全限制,比如下网页源码更改,重复刷新等。
2.服务端防止表单重复提交,在servlet中限制。
a.由程序产生表单
程序生成一个token值通过session存储
package cn.cast.session;
import java.io.IOException;
import java.io.PrintWriter;
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 FormServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//产生一个随机数(表单号)
TokenProcessor tp = TokenProcessor.GetInstance();
String token = tp.generateToken();
request.getSession().setAttribute("token", token);
request.getRequestDispatcher("/form.jsp").forward(request, response);
}
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 generateToken(){
String Token = System.currentTimeMillis() + new Random().nextInt() +"";
try {
MessageDigest md = MessageDigest.getInstance("md5");
byte[] md5 = md.digest(Token.getBytes());
//base64编码 任何数据经过base64编码 都会成为键盘上能够找到的明文字符
BASE64Encoder enoder = new BASE64Encoder();
return enoder.encode(md5);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
throw new RuntimeException(e);
}
}
}
jsp网页中通过表单存储一个token值
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'form.jsp' starting page</title>
</head>
<body>
<form action="/web2/servlet/DoFormServlet" method="post">
<input type="hidden" name="token" value="${token }">
用户名:<input type="text" name="username">
<input type="submit" value="提交">
</form>
</body>
</html>
处理表单。
package cn.cast.session;
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 DoFormServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/*String username = request.getParameter("username");
try {
Thread.sleep(1000*3);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("向数据库注册");
}*/
boolean b = isTokenValid(request);
if(!b){
System.out.println("请不要重复提交");
return;
}
request.getSession().removeAttribute("token");
System.out.println("向数据库注册");
}
//判断表单号是否有效;
private boolean isTokenValid(HttpServletRequest request){
String client_token = request.getParameter("token");
if(client_token==null){
return false;
}
String server_token = (String) request.getSession().getAttribute("token");
if(server_token ==null){
return false;
}
if(!client_token.equals(server_token)){
return false;
}
return true;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}