`

struts2防止表单重复提交

阅读更多
这是Struts2.1.8.1应用,关于表单重复提交的原理,参见代码注释

首先是web.xml文件

view plaincopy to clipboardprint?
01.<?xml version="1.0" encoding="UTF-8"?> 
02.<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" 
03.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
04.    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   
05.    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 
06.    <filter> 
07.        <filter-name>struts2</filter-name> 
08.        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> 
09.    </filter> 
10.    <filter-mapping> 
11.        <filter-name>struts2</filter-name> 
12.        <url-pattern>/*</url-pattern> 
13.    </filter-mapping> 
14.    <welcome-file-list> 
15.        <welcome-file>testToken.jsp</welcome-file> 
16.    </welcome-file-list> 
17.</web-app> 
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>testToken.jsp</welcome-file>
</welcome-file-list>
</web-app>

然后是用于输入用户名和密码以测试重复提交表单的testToken.jsp页面

view plaincopy to clipboardprint?
01.<%@ page language="java" pageEncoding="UTF-8"%> 
02.<%@ taglib prefix="s" uri="/struts-tags"%> 
03. 
04.<h2>测试表单重复提交</h2> 
05. 
06.<s:actionerror/> 
07. 
08.<s:form action="testToken" theme="simple"> 
09.    <s:token name="hello"/> 
10.    姓名:<s:textfield name="username"/><br/> 
11.    密码:<s:password name="password"/><br/> 
12.    <s:submit value="提交"/> 
13.</s:form> 
14. 
15.<%-- 
16.==========================================================================================  
17.【表单重复提交】  
18.只需在<s:form/>中添加<s:token/>即可  
19.然后运行项目,打开该页面右键查看源文件发现<s:token/>转化成了如下代码  
20.<input type="hidden" name="struts.token.name" value="struts.token" /> 
21.<input type="hidden" name="struts.token" value="KF98D738ZRY8TNVQWJL3GYSB8LO5U748" /> 
22.其中struts.token.name是永远固定的,第一个hidden的value值与第二个hidden的name值是关联在一起的  
23.第二个hidden的value值是一个32位的随机的被加密过的字符串,由大写A到Z加上数字0到9组成  
24.另外,如果页面中写成<s:token name="hello"/>的话,那么再运行项目,查看该页面的源代码后发现  
25.此时的第一个hidden的value值与第二个hidden的name值都已经变成了hello了  
26.==========================================================================================  
27.【通过<s:token name="hello"/>举例说明】  
28.<input type="hidden" name="struts.token.name" value="hello"/> 
29.<input type="hidden" name="hello" value="HUZU1PLOZ2111AAN5XN48I5914IUM668"/> 
30.由于<s:token/>是个标签,所以必然存在相应的标签库的代码文件  
31.当服务器端解析到页面中的<s:token/>标签的位置时,该标签对应的类文件就会自动生成两个hidden  
32.第二个hidden的value属性对应的是Struts2产生的一个GUID值(Globally Unique Identifier全局唯一标识符)  
33.这个GUID是一个类似于HUZU1PLOZ2111AAN5XN48I5914IUM668的字符串  
34.然后Struts2会将HUZU1PLOZ2111AAN5XN48I5914IUM668放到HttpSession中,然后使用hello来标识它  
35.由于<s:token name="hello"/>是放在了表单里面,所以当我们提交表单的时候  
36.就会把两个hidden全部发送到服务器上,然后名为token的表单重复提交的拦截器就会截获struts.token.name  
37.如果截获到struts.token.name的话,就读取它的value值hello  
38.接着再以hello为name来读取HUZU1PLOZ2111AAN5XN48I5914IUM668  
39.然后就把HUZU1PLOZ2111AAN5XN48I5914IUM668值与已经放在HttpSession中的值进行比较  
40.如果两个值是一样的话,它就认为该表单是第一次提交,接着程序就正常执行  
41.如果第一次提交完毕之后,再去刷新页面或者进行第二次提交的话,仍然会发送一个被加密过的字符串  
42.当第一次提交成功之后,Struts2会将session里面的加密字符串删掉,也就是说session里面就不存在这个值了  
43.既然不存在这个值,那么客户端再发过来一个加密字符串的话。二者一比较,不一样,于是就认为这是第二次提交  
44.这样的话,就可以有效的对提交请求进行拦截。这个功能是通过拦截器来实现的  
45.这里用到的token拦截器,对应org.apache.struts2.interceptor.TokenInterceptor类  
46.它继承了MethodFilterInterceptor拦截器。另外token并没有配置在defaultStack拦截器里  
47.我们可以发现Struts2采用的防止表单重复提交的方式与Struts1是一模一样的,原理上没有任何改变  
48.但在使用方式上却简化又简化,不像Struts1那样还要写代码。显然比Struts1采用的token方式简洁得多得多  
49.==========================================================================================  
50.【重复提交表单时的提示信息的国际化】  
51.表单重复提交时的报错信息是存放在ActionError中的。在前台页面对错误信息进行输出结果如下所示  
52.The form has already been processed or no token was supplied, please try again.   
53.在org.apache.struts2.struts-message.properties中查找到了该信息对应的key  
54.然后我们就可以设置国际化信息,以输出中文提示  
55.==========================================================================================  
56.【tokenSession拦截器】  
57.使用token拦截器的做法在论坛中用得比较多,不过也有一些商务网站使用的是tokenSession拦截器  
58.商务网站通常会给用户一个提交成功的提示,而不管用户刷新多少次页面,它都会一直显示给用户提交成功的提示  
59.只不过这个成功提交可能会让用户产生误解罢了。事实上也仅仅提交成功了一次,后面的刷新操作都被忽略掉了  
60.这个功能就是由tokenSession拦截器实现的,使用这个拦截器不需要我们配置任何result,它返回的永远是成功页面  
61.也就是说,使用tokenSession拦截器时,前台不用做任何改变,还是在表单里面放置一个<s:token/>标签  
62.然后在struts.xml中写成<interceptor-ref name="tokenSession"/>即可  
63.如果发现用户重复提交表单数据的话,由于tokenSession拦截器的作用,它会返回result为success的页面  
64.我们也可以在Action的方法中打印输出一句话来测试是否仅仅第一次的提交被成功执行了  
65.经过测试得知,无论用户在客户端刷新几百遍几千遍,最后只有第一次的提交操作被执行了  
66.事实上后面的刷新的提交操作都被tokenSession拦截器给拦截了  
67.因为它发现客户端的session与服务器上的session不一样,于是就把后面的请求给拦截了  
68.==========================================================================================  
69.--%> 
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<h2>测试表单重复提交</h2>

<s:actionerror/>

<s:form action="testToken" theme="simple">
<s:token name="hello"/>
姓名:<s:textfield name="username"/><br/>
密码:<s:password name="password"/><br/>
<s:submit value="提交"/>
</s:form>

<%--
==========================================================================================
【表单重复提交】
只需在<s:form/>中添加<s:token/>即可
然后运行项目,打开该页面右键查看源文件发现<s:token/>转化成了如下代码
<input type="hidden" name="struts.token.name" value="struts.token" />
<input type="hidden" name="struts.token" value="KF98D738ZRY8TNVQWJL3GYSB8LO5U748" />
其中struts.token.name是永远固定的,第一个hidden的value值与第二个hidden的name值是关联在一起的
第二个hidden的value值是一个32位的随机的被加密过的字符串,由大写A到Z加上数字0到9组成
另外,如果页面中写成<s:token name="hello"/>的话,那么再运行项目,查看该页面的源代码后发现
此时的第一个hidden的value值与第二个hidden的name值都已经变成了hello了
==========================================================================================
【通过<s:token name="hello"/>举例说明】
<input type="hidden" name="struts.token.name" value="hello"/>
<input type="hidden" name="hello" value="HUZU1PLOZ2111AAN5XN48I5914IUM668"/>
由于<s:token/>是个标签,所以必然存在相应的标签库的代码文件
当服务器端解析到页面中的<s:token/>标签的位置时,该标签对应的类文件就会自动生成两个hidden
第二个hidden的value属性对应的是Struts2产生的一个GUID值(Globally Unique Identifier全局唯一标识符)
这个GUID是一个类似于HUZU1PLOZ2111AAN5XN48I5914IUM668的字符串
然后Struts2会将HUZU1PLOZ2111AAN5XN48I5914IUM668放到HttpSession中,然后使用hello来标识它
由于<s:token name="hello"/>是放在了表单里面,所以当我们提交表单的时候
就会把两个hidden全部发送到服务器上,然后名为token的表单重复提交的拦截器就会截获struts.token.name
如果截获到struts.token.name的话,就读取它的value值hello
接着再以hello为name来读取HUZU1PLOZ2111AAN5XN48I5914IUM668
然后就把HUZU1PLOZ2111AAN5XN48I5914IUM668值与已经放在HttpSession中的值进行比较
如果两个值是一样的话,它就认为该表单是第一次提交,接着程序就正常执行
如果第一次提交完毕之后,再去刷新页面或者进行第二次提交的话,仍然会发送一个被加密过的字符串
当第一次提交成功之后,Struts2会将session里面的加密字符串删掉,也就是说session里面就不存在这个值了
既然不存在这个值,那么客户端再发过来一个加密字符串的话。二者一比较,不一样,于是就认为这是第二次提交
这样的话,就可以有效的对提交请求进行拦截。这个功能是通过拦截器来实现的
这里用到的token拦截器,对应org.apache.struts2.interceptor.TokenInterceptor类
它继承了MethodFilterInterceptor拦截器。另外token并没有配置在defaultStack拦截器里
我们可以发现Struts2采用的防止表单重复提交的方式与Struts1是一模一样的,原理上没有任何改变
但在使用方式上却简化又简化,不像Struts1那样还要写代码。显然比Struts1采用的token方式简洁得多得多
==========================================================================================
【重复提交表单时的提示信息的国际化】
表单重复提交时的报错信息是存放在ActionError中的。在前台页面对错误信息进行输出结果如下所示
The form has already been processed or no token was supplied, please try again.
在org.apache.struts2.struts-message.properties中查找到了该信息对应的key
然后我们就可以设置国际化信息,以输出中文提示
==========================================================================================
【tokenSession拦截器】
使用token拦截器的做法在论坛中用得比较多,不过也有一些商务网站使用的是tokenSession拦截器
商务网站通常会给用户一个提交成功的提示,而不管用户刷新多少次页面,它都会一直显示给用户提交成功的提示
只不过这个成功提交可能会让用户产生误解罢了。事实上也仅仅提交成功了一次,后面的刷新操作都被忽略掉了
这个功能就是由tokenSession拦截器实现的,使用这个拦截器不需要我们配置任何result,它返回的永远是成功页面
也就是说,使用tokenSession拦截器时,前台不用做任何改变,还是在表单里面放置一个<s:token/>标签
然后在struts.xml中写成<interceptor-ref name="tokenSession"/>即可
如果发现用户重复提交表单数据的话,由于tokenSession拦截器的作用,它会返回result为success的页面
我们也可以在Action的方法中打印输出一句话来测试是否仅仅第一次的提交被成功执行了
经过测试得知,无论用户在客户端刷新几百遍几千遍,最后只有第一次的提交操作被执行了
事实上后面的刷新的提交操作都被tokenSession拦截器给拦截了
因为它发现客户端的session与服务器上的session不一样,于是就把后面的请求给拦截了
==========================================================================================
--%>

然后是当用户名和密码正确时显示的result.jsp页面

view plaincopy to clipboardprint?
01.<%@ page pageEncoding="UTF-8"%> 
02.<h2>Login Success</h2> 
<%@ page pageEncoding="UTF-8"%>
<h2>Login Success</h2>

然后是Struts2的配置文件struts.xml

view plaincopy to clipboardprint?
01.<?xml version="1.0" encoding="UTF-8" ?> 
02.<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"  
03.                        "http://struts.apache.org/dtds/struts-2.1.dtd"> 
04. 
05.<struts> 
06.    <package name="struts2.1" extends="struts-default"> 
07.        <action name="testToken" class="com.jadyer.action.LoginAction" method="testToken"> 
08.            <result>/result.jsp</result> 
09.            <result name="invalid.token">/testToken.jsp</result> 
10.            <interceptor-ref name="token"/> 
11.            <interceptor-ref name="defaultStack"/> 
12.        </action> 
13.        <!-- 当Struts2发现用户进行表单重复提交时,它会寻找invalid.token --> 
14.        <!-- 并根据invalid.token找到与之对应的页面。所以记得要配置invalid.token结果 --> 
15.    </package> 
16.</struts> 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
"http://struts.apache.org/dtds/struts-2.1.dtd">

<struts>
<package name="struts2.1" extends="struts-default">
<action name="testToken" class="com.jadyer.action.LoginAction" method="testToken">
<result>/result.jsp</result>
<result name="invalid.token">/testToken.jsp</result>
<interceptor-ref name="token"/>
<interceptor-ref name="defaultStack"/>
</action>
<!-- 当Struts2发现用户进行表单重复提交时,它会寻找invalid.token -->
<!-- 并根据invalid.token找到与之对应的页面。所以记得要配置invalid.token结果 -->
</package>
</struts>

最后是处理所输入的用户名和密码的LoginAction.java

view plaincopy to clipboardprint?
01.package com.jadyer.action;  
02. 
03.import com.opensymphony.xwork2.ActionSupport;  
04. 
05.@SuppressWarnings("serial")  
06.public class LoginAction extends ActionSupport {  
07.    public String testToken() throws Exception {  
08.        return SUCCESS;  
09.    }  
10.}


本文来自CSDN博客,出处:http://blog.csdn.net/jadyer/archive/2011/02/07/6174095.aspx
分享到:
评论

相关推荐

    struts2 防止表单重复提交的例子

    Struts2框架提供了一种解决方案,即使用Token机制来防止表单的重复提交。以下是对这个主题的详细说明: 1. **表单重复提交问题**:当用户在提交表单时,由于网络延迟或用户误操作,可能会导致同一个表单被多次提交...

    【原创】Struts2防止表单重复提交.doc

    ### Struts2防止表单重复提交的技术解析 #### 一、引言 在Web应用程序开发过程中,表单重复提交是一个常见的问题,特别是在网络环境不稳定或用户误操作的情况下。这种重复提交不仅可能导致数据冗余,还可能引起事务...

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

    下面将详细解释Struts2如何通过重定向来防止表单重复提交。 首先,理解表单重复提交的场景:用户在提交表单后,由于网络延迟或其他原因,可能会无意中多次点击提交按钮。如果服务器没有处理这些重复请求,那么相同...

    Struts2防止表单重复提交示例

    在Struts2中防止表单重复提交的过程主要包括以下几个步骤: 1. **生成Token**:当用户发起表单请求时,服务器会生成一个唯一的Token并将其存储在服务器的会话(Session)中,同时将这个Token作为隐藏字段放入到HTML...

    struts2利用token防止表单重复提交(源代码)

    struts2防止表单重复提交,利用struts的拦截器tokenSession,轻轻松松解决表单重复提交的问题。 附件为源代码,后台延迟了3秒,可直接在web服务器下部署运行,输入用户名和密码后,多点几次提交按钮,然后看控制台...

    Struts2解决表单重复提交

    Struts2作为一个流行的Java Web框架,为解决表单重复提交提供了多种方法。 首先,关于表单重复提交的原因,有以下几点: 1. 服务器或网络延迟导致用户多次点击提交按钮。 2. 用户在表单提交后刷新浏览器页面。 ...

    Struts2防止重复提交解决方案

    在Struts2中,防止重复提交是一个重要的问题,因为它可能导致数据不一致性和服务器资源的浪费。本文将详细介绍如何在Struts2中解决这个问题,以及相关的技术概念。 首先,我们要理解Struts2中的拦截器(Interceptor...

    防止表单重复提交

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

    Struts2 表单 重复提交

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

    Struts2文件上传下载和表单重复提交问题

    在实际应用中,文件上传和下载以及防止表单重复提交是两个常见的需求,同时也是开发者必须掌握的重要技能。 1. **文件上传** 文件上传功能在Struts2中通过`Struts2`提供的插件来实现,主要依赖于`Apache Commons ...

    struts2防止重复提交

    Struts2提供了几种策略来防止表单的重复提交,确保请求的唯一性和事务的一致性。 一、令牌(Token)机制 Struts2的Token插件是防止重复提交的一种常见方法。这里的"Strut2Token"很可能是指这个插件的应用。它的...

    struts2令牌解决页面重复提交问题

    Struts2是一个流行的Java web框架,它...总的来说,Struts2的令牌机制是通过生成和验证令牌来防止重复提交和CSRF攻击的有效方式。开发者应当理解其工作原理,并在需要的地方正确使用,以提高应用程序的安全性和稳定性。

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

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

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

    综上所述,Struts2提供了多种手段来防止表单的重复提交,开发者可以根据具体的应用场景选择合适的方法。同时,Struts2还具备强大的功能扩展性和灵活性,能够满足复杂应用的需求。通过合理的配置和开发实践,可以有效...

    struts token机制解决表单重复提交

    Struts Token机制是一种防止表单重复提交的有效策略,尤其在处理关键操作时,如金融交易或数据修改,防止用户意外或恶意多次点击提交按钮导致的数据重复性问题。下面将详细介绍Struts Token的工作原理、实现方式及其...

    struts2中防止重复提交的方法

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

    Struts之Token解决表单那重复提交

    综上所述,Struts框架通过Token机制有效地解决了表单重复提交的问题,提供了更健壮的Web应用安全性。正确理解和应用这一机制对于Java Web开发者来说至关重要。在实际项目中,结合其他防御策略,如CSRF防护,可以...

Global site tag (gtag.js) - Google Analytics