服务器端防止表单重复提交思路:
- 由服务器端发给每个表单唯一的随机数,作为表单令牌
- 每个客户端在服务器端保存的session对象中,存储生成的表单令牌
- 客户端提交表单后进行表单令牌的验证,如果客户端与服务器中的令牌一致,那么可以提交,并且提交后移除session中的令牌
- 如果不一致,说明已经注册过了,从而终止提交动作
- 令牌发生器采用单例模式,获取数据摘要,并进行base64编码,得到统一长度的随机令牌字符串
登录servlet:
package com.franky.login;
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 javax.servlet.http.HttpSession;
import sun.misc.BASE64Encoder;
/**
* @作者 franky
* @描述 防止表单重复提交
* @日期 2015-1-12 下午04:35:47
*/
public class LoginForm extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//生成随机数,将随机数写入表单
TokenProcessor token = TokenProcessor.getInstance();
String encode = token.generateToken();
System.out.println(encode);
//随机数写入session
HttpSession session = request.getSession();
session.setAttribute("token", encode);
//随机数写入表单
request.getRequestDispatcher("/login2.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
/**
*
* @作者 franky
* @描述 随机数生成器,采用单例模式,防止重复随机数路领跑
* @日期 2015-1-12 下午04:35:33
*/
class TokenProcessor{
private static final TokenProcessor instance = new TokenProcessor();
private TokenProcessor(){
}
public static TokenProcessor getInstance(){
return instance;
}
/**生成随机令牌的方法
* @return 返回随机字符串随机令牌
*/
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();
String encode = encoder.encode(md5);
return encode;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
}
转发的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>Insert title here</title>
<script type="text/javascript">
var isSubmit = false;
function doSubmit(){
if(!isSubmit){
isSubmit = true;
return true;
}else{
window.alert("请不要重复注册");
return false;
}
}
</script>
</head>
<body>
<form action="/javawebdemos/servlet/CheckServlet" method="post" >
<input type="hidden" name="token" value="${token}"/>
username:<input type="text" name="username"><br/>
<input type="submit" value="submit" onclick="return doSubmit()" >
</form>
</body>
</html>
验证servlet:
package com.franky.login;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* @作者 franky
* @描述 防止表单重复提交,利用session中的表单令牌
* @日期 2015-1-12 下午04:43:02
*/
public class CheckServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//验证表单是否有效
boolean isValid = isTokenValid(request);
if(!isValid){
System.out.println("请不要重复注册!");
return;
}
request.getSession().removeAttribute("token");
System.out.println("注册成功");
}
/**
* 检验表单令牌是否有效
* @param request 传入request对象
* @return 返回令牌是否有效
*/
private boolean isTokenValid(HttpServletRequest request) {
String c_token = request.getParameter("token");
//验证表单令牌是否为空,为空返回false
if(c_token==null){
return false;
}
HttpSession session = request.getSession();
String s_token = (String) session.getAttribute("token");
//验证服务器端令牌是否为空,为空返回false
if(s_token==null){
return false;
}
//验证两端的令牌是否相同,不相同返回false
if(!s_token.equals(c_token)){
return false;
}
//排除以上三种情况后,返回true
return true;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}