struts的重复提交源码分析

开始一直都对这个重复提交的问题理解的都不是很好,就知道有几个方法用了就可以达到效果,之于这几个方法,为什么能够达到这个效果就不得而知了。 

现在,对这几个方法回头整理一下,一下子就明白了。我用的是 struts 的令牌。 
举例,以论坛留言来说明: 
论坛发贴首先需要跳转到一个页面,你可以填写帖子的主题和内容,填写完后,单击“提交”,贴子就发表了,所以这里经过两个步骤: 
第一个进入发帖页面: 
/InsertToken/liuYan.do?method=add 

Java代码   收藏代码
  1. public ActionForward add(ActionMapping mapping, ActionForm form,  
  2.             HttpServletRequest request, HttpServletResponse response) {  
  3.         this.saveToken(request);  
  4.         return mapping.findForward("success");  
  5. }  

成功后,会生成新的页面: 
      这个生成的新页面中都会包含类似如下的类容: 
Hmtl代码   收藏代码
  1. <div>  
  2. <input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="70569d6c53ecfbe4748cf5b7b1a4d87e">  
  3. </div>  

这一组标签中value的值是经常变换的,每刷新一次,重新生成新页面的时候就会变化一次 
而且这组标签都会生成在form标签内部,如果没有form标签是不会生成的。 
看了源代码之后过程如下: 
首先 
Java代码   收藏代码
  1. public synchronized void saveToken(HttpServletRequest request) {  
  2.         HttpSession session = request.getSession();  
  3.         String token = generateToken(request);  
  4.         if (token != null) {  
  5.             session.setAttribute(Globals.TRANSACTION_TOKEN_KEY, token);  
  6.         }  
  7. }  
  8. public synchronized String generateToken(HttpServletRequest request) {  
  9.         HttpSession session = request.getSession();  
  10.         return generateToken(session.getId());  
  11. }  

这里在保存后 这里获得了 session 的 id 并进行了generateToken(session.getId())的操作返回一个可变的值,然后保存在 session 中。并用Globals.TRANSACTION_TOKEN_KEY指代,这个是第一步。 

然后 mapping.findForward("success"); 生成页面。这个新的页面如果有 form 标签那么就会在 FormTag.class 中进行如下的执行,以形成控制重复提交的必要标签 
Java代码   收藏代码
  1. protected String renderToken() {  
  2.         StringBuffer results = new StringBuffer();  
  3.         HttpSession session = pageContext.getSession();  
  4.         if (session != null) {  
  5.             String token =(String) session.getAttribute(Globals.TRANSACTION_TOKEN_KEY);  
  6.             if (token != null) {  
  7.                 results.append("<div><input type=\"hidden\" name=\"");  
  8.                 results.append(Constants.TOKEN_KEY);  
  9.                 results.append("\" value=\"");  
  10.                 results.append(token);  
  11.                 if (this.isXhtml()) {  
  12.                     results.append("\" />");  
  13.                 } else {  
  14.                     results.append("\">");  
  15.                 }  
  16.                 results.append("</div>");  
  17.             }  
  18.         }  
  19.         return results.toString();  
  20.  }  

在此取得 Globals.TRANSACTION_TOKEN_KEY 中之然后一起合成新页面的标签 就是上面的 
<div></div> 中的代码. 
在新页面形成之后,可以进行相应的操作,然后提交。 
/insertinfo?method=insertinfo 
Java代码   收藏代码
  1. public ActionForward insertinfo(ActionMapping mapping, ActionForm form,  
  2.         HttpServletRequest request, HttpServletResponse response) {  
  3.         if (this.isTokenValid(request)) {  
  4.         System.out.println("****执行****" + saved.equals(token));  
  5.             this.resetToken(request);  
  6.             return mapping.findForward("insertok");  
  7.         } else {  
  8.             System.out.println("++重复提交++");  
  9.             this.saveToken(request);  
  10.             return mapping.findForward("insertnotok");  
  11.         }  
  12. }  

进入这块代码 ,首先是验证是不是重复提交(if),然后通过函数resetToken从当前session范围内删除令牌属性。 
或者 已经提交(else),然后再通过函数saveToken在session中重新设置新的值。 
过程分析具体如下: 
Java代码   收藏代码
  1. public synchronized boolean isTokenValid(HttpServletRequest request,  
  2.         boolean reset) {  
  3.         // Retrieve the current session for this request  
  4.         HttpSession session = request.getSession(false);  
  5.         if (session == null) {  
  6.             return false;  
  7.         }  
  8.         // Retrieve the transaction token from this session, and  
  9.         // reset it if requested  
  10.         String saved =  
  11. (String) session.getAttribute(Globals.TRANSACTION_TOKEN_KEY);  
  12.         if (saved == null) {  
  13.             return false;  
  14.         }  
  15.         if (reset) {  
  16.             this.resetToken(request);  
  17.         }  
  18.         // Retrieve the transaction token included in this request  
  19.         String token = request.getParameter(Globals.TOKEN_KEY);  
  20.         if (token == null) {  
  21.             return false;  
  22.         }  
  23.         return saved.equals(token);  
  24.     }  

第一次得到的 saved 和 token 值是一样的。这里 Globals.TRANSACTION_TOKEN_KEY 
= "org.apache.struts.action.TOKEN" 
Globals.TOKEN_KEY 就是生成标签的name属性org.apache.struts.taglib.html.TOKEN 
通过比较第一次 相同 提交成功。 
重设和第一次一样。 
然后刷新提交后的页面,或者后退重填提交。此时生成的标签的value不变。但是在第一次的时候 resetToken 已经从当前 session 范围内删除令牌属性。所以直接进入 else。这里报告重复提交。同时再次保存 token ,此时的保存值又和value值不一样。所以重复体提交失败。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值