`

js或struts的token控制重复提交操作

阅读更多
这几天由于一些原因看了一下防止重复提交的方法,现整理如下:
一:使用struts1.x的Token机制(来源于http://www.iteye.com/topic/627822帖子)
Struts的Token(令牌)机制能够很好的解决表单重复提交的问题,基本原理是:服务器端在处理到达的请求之前,会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较,看是否匹配。在处理完该请求后,且在答复发送给客户端之前,将会产生一个新的令牌,该令牌除传给客户端以外,也会将用户会话中保存的旧的令牌进行替换。这样如果用户回退到刚才的提交页面并再次提交的话,客户端传过来的令牌就和服务器端的令牌不一致,从而有效地防止了重复提交的发生。
  
  这时其实也就是两点,第一:你需要在请求中有这个令牌值,请求中的令牌值如何保存,其实就和我们平时在页面中保存一些信息是一样的,通过隐藏字段来保存,保存的形式如: 〈input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae"〉,这个value是TokenProcessor类中的generateToken()获得的,是根据当前用户的session id和当前时间的long值来计算的。第二:在客户端提交后,我们要根据判断在请求中包含的值是否和服务器的令牌一致,因为服务器每次提交都会生成新的Token,所以,如果是重复提交,客户端的Token值和服务器端的Token值就会不一致。下面就以在数据库中插入一条数据来说明如何防止重复提交。
  
  在Action中的add方法中,我们需要将Token值明确的要求保存在页面中,只需增加一条语句:saveToken(request);,如下所示:
public ActionForward add(ActionMapping mapping, ActionForm form, 
   
  HttpServletRequest request, HttpServletResponse response) 
   
  //前面的处理省略 
   
  saveToken(request); 
   
  return mapping.findForward("add"); 
   
  }
在Action的insert方法中,我们根据表单中的Token值与服务器端的Token值比较,如下所示:
  
  
public ActionForward insert(ActionMapping mapping, ActionForm form, 
   
  HttpServletRequest request, HttpServletResponse response) 
   
  if (isTokenValid(request, true)) { 
   
  // 表单不是重复提交 
   
  //这里是保存数据的代码 
   
  } else { 
   
  //表单重复提交 
   
  saveToken(request); 
   
  //其它的处理代码 
   
  } 
   
  } 
其实使用起来很简单,举个最简单、最需要使用这个的例子:
  
  一般控制重复提交主要是用在对数据库操作的控制上,比如插入、更新、删除等,由于更新、删除一般都是通过id来操作(例如:updateXXXById, removeXXXById),所以这类操作控制的意义不是很大(不排除个别现象),重复提交的控制也就主要是在插入时的控制了。
  
  先说一下,我们目前所做项目的情况:
  
  目前的项目是用Struts+Spring+Ibatis,页面用jstl,Struts复杂View层,Spring在Service层提供事务控制,Ibatis是用来代替JDBC,所有页面的访问都不是直接访问jsp,而是访问Structs的Action,再由Action来Forward到一个Jsp,所有针对数据库的操作,比如取数据或修改数据,都是在Action里面完成,所有的Action一般都继承BaseDispatchAction,这个是自己建立的类,目的是为所有的Action做一些统一的控制,在Struts层,对于一个功能,我们一般分为两个Action,一个Action里的功能是不需要调用Struts的验证功能的(常见的方法名称有add,edit,remove,view,list),另一个是需要调用Struts的验证功能的(常见的方法名称有insert,update)。
  
  就拿论坛发贴来说吧,论坛发贴首先需要跳转到一个页面,你可以填写帖子的主题和内容,填写完后,单击“提交”,贴子就发表了,所以这里经过两个步骤:
  
  1、转到一个新增的页面,在Action里我们一般称为add,例如:
public ActionForward add(ActionMapping mapping, ActionForm form, 
   
  HttpServletRequest request, HttpServletResponse response) 
   
  throws Exception { 
   
  //这一句是输出调试信息,表示代码执行到这一段了 
   
  log.debug(":: action - subject add"); 
   
  //your code here 
   
  //这里保存Token值 
   
  saveToken(request); 
   
  //跳转到add页面,在Structs-config.xml里面定义,例如,跳转到subjectAdd.jsp 
   
  return mapping.findForward("add"); 
   
  } 

2、在填写标题和内容后,选择 提交 ,会提交到insert方法,在insert方法里判断,是否重复提交了。
public ActionForward insert(ActionMapping mapping, ActionForm form, 
   
  HttpServletRequest request, HttpServletResponse response){ 
   
  if (isTokenValid(request, true)) { 
   
  // 表单不是重复提交 
   
  //这里是保存数据的代码 
   
  } else { 
   
  //表单重复提交 
   
  saveToken(request); 
   
  //其它的处理代码 
   
  } 
   
  } 
下面更详细一点(注意,下面所有的代码使用全角括号):
  
  1、你想发贴时,点击“我要发贴”链接的代码可以里这样的:
  
  〈html:link action="subject.do?method=add"〉我要发贴〈/html:link〉
  
  subject.do 和 method 这些在struct-config.xml如何定义我就不说了,点击链接后,会执行subject.do的add方法,代码如上面说的,跳转到subjectAdd.jsp页面。页面的代码大概如下:
  
〈html:form action="subjectForm.do?method=insert"〉 
   
  〈html:text property="title" /〉 
   
  〈html:textarea property="content" /〉 
   
  〈html:submit property="发表" /〉 
   
  〈html:reset property="重填" /〉 

  
  〈html:form〉如果你在add方法里加了“saveToken(request);”这一句,那在subjectAdd.jsp生成的页面上,会多一个隐藏字段,类似于这样〈input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae"〉,
  
  2、点击发表后,表单提交到subjectForm.do里的insert方法后,你在insert方法里要将表单的数据插入到数据库中,如果没有进行重复提交的控制,那么每点击一次浏览器的刷新按钮,都会在数据库中插入一条相同的记录,增加下面的代码,你就可以控制用户的重复提交了。
if (isTokenValid(request, true)) { 
   
  // 表单不是重复提交 
   
  //这里是保存数据的代码 
   
  } else { 
   
  //表单重复提交 
   
  saveToken(request); 
   
  //其它的处理代码 
   
  } 
注意,你必须在add方法里使用了saveToken(request),你才能在insert里判断,否则,你每次保存操作都是重复提交。
  
  记住一点,Struts在你每次访问Action的时候,都会产生一个令牌,保存在你的Session里面,如果你在Action里的函数里面,使用了saveToken(request);,那么这个令牌也会保存在这个Action所Forward到的jsp所生成的静态页面里。
  
  如果你在你Action的方法里使用了isTokenValid,那么Struts会将你从你的request里面去获取这个令牌值,然后和Session里的令牌值做比较,如果两者相等,就不是重复提交,如果不相等,就是重复提交了。
  
  由于我们项目的所有Action都是继承自BaseDispatchAction这个类,所以我们基本上都是在这个类里面做了表单重复提交的控制,默认是控制add方法和insert方法,如果需要控制其它的方法,就自己手动写上面这些代码,否则是不需要手写的,控制的代码如下:
public abstract class BaseDispatchAction extends BaseAction { 
   
  protected ActionForward perform(ActionMapping mapping, ActionForm form, 
   
  HttpServletRequest request, HttpServletResponse response) 
   
  throws Exception { 
   
  String parameter = mapping.getParameter(); 
   
  String name = request.getParameter(parameter); 
   
  if (null == name) { //如果没有指定 method ,则默认为 list 
   
  name = "list"; 
   
  } 
   
  if ("add".equals(name)) { 
   
  if ("add".equals(name)) { 
   
  saveToken(request); 
   
  } 
   
  } else if ("insert".equals(name)) { 
   
  if (!isTokenValid(request, true)) { 
   
  resetToken(request); 
   
  saveError(request, new ActionMessage("error.repeatSubmit")); 
   
  log.error("重复提交!"); 
   
  return mapping.findForward("error"); 
   
  } 
   
  } 
   
  return dispatchMethod2(mapping, form, request, response, name); 
   
  } 
   
  } 

注:
1、 通过重定向的方式:把地址栏的地址显示为最后的地址。 
2、 禁止客户端刷新:通过JS来控制,禁用刷新的功能、清除访问历史纪录; 
3、 Struts自带的方式(令牌):服务器端发放一次性使用的令牌方式,服务器端给客户端每次请求发一个令牌,在客户端提交之后,检查令牌,如果这个令牌是第一次使用,就ok;否则,提示重复提交。 
Action中有个几个相关方法: 
SaveToken(request):生成一个新的令牌,并保存到客户端的请求对象中。 
IsTokenValid(request,true):检查客户端的令牌是否是第一次使用,并且使该令牌失效。 
ResetToken(request):重置客户端的令牌。
二:使用客户端的js来控制重复提交
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
 <HEAD>
  <TITLE> New Document </TITLE>
  <script>
  var isSubmit = false;
  //防止重复提交的方式一:隐藏按钮
  function check(){
  document.getElementById('bt1').disabled=true;
  }
  //防止重复提交的方式二:通过全局变量来控制提交流程
  function check2(){
	  if(!isSubmit){
		alert('第一次提交');
		isSubmit = true;
	  }else{
		alert('第二次提交,不允许该操作');
	  }
  }
  </script>
 </HEAD>

 <BODY>
  <input type="button" value="submit" name="bt1" onclick="check();">
  <input type="button" value="submit2" name="bt2" onclick="check2();">
 </BODY>
</HTML>


附struts的action有这样的一个方法生成令牌:
   protected String generateToken(HttpServletRequest request) { 
       HttpSession session = request.getSession(); 
       try { 
//获取当前session的id,并转换成字符数组
           byte id[] = session.getId().getBytes(); 
//获取当前系统时间的毫秒数,并转换成字符数组
           byte now[] = 
               new Long(System.currentTimeMillis()).toString().getBytes(); 
//创建MD5的信息摘要
           MessageDigest md = MessageDigest.getInstance("MD5"); 
//使用id更新摘要
           md.update(id); 
//使用now更新摘要
           md.update(now); 
//md.digest()完成哈希计算
//
           return (toHex(md.digest())); 
       } catch (IllegalStateException e) { 
           return (null); 
       } catch (NoSuchAlgorithmException e) { 
           return (null); 
       } 
   }
分享到:
评论

相关推荐

    struts1.2之token解决重复提交

    通过在服务器端验证Token,我们可以确保每个请求的唯一性,从而避免了可能导致数据错误的重复提交操作。而`token.wrf`文件可能是保存了一些关于这个机制的示例或者日志记录,具体内容需要查看文件才能进一步分析。

    Struts2 表单 重复提交

    "防止表单重复提交 token"是Struts2提供的一种解决方案,通过在请求中加入一个唯一的token来确保请求的唯一性和一致性。 首先,我们来看如何实现这个机制。在Struts2中,我们可以使用拦截器(Interceptor)来实现...

    用struts使用Token机制来实现防重复提交

    在实际应用中,我们经常会遇到一个问题:用户可能由于网络延迟或其他原因,导致同一请求被多次提交,这被称为重复提交。为了避免这种情况,我们可以采用Token机制来实现防护。 Token机制的基本原理是在客户端(通常...

    struts2的token实现.

    在Web表单提交中,防止重复提交是一个常见的需求,而Struts2的Token机制就是为了应对这一问题而设计的。Token机制能确保用户只能提交一次表单,避免了由于网络延迟或误操作导致的重复数据录入。 ### 一、Token机制...

    Struts2防止重复提交的解决方案

    - 使用JavaScript禁用提交按钮或者通过AJAX异步提交表单,从而避免用户误操作导致的重复提交。 #### 四、Struts2相关开发技巧 除了防止重复提交外,Struts2还提供了丰富的功能支持,包括但不限于: 1. **处理结果...

    struts2中防止重复提交的方法

    在Struts2框架中,防止重复提交是一个重要的安全性考量,因为重复提交可能导致数据不一致性和资源浪费。在上述描述中,给出了三种主要方法来解决这个问题: 1) **使用 `&lt;s:token&gt;` 标签** Struts2 提供了一个称为 ...

    struts2防止表单重复提交--重定向

    总结起来,Struts2通过重定向策略可以有效地防止表单重复提交,结合其他如Token Session Strategy等方法,可以进一步提高应用的安全性和稳定性。开发者可以根据项目需求选择合适的防重提交方案,确保系统正常运行。

    不能重复提交

    ### 二、Struts框架实现表单提交及防止重复提交 #### Struts框架简介 Struts是一个基于MVC(Model-View-Controller)设计模式的开源Java Web应用程序框架。它可以帮助开发者构建可扩展的企业级应用。 #### 使用...

    防重复提交代码

    ### 防止重复提交代码知识点详解 #### 一、问题背景 ...需要注意的是,虽然这种方法可以在一定程度上防止重复提交,但在实际应用中还需要结合其他手段,如前端JavaScript控制等方式,以提供更全面的防护措施。

    J2EE框架-重复提交、重复刷新、防止后退的问题以及处理方式

    - Struts框架提供了一些机制来处理重复提交,如使用Session令牌(Token)机制。在用户提交表单前,服务器生成一个唯一的Token并存储在Session中,同时将其作为隐藏字段放在表单中。当用户提交表单时,服务器检查...

    struts数据回显、模型驱动、防止表单重复提交

    本主题将深入探讨Struts框架中的数据回显、模型驱动以及如何防止表单重复提交,这些都是在实际开发中非常关键且实用的技术点。 1. 数据回显: 数据回显是指在用户提交表单后,服务器端处理数据并返回结果页面时,将...

    struts2开发 token.rar

    通过解压并导入到Eclipse或MyEclipse,开发者可以学习和分析实际的代码实现,了解Token如何与Struts2框架结合,以及如何防止重复提交攻击。 总的来说,这个压缩包是一个关于Struts2框架中Token机制的实战示例,涵盖...

    在客户端限制表单重复提交有两种方法

    总结来说,限制表单重复提交在客户端可以通过JavaScript标志变量或禁用提交按钮实现,而服务端的Struts Token机制则提供了一种更安全、可靠的解决方案。根据项目需求和安全级别,开发者可以选择适合的方式来防止表单...

    防止表单重复提交

    本篇文章将深入探讨如何防止表单重复提交,主要关注于基于Struts2框架的解决方案。 首先,理解表单重复提交的原因。用户在点击提交按钮后,如果网络延迟或用户误操作导致页面刷新或再次点击提交,就可能发生重复...

    重复提交问题例子

    - 设置Token的有效时间,避免用户长时间未操作后重复提交。 - 结合前端JavaScript进行预防,如禁用提交按钮或显示加载状态,避免用户频繁点击。 通过以上方式,我们可以有效地防止Web应用中的重复提交问题,确保...

    解决重复提交、上传组件

    在开发Web应用时,用户可能会由于网络延迟或其他原因导致同一操作(如表单提交或文件上传)被意外多次触发,这通常称为重复提交或重复上传问题。为避免这种情况,我们需要采取措施来确保数据的一致性和完整性。本篇...

    JSP避免Form重复提交的三种方案

    在Web开发中,尤其是使用JavaServer Pages (JSP)时,Form表单的重复提交问题是一个常见的挑战。这可能导致数据不一致性和服务器资源的浪费。本文将探讨三种防止JSP表单重复提交的方法。 首先,我们可以使用...

    Java怎样防止重复提交

    - 这是一种设计模式,用于防止由于用户误操作或浏览器后退按钮导致的重复提交。每个表单提交时附带一个与Session中保存的令牌相匹配的令牌,提交后更新Session中的令牌,使得下一次提交的令牌无法匹配,从而避免...

    JSP避免Form重复提交的三种方案.docx

    在JSP开发中,防止表单(Form)重复提交是一个重要的问题,因为它可能导致数据的冗余或不一致性。以下是对避免Form重复提交的三种常见方案的详细解释: 1. JavaScript控制提交: 这种方法通过JavaScript在客户端...

    jsp 重复提交问题

    6. 使用 AJAX 无刷新提交,避免浏览器的刷新键引起系统操作重复提交。 7. 使用重定向解决页面刷新带来的数据重复提交的问题。在 Struts 的 action 中使用 redirect 属性,修改 Struts-config.xml 文件,添加 ...

Global site tag (gtag.js) - Google Analytics