背景
在提交表单的时候,通常有一种情况是新增加一条记录。当新增成功的时候,跳到添加成功的界面,如果用户点击了浏览器的回退,转到刚才的提交页面,再次点击提交。此时如果没有做处理,就会发生重复提交的问题。如果新插入一条记录不对重复提交进行处理的话,那么就会在数据库中重复插入同一记录,这样会在数据库产生冗余的重复记录。
Token 机制
Struts中的Token机制,实际上就是通过用户提交表单时,比较request中的请求参数org.apache.struts.taglib.html.TOKEN
的值与当前会话中的属org.apache.struts.action.TOKEN
的值是否相等,相等则是正常提交,不等则为重复提交。
if (isTokenValid(request, true)) {
// 未重复提交时,正确的时候应该做的事情
return mapping.findForward("success");
} else {
// 重复提交时,需要做的事情
saveToken(request);
return mapping.findForward("error");
}
处理过程
1. 新增一条记录时
在转到新增界面的action中
public ActionForward add(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
this.saveToken(request);//这个方法就是产生令牌值,struts已有的方法
return mapping.findForward("add");//返回新增页面
}
通过调用saveToken(request)
,产生一个token
值。(注:每次调用saveToken
方法产生的token
值都不同)
然后在记录新增页面中的<html:form>
内部增加一个隐含表单字段,形式如下:
<div>
<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="8b2d950f23b02c527988a14171254025">
</div>
然后再把token值8b2d950f23b02c527988a14171254025
保存到当前会话中,也就是 session.setAttribute( "org.apache.struts.action.TOKEN","8b2d950f23b02c527988a14171254025")
;
2. 提交的数据保存
public ActionForward save(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
if (this.isTokenValid(request)) {//正常提交
//其它业务操作......
this.resetToken(request);//清空当前会话中的token值
return mapping.findForward("success");//返回保存成功页面
} else {//重复提交
this.saveToken(request);//注:此方法在这里可要也可不要。
return mapping.findForward("fail");//返回重复提交提示信息页面
}
}
判断是不是重复提交关键是isTokenValid(request)
这个方法,这个方法由struts提供,如果返回结果为true
则表示正常提交,false
则为重复提交。isTokenValid(request)
这个方法实际上主要做了三件事,
- 判断当前会话是否过期,如果过期,直接返回false
HttpSession session = request.getSession(false);
if (session == null) {
return false;
}
- 然后再判断当前会话中是否存在令牌属性
org.apache.struts.action.TOKEN
,如果不存在,返回false
String saved =(String) session.getAttribute("org.apache.struts.action.TOKEN");
if (saved == null) {
return false;
}
为什么令牌属性org.apache.struts.action.TOKEN
会不存在呢,那是因为当用户正常提交后,会调用this.resetToken(request);
//清空当前会话中的token
值。也就是说resetToken(request)
方法中调用了 session.removeAttribute("org.apache.struts.action.TOKEN");
3 .从当前会话中取得token
的值与当前request
中得到的token
值比较,相同返回true
,不同返回false
String token = request.getParameter("org.apache.struts.taglib.html.TOKEN");
if (token == null) {
return false;
}
return saved.equals(token);
如果是重复刷新,那么每次request
中的令牌值都是一样的,但每次刷新当前会话中的令牌值都被重新替换了,所以会返回false
注:使用struts的表单提交Token机制时,提交的表单一定要写成<html:form></html:form>
这种形式,如果写成<form></form>
这种形式的话,尽管调用saveToken(request)
方法也不会在当前的<form></form>
里面生成隐含表单,最终的结果都是"重复提交".
网友评论