首页 > 代码库 > Struts防止表单重复提交
Struts防止表单重复提交
1.什么是表单重复提交
> 在不刷新表单页面的前提下:
>> 多次点击提交按钮
>> 已经提交成功, 按 "回退" 之后, 再点击 "提交按钮".
>> 在控制器响应页面的形式为转发情况下,若已经提交成功, 然后点击 "刷新(F5)"
> 注意:
>> 若刷新表单页面, 再提交表单不算重复提交
>> 若使用的是 redirect 的响应类型(地址栏发生变化), 已经提交成功后, 再点击 "刷新", 不是表单的重复提交
2.Struts解决表单重复提交问题
I. 在表单中添加 s:token 子标签
> 生成一个隐藏域
> 在 session 添加一个属性值
> 隐藏域的值和 session 的属性值是一致的可以提交,否则认为是重复提交.
II. 使用 Token 或 TokenSession 拦截器.
> 这两个拦截器均不在默认的拦截器栈中, 所以需要手工配置一下
> 若使用 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防止表单重复提交