今天在做注册页面的时候,碰到表单重复提交的问题。我就想到要使用模拟struts中的令牌机制来防止表单重复提交。
具体的实现过程是这样的:应为springmvc的控制器控制着页面的跳转或者重定向,所以在跳转到注册页面的时候,
创建一个token使用的是当前事件的long类型数字标识,能在一定范围内标识当前的值唯一性(当然
你也可以使用其他的标识方法比如随机数、系统的当前时间等等),并在session中存放一个set类型的集合tokens,这个集合
存放的是long类型的数据,也就是token。这个集合也有可能为空(如:当提交表单成功后,集合会将token移除掉,这个时候
刷新,则集合中为空,没有数据)。在jsp页面上则会获得集合中的token通过参数传递到后台。在后台则会计算该参数是否
包含于session中集合(即通过contains()方法判断)进而判断是否是重复提交。在第一次提交之后应该在session的token集合中
移除token。
现在我们来看看具体代码:
java中的设置token代码:
//获取当前时间作为标识
long token=new Date().getTime();
//获取token集合 如果为空则创建
Set<Long> tokens=(Set<Long>) request.getSession(false).getAttribute("tokens");
if(tokens==null){
tokens=new HashSet<Long>();
}//判断token的集合中是否存在token,如果存在则说明是之前的token需要更换新的
while(tokens.contains(token)){
token=new Date().getTime();
}//添加到token集合中
tokens.add(token);
request.getSession().setAttribute("tokens", tokens);//设置到session中
在Jsp中的代码:
<%
Set<Long> tokens=(Set<Long>)session.getAttribute("tokens"); //获取session中的token集合
long token=(long)tokens.toArray()[0]; //获取token
%>
<input type="hidden" name="token" value="<%=token%>"/>//将token作为参数放入隐藏域中传递给后台
java代码:判断token的方法
String token=request.getParameter("token"); // 获取参数传过来的token
if(token!=null){
HttpSession session=request.getSession(false); //获取session
Set<Long> sessionToken=(Set<Long>) session.getAttribute("tokens");//获取session中的token集合
long paramToken=Long.parseLong(token);
if(sessionToken.contains(paramToken)){//判断token是否在token集合是否 存在
int n=userService.add(userVO); //执行的用户逻辑
sessionToken.remove(paramToken); //执行用户逻辑之后要移除token
request.getSession().setAttribute("tokens", sessionToken); 再次设置session中的token集合
return "user/regsuccess";//返回指定的页面
}
}
request.setAttribute("errorMessage", "对不起!您的申请已经提交过了,不能重复提交!");
return "user/regFail";
刚开始的时候直接使用的是一个long类型的数字设置到session里面,然后分别通过放入session中以及通过参数的方式传递到后台,后台分别接收到之后进行比较
得到结果。但是出现了一个问题,后台代码中 session.getAttribute("token')抛出了空指针异常,这是因为在第一次提交成功提交之后,在执行完成其他代码之后,我将
session中的Attribute移除了,第二次刷新提交的时候,后台获取不到session中的token,就抛出了空指针异常。这个确实会很容易犯的错误,特别是在没有使用重定向
方式或者使用拦截器进行防止表单重复提交的操作的时候。
以此共勉,谢谢!如有问题,请多指教!