浏览 689 次
|
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
|---|---|
| 作者 | 正文 |
|
最后更新时间:2008-07-22 关键字: strust
开始一直都对这个重复提交的问题理解的都不是很好,就知道有几个方法用了就可以达到效果,之于这几个方法,为什么能够达到这个效果就不得而知了。
现在,对这几个方法回头整理一下,一下子就明白了。我用的是struts的令牌。 举例,以论坛留言来说明: 论坛发贴首先需要跳转到一个页面,你可以填写帖子的主题和内容,填写完后,单击“提交”,贴子就发表了,所以这里经过两个步骤: 第一个进入发帖页面: 引用 /InsertToken/liuYan.do?method=add
public ActionForward add(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { this.saveToken(request); return mapping.findForward("success"); 成功后,会生成新的页面: 这个生成的新页面中都会包含类似如下的类容: 引用 <div>
<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="70569d6c53ecfbe4748cf5b7b1a4d87e"> </div> 这一组标签中value的值是经常变换的,每刷新一次,重新生成新页面的时候就会变化一次 而且这组标签都会生成在form标签内部,如果没有form标签是不会生成的。 看了源代码之后过程如下: 首先 引用 public synchronized void saveToken(HttpServletRequest request) {
HttpSession session = request.getSession(); String token = generateToken(request); if (token != null) { session.setAttribute(Globals.TRANSACTION_TOKEN_KEY, token); } } public synchronized String generateToken(HttpServletRequest request) { HttpSession session = request.getSession(); return generateToken(session.getId()); } 这里在保存后 这里获得了session的id并进行了generateToken(session.getId())的操作返回一个可变的值,然后保存在session中。并用Globals.TRANSACTION_TOKEN_KEY指代,这个是第一步。 然后mapping.findForward("success"); 生成页面。这个新的页面如果有form标签那么就会在 FormTag.class中进行如下的执行,以形成控制重复提交的必要标签 引用 protected String renderToken() {
StringBuffer results = new StringBuffer(); HttpSession session = pageContext.getSession(); if (session != null) { String token =(String) session.getAttribute(Globals.TRANSACTION_TOKEN_KEY); if (token != null) { results.append("<div><input type=\"hidden\" name=\""); results.append(Constants.TOKEN_KEY); results.append("\" value=\""); results.append(token); if (this.isXhtml()) { results.append("\" />"); } else { results.append("\">"); } results.append("</div>"); } } return results.toString(); } 在此取得Globals.TRANSACTION_TOKEN_KEY中之然后一起合成新页面的标签 就是上面的 <div></div>中的代码. 在新页面形成之后,可以进行相应的操作,然后提交。 引用 /insertinfo?method=insertinfo
public ActionForward insertinfo(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { if (this.isTokenValid(request)) { System.out.println("*********执行****" + saved.equals(token)); this.resetToken(request); return mapping.findForward("insertok"); } else { System.out.println("+++++++重复提交+++++++++"); this.saveToken(request); return mapping.findForward("insertnotok"); } } 进入这块代码 ,首先是验证是不是重复提交(if),然后通过函数resetToken从当前session范围内删除令牌属性。 或者 已经提交(else),然后再通过函数saveToken在session中重新设置新的值。 过程分析具体如下: 引用 public synchronized boolean isTokenValid(HttpServletRequest request,
boolean reset) { // Retrieve the current session for this request HttpSession session = request.getSession(false); if (session == null) { return false; } // Retrieve the transaction token from this session, and // reset it if requested String saved = (String) session.getAttribute(Globals.TRANSACTION_TOKEN_KEY); if (saved == null) { return false; } if (reset) { this.resetToken(request); } // Retrieve the transaction token included in this request String token = request.getParameter(Globals.TOKEN_KEY); if (token == null) { return false; } return saved.equals(token); } 第一次得到的 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值不一样。所以重复体提交失败。 声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
最后更新时间:2008-07-23
顶下
但是struts年岁真是有点大了 呵呵 |
|
| 返回顶楼 | |
|
最后更新时间:2008-07-24
试下同时打开两个浏览器窗口,再提交下..
这时这个就没用了... |
|
| 返回顶楼 | |
|
最后更新时间:2008-07-24
引用 wcleye 3 小时前
试下同时打开两个浏览器窗口,再提交下.. 这时这个就没用了 不是这么理解的,这相当于又开启了新的会话。重复提交是针对同一个会话! |
|
| 返回顶楼 | |
|
最后更新时间:2008-07-24
同意楼上的
|
|
| 返回顶楼 | |




