struts2防表单重复提交有两种方式。
其一是action的重定向,跳转时设置type为从一个action跳转到另一个action或者另一个页面,
使用户提交后,所停留的位置,不是当前处理数据的Action,这样用户再刷新时,就不会再次执行这个Action了,
就会避免表单重复提交的问题了。
其二就是session令牌的方式(token)
处理也很方便,只需要在所提交的表单上加一个struts2标签 <s:token>
注意在该页面需要导入 <%@taglib prefix="s" uri="/struts-tags"%>
这样,当浏览器第一次访问这个带有<s:token>标签的页面时,在服务器中,解析<s:token>标签的类(TokenTag.class),
会生成一个随机的字符串(这个字符串,查看网页的源代码可以看到),并且发送给客户端的浏览器,同时,在服务器中,
会把这个随机字符串保存到用户的session对象中。
当第一次提交表单时,在服务器中,会比较客户端和服务器中分别保存的这个随机字符串,因为是第一次提交,
所以这两个字符串相等,然后进行正常的业务处理。第一次提交后,在服务器中的session中保存的这个随机字符串,
会改变为其他的随机值,注意,这是很重要的一步!此时,地址栏停留在处理用户提交数据的Action中,
客户端中保存的随机字符串没有改变,若是刷新页面,即重复提交,服务器再进行两个字符串的比较,
会不相等,就会跳转到name为invalid.token的结果页面中,这样就会防止表单重复提交了。
贴上示例代码
struts_regist.jsp
1 <%@ taglib prefix="s" uri="/struts-tags" %> 2 <%-- 3 Created by IntelliJ IDEA. 4 User: leslie 5 Date: 17-12-2 6 Time: 上午10:46 7 To change this template use File | Settings | File Templates. 8 --%> 9 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 10 <html> 11 <head> 12 <title>注册</title> 13 </head> 14 <body> 15 <form action="${pageContext.request.contextPath}/struts_regist" method="post"> 16 <s:token /> 17 用户名:<input type="text" name="name"><br> 18 密 码:<input type="password" name="password"><br> 19 <input type="submit" value="注册"> 20 </form> 21 </body> 22 </html>
struts.xml
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 <package name="default" namespace="/" extends="struts-default"> 8 <action name="regist" class="cn.itcast.action.RegistAction"> 9 <result name="invalid.token">/token.jsp</result> 10 <interceptor-ref name="token" /> 11 <interceptor-ref name="defaultStack" /> 12 </action> 13 </package> 14 </struts>
token.jsp
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <%@taglib prefix="s" uri="/struts-tags"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>My JSP ‘index.jsp‘ starting page</title> 7 </head> 8 9 <body> 10 <s:actionerror/> 11 </body> 12 </html>
RegistAction
1 package com.emuii.action; 2 3 import com.opensymphony.xwork2.ActionSupport; 4 import org.apache.struts2.ServletActionContext; 5 6 public class RegistAction extends ActionSupport { 7 8 @Override 9 public String execute() throws Exception { 10 11 String name = ServletActionContext.getRequest().getParameter("name"); 12 String password = ServletActionContext.getRequest().getParameter("password"); 13 14 System.out.println(name+":"+password+"已注册"); 15 16 return null; 17 } 18 }
如果想要自定义错误信息,只需在action同一目录下创建一个 ----类名.properties配置文件即可
RegistAction.properties
1 struts.messages.invalid.token=\u60A8\u5DF2\u7ECF\u91CD\u590D\u63D0\u4EA4\u8868\u5355\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5
另:对于只有一个action来说,通配符跳转的方式第一种防表单提交无效的,虽然重定向之后的jsp页面不一样。
如果需要对特定的方法进行防表单提交这样:
1 <action name="someAction" class="com.examples.SomeAction"> 2 <interceptor-ref name="token"> 3 <param name="includeMethods">myMethod</param> 4 </interceptor-ref name="token"/> 5 <interceptor-ref name="basicStack"/> 6 <result name="success">good_result.ftl</result> 7 </action>
<param name="includeMethod">xx</param>表示只拦截xx方法
<param name="excludeMethod">xx</param>表示拦截xx方法之外的方法
另:WARN [org.apache.struts2.util.TokenHelper] - Could not find token name in params.出现这个问题,
也有可能是你没对指定方法进行拦截,当然情况不一定非是这种的,只是因为我的项目问题才导致这个问题的。