首页 > 代码库 > Struts防止表单重复提交

Struts防止表单重复提交

1.什么是表单重复提交

> 在不刷新表单页面的前提下:
        >> 多次点击提交按钮
        >> 已经提交成功, 按 "回退" 之后, 再点击 "提交按钮".
        >> 在控制器响应页面的形式为转发情况下,若已经提交成功, 然后点击 "刷新(F5)"

> 注意:
        >> 若刷新表单页面, 再提交表单不算重复提交
        >> 若使用的是 redirect 的响应类型(地址栏发生变化), 已经提交成功后, 再点击 "刷新", 不是表单的重复提交

2.Struts解决表单重复提交问题

I. 在表单中添加 s:token 子标签

    > 生成一个隐藏域
    > 在 session 添加一个属性值
    > 隐藏域的值和 session 的属性值是一致的可以提交,否则认为是重复提交.
    
II. 使用 TokenTokenSession 拦截器.

    > 这两个拦截器均不在默认的拦截器栈中, 所以需要手工配置一下
    > 若使用 Token 拦截器, 则需要配置一个 token.valid 的 result
    > 若使用 TokenSession 拦截器, 则不需要配置任何其它的 result
    
III. Token VS TokenSession

    > 都是解决表单重复提交问题的
    > 使用 token 拦截器会转到 token.valid 这个 result
    > 使用 tokenSession 拦截器则还会响应那个目标页面, 但不会执行 tokenSession 的后续拦截器. 就像什么都没发生过一样!
    
IV. 可以使用 s:actionerror 标签来显示重复提交的错误消息.
该错误消息可以在国际化资源文件中覆盖. 该消息可以在 struts-messages.properties 文件中找到

3.token解决表单重复提交问题(可以跳转到指定页面显示指定消息)

1.Action同正常的Action一样

 1 package FormRepeat;
 2 import com.opensymphony.xwork2.ActionSupport;
 3 public class FormRepeatSub extends ActionSupport {
 4     private String username;
 5     public String getUsername() {
 6         return username;
 7     }
 8     public void setUsername(String username) {
 9         this.username = username;
10     }
11     @Override
12     public String execute() throws Exception {
13         Thread.sleep(2000);
14         System.out.println(username);
15         return super.execute();
16     }
17 }

 2.JSP表单页面(表单中插入<s:token>)

 1 <%@ page language="java" contentType="text/html; charset=UTF-8"
 2     pageEncoding="UTF-8"%>
 3     <%@ taglib uri="/struts-tags" prefix="s" %>
 4 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 5 <html>
 6 <head>
 7 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 8 <title>Insert title here</title>
 9 </head>
10 <body>
11 <form action="/Struts2FileUpload/formRepeatSub.action" method="post">
12     <s:token></s:token>
13     username:<input type="text" name="username">
14     <br/>
15     <input type="submit" value="提交">
16 </form>
17 </body>
18 </html>

 

错误处理页面 TokenError.jsp

 

 1 <%@ page language="java" contentType="text/html; charset=UTF-8"
 2     pageEncoding="UTF-8"%>
 3     <%@taglib uri="/struts-tags" prefix="s" %>
 4 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 5 <html>
 6 <head>
 7 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 8 <title>Insert title here</title>
 9 </head>
10 <body>
11 <!-- 用于struts排错,看出什么类型错误 -->
12 <s:debug></s:debug>
13 <!-- 显示错误的消息 -->
14 <s:actionerror/>
15 </body>
16 </html>

 

 3.Struts的配置

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE struts PUBLIC
 3     "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
 4     "http://struts.apache.org/dtds/struts-2.3.dtd">
 5 
 6 <struts>
 7 
 8     <!-- <constant name="struts.devMode" value="http://www.mamicode.com/true"></constant> -->
 9     <package name="test2" extends="struts-default">
10         <action name="formRepeatSub" class="FormRepeat.FormRepeatSub">
11             <!-- 使用token拦截器 -->
12             <interceptor-ref name="token"></interceptor-ref>
13             <!-- 使用系统默认拦截 -->
14             <interceptor-ref name="defaultStack"></interceptor-ref>
15             <!-- 正常提交跳转的页面 -->
16             <result>/message.jsp</result>
17             <!-- 重复提交后跳转的页面 -->
18             <result name="invalid.token">/TokenError.jsp</result>
19         </action>
20     </package>
21 </struts>

 主配置文件

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE struts PUBLIC
 3     "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
 4     "http://struts.apache.org/dtds/struts-2.3.dtd">
 5 
 6 <struts>
 7 
 8     <!-- 设置热加载,即修改配置文件后不用重启 -->
 9     <constant name="struts.devMode" value="true"></constant> 
