Struts1防止重复提交

如果表单被重复的提交,第二次提交可能产生错误,用户不断的刷新页面,调用对应的Action,不进行控制,如注册页面不断的和数据库交互,对于服务器端负载太大。
在此利用Struts的同步令牌机制来解决问题

主要是利用了Action类中的一些方法

(1)saveToken(HttpServletRequest request)

生成一个新的令牌值并保存在session中(每次生成的都不一样)

(2)isTokenValid(HttpServletRequest request)

判断当前session和请求参数中的令牌值是否匹配,若匹配返回true,若不匹配返回false

(3)resetToken(HttpServletRequest request)

将session中的令牌值删除

服务器端:

1、在入口Action(初始化Action)中添加:

saveToken(request);

JSP页面会自动添加一个隐藏字段,类似于这样<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae" />

2、在业务的Action中添加:

if (!isTokenValid(request)) {
            errors.add(
                ActionMessages.GLOBAL_MESSAGE,
                new ActionMessage("errors.token"));
        }
        resetToken(request);

// Report any errors we have discovered back to the original form
        if (!errors.isEmpty()) {
            saveErrors(request, errors);
            saveToken(request);
            return (mapping.getInputForward());

}

客户端:

JS使提交不可用

BM示例:

在初始化的action中设置token

saveToken(request);

在业务的action中先校验token,然后充值token

        if (!isTokenValid(request)) {                addMainError(request, ErrorConstants.common, "处理中,请勿重复提交!");            }            resetToken(request);            if (getErrors(request).size() > 0) {                saveToken(request);                return actionMapping.findForward(Constants.FAIL);            }

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);
    }
}

采集

#HUABAN_WIDGETS .HUABAN-red-normal-icon-button, .HUABAN-red-large-icon-button, .HUABAN-red-small-icon-button, .HUABAN-white-normal-icon-button, .HUABAN-white-large-icon-button, .HUABAN-white-small-icon-button { background-image: url({{imgBase}}/widget_icons_ie6.png)

采集

#HUABAN_WIDGETS .HUABAN-red-normal-icon-button, .HUABAN-red-large-icon-button, .HUABAN-red-small-icon-button, .HUABAN-white-normal-icon-button, .HUABAN-white-large-icon-button, .HUABAN-white-small-icon-button { background-image: url({{imgBase}}/widget_icons_ie6.png)

时间: 2024-11-07 14:14:49

Struts1防止重复提交的相关文章

struts1与struts2的防止表单重复提交

struts1的防止表单重复提交 一.方法:利用令牌来解决页面重复提交的问题 二.步骤 2.1  Action中需要添加以下代码 public ActionForward entry(ActionMapping mapping, ActionForm form, HttpServletRequestrequest, HttpServletResponse response) throws Exception { saveToken(request); return mapping.findFor

Struts1防止表单重复提交

package org.zln.struts.action; import org.apache.struts.action.Action; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import javax.servlet.http.HttpServletRequ

JavaWeb 之 重复提交表单和验证码相关的问题!

下面我们首先来说一下表单的重复提交问题,我们知道在真实的网络环境中可能受网速带宽的原因会造成页面中表单在提交的过程中出现网络的延迟等问题,从而造成多次提交的问题!下面我们就具体来分析一下造成表单提交的一些常见问题. 下面我们就来列举一下重复提交的情况: ① .当表单提交数据到一个 Servlet 中,然后 Servlet再通过请求转发到成功页面,但是此时的地址栏中的地址是到 Servlet映射中的地址,并没有跳转到成功页面相关的JSP页面中,此时刷新页面会造成再一次提交表单. ② .当在表单页面

php防止用户重复提交表单

我们提交表单的时候,不能忽视的一个限制是防止用户重复提交表单,因为有可能用户连续点击了提交按钮或者是攻击者恶意提交数据,那么我们在提交数据后的处理如修改或添加数据到数据库时就会惹上麻烦. 效果图: 那么如何规避这中重复提交表单的现象出现呢?我们可以从很多方面入手: 首先从前端做限制.前端JavaScript在按钮被点击一次后禁用,即disabled,这个方法简单的防止了多次点击提交按钮,但是缺点是如果用户禁用了javascript脚本则失效. 第二,我们可以在提交后做redirect页面重定向,

表单重复提交问题

一.常见的重复提交问题  a>点击提交按钮两次.  b>点击刷新按钮.  c>使用浏览器后退按钮重复之前的操作,导致重复提交表单.  d>使用浏览器历史记录重复提交表单.  e>浏览器重复的HTTP请求. 二.防止表单重复提交原理 提交表单的时候提交一份随机的字符串或随机数字等等,再把这个随机的数据存到request里面,然后把表单数据提交,在后台验证的时候判断提交的这两份额外的数据是否一致,如果一致,则把其中一份删除掉,这么做的目的是防止再次提交,继续进行操作,如果不一致,

防止表单重复提交

客户端防止表单重复提交: 不足之处:用户单击”刷新”,或单击”后退”再次提交表单,将导致表单重复提交 <script type="text/javascript"> //方式一 var iscommitted = false; function dosubmit(){ if(!iscommitted){ iscommitted = true; return true; }else{ return false; } } //方式二 function dosubmit(){ d

struts2 文件的上传下载 表单的重复提交 自定义拦截器

文件上传中表单的准备 要想使用 HTML 表单上传一个或多个文件 须把 HTML 表单的 enctype 属性设置为 multipart/form-data 须把 HTML 表单的method 属性设置为 post 需添加 <input type=“file”> 字段. Struts 对文件上传的支持 在 Struts 应用程序里, FileUpload 拦截器和 Jakarta Commons FileUpload 组件可以完成文件的上传. 步骤:1. 在 Jsp 页面的文件上传表单里使用

[原创]java WEB学习笔记34:Session 案例 之 解决表单重复提交

本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 ---------------------------------

struts2 模拟令牌机制防止表单重复提交

web.xml: <?xml version="1.0" encoding="UTF-8"?><web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http: