重复提交的情景:
一般控制重复提交主要是用在对数据库操作的控制上,比如插入、更新、删除等,由于更新、删除一般都是通过id来操作(例如: updateXXXById, removeXXXById),所以这类操作控制的意义不是很大(不排除个别现象),重复提交的控制也就主要是在插入时的控制了。
1.常见防重提交的方式主要有:js方式 验证码 令牌
2.这里主要介绍第三种:
其实从原理上来说,第二种跟第三种是一样的。都是通过生成随机数,存放于session,使得重复提交时获取到的数据与上一次发的数据不一致,从而不满足提交条件。
分三步:
1.初始化令牌值 AvoidSubmitFormAgain.initTokenProcessor(request, response); 生成token,并放置到session里
2.在页面上获取刚才生成的令牌值token
3.在后台对token进行校验:AvoidSubmitFormAgain.isTokenValid(request) true:可以提交 false:重复提交
4.清除当前的令牌值:AvoidSubmitFormAgain.removeTokenProecessor(request);
下面是具体代码:
令牌生成器:TokenProcessor.java
package com.sie.commons;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import sun.misc.BASE64Encoder;
public class TokenProcessor {
/*
* 1.把构造函数私有
* 2.自己创建一个
* 3.对外暴露一个方法,允许获取上面创建的对象
* */
private static final TokenProcessor instance=new TokenProcessor();
private 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编码
BASE64Encoder encoder=new BASE64Encoder();
return encoder.encode(md5);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
throw new RuntimeException(e);
}
}
}
第二个是我自己整合后一个令牌的操作工具AvoidSubmitFormAgain.java
package com.sie.commons;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 重复提交工具类
* @author lyq
*
*/
public class AvoidSubmitFormAgain {
/**
* 初始化token
* @param request
* @param response
* @param path
* @throws ServletException
* @throws IOException
* @author lyq
* @date:2014-4-25 下午4:05:27
* @version :
*/
public static void initTokenProcessor(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//产生随机数
TokenProcessor tp=TokenProcessor.getInstance();
String token=tp.generateToken();
request.getSession().setAttribute("token", token);
}
/**
* 清除token
* @param request
* @author lyq
* @date:2014-4-25 下午4:03:42
* @version :
*/
public static void removeTokenProecessor(HttpServletRequest request)
{
request.getSession().removeAttribute("token");
}
/**
* 对token的有效性进行判断
* @param request
* @return
* @author lyq
* @date:2014-4-25 下午4:07:03
* @version :
* 判断是否为重复提交
*/
@SuppressWarnings("unused")
public static 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 ActionForward user_registe(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws UserException {
UserForm userform = (UserForm)form;
//较验当前令牌与提交的是否相等,如果相同,则允许提交,否则,提交“重复提交”
if(!AvoidSubmitFormAgain.isTokenValid(request))
{
userform.user_mess = "注册请求己提交,不要再重复提交,请重新注册";
return mapping.findForward("user_registe_resubmit_front");
}
if(userservice.user_registe(userform.getUser()))
{
AvoidSubmitFormAgain.removeTokenProecessor(request);
userform.user_mess = "用户注册成功,页面跳到登录页面";
request.setAttribute("userform",userform);
return mapping.findForward("user_registe_success_front");
}
}