10     <!-- 配置国际化资源文件 -->
11     <constant name="struts.custom.i18n.resources" value="i18n"></constant>
12     <!-- 第二个package命名空间 -->
13     <package name="test" namespace="/" extends="struts-default">
14     <!-- 配置允许文件上传类型与大小的配置 -->
15             <interceptors>
16             <!-- 配置拦截器 -->
17             <interceptor-stack name="atguigustack">
18                 <interceptor-ref name="defaultStack">
19                     <!-- 设置单个文件上传大小 -->
20                     <param name="fileUpload.maximumSize">5000000</param>
21                     <!-- 设置文件类型,可以先上传一个,打印出contentType -->
22                     <param name="fileUpload.allowedTypes">text/html,text/xml,application/pdf</param>
23                     <!-- 设置允许上传的文件后缀名 -->
24                     <param name="fileUpload.allowedExtensions">html,dtd,xml,zip,pdf</param> 
25                 </interceptor-ref>
26             </interceptor-stack>
27         </interceptors> 
28         
29         <!-- 应用拦截器 -->
30         <default-interceptor-ref name="atguigustack"></default-interceptor-ref> 
31        <!--  <action name="fileUpload" class="fileUpload">
32             <result>/index.jsp</result>
33         </action>
34         
35          <action name="fileUpload2" class="fileUpload2">
36             <result>/index.jsp</result>
37         </action> -->
38         <!-- 单个文件上传 -->
39         <action name="fileUp" class="FileUpload.FileUpload">
40             <result>/message.jsp</result>
41         </action>
42         <!-- 上传多个文件 -->
43         <action name="filesUp" class="FileUpload.FilesUpload">
44             <result>/message.jsp</result>
45         </action>
46         <!-- 文件下载 -->
47         <action name="fileDownload" class="FileDownload.FileDownLoad">
48             <result type="stream">
49                 <!-- 其他的参数在类中设置或者使用默认 -->
50                 <param name="bufferSize">2048</param>
51             </result>
52         </action>
53     </package>
54      <include file="user.xml"></include>
55      <include file="user2.xml"></include>
56 </struts>

 

 

国际化资源文件:

技术分享

测试:

技术分享

 

总结:

    使用token的防止表单提交在form表单的开头添加一个token,添加后可以在页面查看源码生成一个随机的value值。根据session的进行匹配,每次都产生一个随机值,相同可以提交,不同就认为是重复提交。在action配置的时候添加token拦截器,需要配置一个 token.valid 的 result,结果转发到页面出错的页面。如下

技术分享

在页面出错的页面(TokenError.jsp),获取出错消息(前提是导入struts标签<%@taglib uri="/struts-tags" prefix="s" %>)

技术分享

页面出错的消息可以在国际化资源文件(i18n.properties)中设置, 该消息可以在 struts-messages.properties 文件中找到并修改

struts.messages.invalid.token=^^The form has already been processed or no token was supplied, please try again.

 

4.tokenSession解决表单重复提交问题(还会响应那个目标页面, 但不会执行 tokenSession 的后续拦截器. 就像什么都没发生过一样!)

只需要修改一下Ation配置,将拦截器设置为tokenSession ,重复提交后不会出提示,但数据只提交一次。

1      <action name="formRepeatSub" class="FormRepeat.FormRepeatSub">
2             <!-- 改为tokenSession拦截器,这个一般放在前面。出错后不会执行后续拦截器,提高性能 -->
3             <interceptor-ref name="tokenSession"></interceptor-ref>
4             <!-- 使用默认拦截器 -->
5             <interceptor-ref name="defaultStack"></interceptor-ref>
6             <!-- 跳转的页面,不会做处理,相当于只提交一次 -->
7             <result>/message.jsp</result>
8         </action> 

 

 

页面插入一个<s:token></s:token>

1 <form action="/Struts2FileUpload/formRepeatSub.action" method="post">
2     <s:token></s:token>
3     username:<input type="text" name="username">
4     <br/>
5     <input type="submit" value="提交">
6 </form>

 

 这个多次点也提交一次,也不会跳转,也不会给出提示,使用简单。只需要在表单第一个元素添加一个<s:token></s:token>,然后配置一下拦截器。

Struts防止表单重复提交