用户在web页面上会可能会重复提交表单,比如提交完后利用IE的Back按钮回退再提交. 即使后台程序费了九牛二虎之力气很好地捕捉了这种异常,也存在服务器不得不去响应这些"骚扰"而造成不必要的负担. Struts的Token利用令牌机制开发出很好实现的方法供开发人员使用.假设有一个页面是用来给用户填写数据,并提交给Database的页面 insert.jsp,按照普通的sturts结构, 我们会有InsertAction.
程序转向关系如下
Insert.jsp->InserAction
利用令牌机制,程序转向关系如下
取得令牌->Insert.jsp->验证令牌&清空令牌->普通InsertAction逻辑…
当取得令牌,转向Insert.jsp后,Insert.jsp中会有原始的令牌值,而这个值也被记在session中.然后提交, 提交前验证通过并清空了session中的令牌值, 所以一旦用户回退到之前的页面, 再次提交, 由于insert.jsp页面中的令牌值和session中的不匹配,所以可以很轻松地捕捉重复提交的行为. 用单独的一个PrepareInsertAction来取得令牌,验证&清空令牌放在InsertAction完成.
整个变化如下:
Struts-Configure.xml调用insert.jsp修改前
<forward name=”insert” path=”InsertAction”/>
Struts-Configure.xml调用insert.jsp修改后
<forward name=”insert” path=”PrepareInsertAction”/>
当然相应jsp上也要进行修改.
Struts-Configure.xml要配置PrepareInsertAction
<action path=”/PrepareInsertAction”
type=”{packagename}.PrepareInsertAction”>
<forward name=”passvalide” path=”/insert.jsp”/>
</action>
PrepareInsertAction.java execute()方法核心是
saveToken(request);
return mapping.findForward(….);
InsertAction.java execute()方法首先需要进行令牌验证,加入的程序行如下
…………….
ActionMessages errorsM=new ActionMessages();
ActionErrors errors = new ActionErrors();
if (!isTokenValid(request)){
errorsM.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("error.invalid.token"));
errors.add(errorsM);
saveErrors(request,errors);
saveToken(request); /*验证不通过,还是要生成新的令牌号*/
// System.out.println("prepare to return");
return mapping.findForward("pagecallinsert.jsp"); /*通常是回到调用insert.jsp的page*/
}else{
resetToken(request);
}
………..
完成这些配置和修改,就可以解决表单重复提交的问题了.
延伸点思考,组织得好的应用系统里,一旦准备转到往数据库中插入记录的jsp页面,可以在
<global-forward>中设定
<foward name="beforeinsert" path=/PrepareInsert"/>
......
这样做的好处,很显然的.