struts的重复提交源码分析
2010-05-04 19:45
363 查看
开始一直都对这个重复提交的问题理解的都不是很好,就知道有几个方法用了就可以达到效果,之于这几个方法,为什么能够达到这个效果就不得而知了。
现在,对这几个方法回头整理一下,一下子就明白了。我用的是 struts 的令牌。
举例,以论坛留言来说明:
论坛发贴首先需要跳转到一个页面,你可以填写帖子的主题和内容,填写完后,单击“提交”,贴子就发表了,所以这里经过两个步骤:
第一个进入发帖页面:
/InsertToken/liuYan.do?method=add
Java代码
public ActionForward add(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
this.saveToken(request);
return mapping.findForward("success");
}
成功后,会生成新的页面:
这个生成的新页面中都会包含类似如下的类容:
Hmtl代码
<div>
<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="70569d6c53ecfbe4748cf5b7b1a4d87e">
</div>
这一组标签中value的值是经常变换的,每刷新一次,重新生成新页面的时候就会变化一次
而且这组标签都会生成在form标签内部,如果没有form标签是不会生成的。
看了源代码之后过程如下:
首先
Java代码
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 中进行如下的执行,以形成控制重复提交的必要标签
Java代码
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
Java代码
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中重新设置新的值。
过程分析具体如下:
Java代码
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值不一样。所以重复体提交失败。
现在,对这几个方法回头整理一下,一下子就明白了。我用的是 struts 的令牌。
举例,以论坛留言来说明:
论坛发贴首先需要跳转到一个页面,你可以填写帖子的主题和内容,填写完后,单击“提交”,贴子就发表了,所以这里经过两个步骤:
第一个进入发帖页面:
/InsertToken/liuYan.do?method=add
Java代码
public ActionForward add(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
this.saveToken(request);
return mapping.findForward("success");
}
public ActionForward add(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { this.saveToken(request); return mapping.findForward("success"); }
成功后,会生成新的页面:
这个生成的新页面中都会包含类似如下的类容:
Hmtl代码
<div>
<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="70569d6c53ecfbe4748cf5b7b1a4d87e">
</div>
<div> <input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="70569d6c53ecfbe4748cf5b7b1a4d87e"> </div>
这一组标签中value的值是经常变换的,每刷新一次,重新生成新页面的时候就会变化一次
而且这组标签都会生成在form标签内部,如果没有form标签是不会生成的。
看了源代码之后过程如下:
首先
Java代码
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());
}
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 中进行如下的执行,以形成控制重复提交的必要标签
Java代码
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();
}
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
Java代码
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");
}
}
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中重新设置新的值。
过程分析具体如下:
Java代码
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);
}
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值不一样。所以重复体提交失败。
相关文章推荐
- struts--token防止表单重复提交(源码分析)
- struts的重复提交源码分析
- struts的重复提交源码分析
- struts--token防止表单重复提交(源码分析)
- 【struts2】struts防止表单重复提交源码分析
- 利用struts的Token机制解决重复提交问题的分析
- 防止表单的重复提交【利用Struts1的TokenProcessor源码】
- struts-spring-hibernate 框架 action 请求 ,form 表单提交 id 重复问题
- struts重复提交处理
- 使用Struts的Token机制解决表单的重复提交
- Hadoop源码分析1: 客户端提交JOB
- 源码分析 Laravel 重复执行同一个队列任务的原因
- spark core源码分析1 集群启动及任务提交过程
- JSP、Struts避免Form重复提交的几种方案
- 使用struts的同步令牌避免form的重复提交
- hadoop的job提交的源码分析
- struts控制重复提交
- MapReduce作业提交源码分析
- Spark源码分析之Job提交运行总流程概述
- php表单加入Token防止重复提交的方法分析