import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
/**
* 禁止表单重复提交拦截器
*
* */
public class DenyDuplicateFormSubmitInterceptor extends HandlerInterceptorAdapter {
private FormManager formManager;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
boolean flag = true;
String token = request.getParameter(Form.FORM_UNIQ_ID_FIELD_NAME);
if (token != null) {
if (formManager.hasForm(request, token)) {
formManager.destroyToken(request, token);
} else {
flag = false;
throw new Exception("表单重复提交或过期,令牌[" + token + "]");
}
}
return flag;
}
public void setFormManager(FormManager formManager) {
this.formManager = formManager;
}
}
在Spring MVC的HandlerMapping中配置该拦截器,随后在需要表单验证的Controller里做如下修改:
1、注入FormManager实例,主要是用newForm()生成一个新的Form对象
2、在返回的ModelAndView里加入该Form对象,假设名称是form
3、页面的表单中加入如下隐藏域
<input type="hidden" value="${form.token}" name="_form_uniq_id" />
<input type="hidden" value="${form.token}" name="_form_uniq_id" />
代码中我去掉了些东西,应该还是能正常工作的,反正原理就是这么回事,呵呵。
抱歉打扰一下,我想说的是:
第二.你不必加同步锁,Session每个线程各有一份
第三.Map的value目的只是为了提供date,好替除最久未使用的token,但你不必for循环每一项吧,token每次put到map是经过你的代码的对吗?那么你很轻松就可记录下put的顺序。还好这个map不太大,但是你的设计可以更好的啊。
建议:把map打散,LinkedList记录顺序,HashSet快速contain到key。
TreeMap按date排序,基本上能解决这个问题
首先,需要将继承了SimpleFormController之类的sessionForm设为true。这样,在显示一个新表单时,Spring会将command存放在session中,而在提交表单时,Spring会从session中取出此command,随后立即从session中删除存放command的attribute。如果发现在session中没有command,Spring将其断定为重复提交,转而执行handleInvalidSubmit(request, response),可覆盖此方法负责防止重复提交的任务。可以这么说,当setSessionForm(true)之后,如果没有先后经历显示表单、提交表单的过程,就会被认为是重复提交表单。而有一些情况下却必须重复提交表单,如,修改数据库的数据后,试图写入数据库时因某些异常失败,如果此时异常被当前页面捕获并依旧返回当前页面,由于command已经被Spring在后台从session中移走,因此,就被认为是无效重复提交,从而导致第二次经修改后的记录无法正确提交到数据库中。handleInvalidSubmit()必须考虑到这种情况。 ------------------------------------------------------------------------------------------------- 方法2 楼上提供的方法比较麻烦。 |