Struts2自定义拦截器实现防止重复提交
防止表单重复提交的几种方法总结

防止表单重复提交的几种方法总结
防止表单重复提交有几种方法,以下是几种常见的方法总结:
1. 使用“单个提交”和“多个提交”选项:在表单中,提供一个“单个提交”或“多个提交”的选项,选择只在单个记录中修改(“单个提交”)或在所有记录中修改(“多个提交”)。
这可以防止表单被重复提交,因为用户必须选择一次。
2. 使用“提交表单数据”按钮:在表单中添加一个“提交表单数据”按钮,这样用户点击按钮时将提交表单数据,而不是表单本身。
这可以防止表单被重复提交,因为用户不需要再次点击表单按钮来提交表单数据。
3. 使用验证码:在表单中添加一个验证码,每次用户提交表单时,验证码将过期并提示用户重新输入。
这可以防止表单被重复提交,因为用户必须等待验证码输入完成后才能继续操作。
4. 使用“唯一标识符”:在表单中添加一个唯一标识符(例如,
用户名或密码),并将该标识符与表单数据关联。
这样,每次用户提交表单时,都将唯一标识符与表单数据对应。
如果同一用户多次提交相同的表单数据,则可以使用唯一标识符来区分它们,防止表单被重复
提交。
5. 使用JavaScript实现异步提交:在表单中添加JavaScript代码,使用户可以在提交表单数据之前暂停表单的提交。
然
后,JavaScript代码可以将数据更改通知服务器,然后将表单重新设置为“可重复提交”。
这可以防止表单被重复提交,因为用户可以在提交表单数据之前暂停表单的提交。
struts2

—高级软件人才实作培训专家! 高级软件人才实作培训专家!
搭建Struts2开发环境
搭建Struts2环境时,我们一般需要做以下几个步骤的工作: 1》找到开发Struts2应用需要使用到的jar文件. 2》编写Struts2的配置文件 3》在web.xml中加入Struts2 MVC框架启动配置
北京传智播客教育
北京传智播客教育
—高级软件人才实作培训专家! 高级软件人才实作培训专家!
搭建Struts2开发环境--Struts2在web中的启动配置
在struts1.x中, struts框架是通过Servlet启动的.在struts2中, struts框架是通过Filter启动的.他在web.xml中的配置如下:
—高级软件人才实作培训专家! 高级软件人才实作培训专家!
Struts2
讲师: 讲师:黎活明
北京传智播客教育
—高级软件人才实作培训专家! 高级软件人才实作培训专家!
Struts2
Struts2是在WebWork2基础发展而来的.和struts1一样, Struts2也属于MVC框架. 不过有一点大家需要注意的是:尽管Struts2和struts1在名字上的差别不是很大,但 Struts2和struts1在代码编写风格上几乎是不一样的.那么既然有了struts1,为何还要 推出struts2.主要是因为struts2有以下优点:
北京传智播客教育
—高级软件人才实作培训专家! 高级软件人才实作培训专家!
第一个Struts2应用--HelloWorld
在默认的配置文件struts.xml 中加入如下配置:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "/dtds/struts-2.0.dtd"> <struts> <package name="itcast" namespace="/test" extends="struts-default"> <action name="helloworld" class="cn.itcast.action.HelloWorldAction" method="execute" > <result name="success">/WEB-INF/page/hello.jsp</result> </action> </package> </struts>
8种解决重复提交的方案你知道哪几种

8种解决重复提交的方案你知道哪几种解决重复提交是一个常见的问题,在数据提交和处理的过程中可能出现重复提交的情况,这会导致数据的异常或者不一致。
为了避免这种问题的发生,我们可以采取以下八种解决方案。
这些方案包括使用前端验证、后端验证、token机制、订单号生成、防止表单重复提交、避免重复提交下载、限制提交频率和使用消息队列。
1. 前端验证前端验证是指在用户提交表单之前,使用JavaScript等前端技术对数据进行验证。
这样可以在客户端就避免一些简单的错误,比如是否填写了必填项、手机号格式是否正确等。
通过前端验证可以减轻服务器的压力,并且提升用户体验。
2. 后端验证除了前端验证,后端也需要对提交过来的数据进行验证。
前端验证只是对一些基本的数据格式进行验证,而后端验证可以对更复杂的数据逻辑进行验证,比如判断某个用户是否已经存在,或者某个商品是否可以购买等。
3. Token机制Token机制可以用来验证用户的身份和请求的合法性。
每次用户提交请求时,服务端会生成一个Token并返回给客户端,在下一次请求中,客户端需要带上该Token。
服务端可以验证该Token的合法性,从而防止重复提交的问题。
4. 订单号生成在某些需要用户支付或者生成唯一标识的场景下,可以使用订单号来避免重复提交。
订单号可以使用时间戳、用户ID等信息生成,并且在生成订单时需要保证其唯一性,从而避免重复提交。
5. 防止表单重复提交有些场景下,用户可能会重复提交表单,比如快速点击提交按钮多次。
为了避免这种情况,可以通过前端禁用提交按钮或者设置提交标志位来防止表单的重复提交。
6. 避免重复提交下载在下载文件的过程中,可能会出现用户多次点击下载按钮的情况,从而导致重复下载同一个文件。
为了解决这个问题,可以在下载开始时生成一个唯一的下载标识,服务端保存该标识并检查是否已经下载过该文件,从而避免重复下载。
7. 限制提交频率为了防止频繁的提交请求,可以通过限制提交的频率来解决。
.net core validateantiforgerytoken 重复提交

.net core validateantiforgerytoken 重复提交在.net中,可以使用 AntiForgeryToken来防止重复提交。
AntiForgeryToken是 MVC框架提供的功能,用于防止跨站请求伪造(CSRF)攻击和重复提交。
要使用 AntiForgeryToken,可以按照以下步骤进行操作:
1. 启用 session:在 services 方法中使用
Configure<CookiePolicyOptions>方法启用 session。
2. 生成 AntiForgeryToken:在控制器的相应方法中,使用 ValidateAntiForgeryToken 注解来生成 AntiForgeryToken。
3. 验证 AntiForgeryToken:在控制器的相应方法中,验证请求中的 AntiForgeryToken 是否与存储在 session 中的 AntiForgeryToken 匹配。
请注意,具体的实现方式可能会因项目需求而有所不同,你可以根据实际情况进行调整。
如果你需要进一步的帮助,请提供更多的上下文或代码示例,以便我能够更好地理解你的问题并提供更具体的解决方案。
8.传智struts-模型驱动、防重复提交、数据回显

情景: 有一个用来处理客户的 CustomerAction 类, 该动作类实现 了 ModelDriven 接口. 当用户触发CustomerAction 动作时, ModelDriven 拦截器将调用 相关CustomerAction 对象的 getModel() 方法, 并把返回的模型 (Customer实例)压入到 ValueStack 栈. 接下来 Parameters 拦截 器将把表单字段映射到 ValueStack 栈的栈顶对象的各个属性中 . 因为此时 ValueStack 栈的栈顶元素是刚被压入的模型 (Product)对象, 所以该模型将被填充. 如果某个字段在模型里没有 匹配的属性, Param 拦截器将尝试 ValueStack 栈中的下一个对 象. 一个模型类必须有一个不带任何参数的构造器.
北京传智播客教育
—高级软件人才实作培训专家!
3. 数据回显:
// 模拟: 从service中查询获取一个user对象,显示数据到编辑页面 public String edit() throws Excபைடு நூலகம்ption { User db_user = new User("Tom",29); // 数据回显技术, 方式1: // user.setName(db_user.getName()); // user.setAge(db_user.getAge()); // 这样? //user = db_user;
}
—高级软件人才实作培训专家!
<s:token />标签防止重复提交
<s:token />标签防止重复提交,用法如下: 第一步:在表单中加入<s:token /> <s:form action="helloworld_other" method="post" namespace="/test"> <s:textfield name=""/><s:token/><s:submit/> </s:form> 第二步: <action name="helloworld_*" class="cn.itcast.action.HelloWorldAction" method="{1}"> <interceptor-ref name="defaultStack"/> <!-- 增加令牌拦截器 --> <interceptor-ref name="token"> <!-- 哪些方法被令牌拦截器拦截 --> <param name=“includeMethods">save</param> </interceptor-ref> <!-- 当表单重复提交转向的页面 --> <result name="invalid.token">/WEB-INF/page/message.jsp</result> </action> 以上配置加入了“token”拦截器和“invalid.token”结果,因为“token”拦截器在会话的token与 请求的token不一致时,将会直接返回“invalid.token”结果。
Struts2教程2:处理一个form多个submit

在很多Web应用中,为了完成不同的工作,一个HTML form标签中可能有两个或多个submit 按钮,如下面的代码所示:<!--[if !supportLineBreakNewLine]--><ht ml action="" method="post"><input type="submit" value="保存"/><input type="submit" value="打印"/></ht ml>由于在<form>中的多个提交按钮都向一个action提交,使用Struts2 Action的execute 方法就无法判断用户点击了哪一个提交按钮。
如果大家使用过Struts1.x就会知道在Struts1.2.9之前的版本需要使用一个LookupDispatchAction动作来处理含有多个submit 的form。
但使用LookupDispatchAction动作需要访问属性文件,还需要映射,比较麻烦。
从Struts1.2.9开始,加入了一个Event DispatchAction动作。
这个类可以通过java反射来调用通过request参数指定的动作(实际上只是判断某个请求参数是不存在,如果存在,就调用在action类中和这个参数同名的方法)。
使用EventDispatchAction必须将submit的name 属性指定不同的值以区分每个submit。
而在Struts2中将更容易实现这个功能。
当然,我们也可以模拟Event DispatchAction的方法通过request获得和处理参数信息。
但这样比较麻烦。
在Struts2中提供了另外一种方法,使得无需要配置可以在同一个action类中执行不同的方法(默认执行的是execute方法)。
strusts2课堂总结

一、1、struts2struts2是mvc设计思想的一个实现,可以将项目低耦合,提高扩展性2、struts2和struts1的区别struts2不是struts1的升级,而是继承的下xwork的血统,它吸收了struts1和webwork 的优势。
struts2的action是原型,安全的,struts2的action是单例,非安全3、步骤:1、导入包2、在web.xml文件中,加入struts2的核心拦截器3、在src下放入struts2的xml struts.xml4、urlhttp://localhost:8080/Struts2_01_HelloWorld/demo/hello.action二、1、默认值2、转发和重定向的区别转发:url显示的依然是上一个的url,共享上一次的请求重定向:url显示的是下一个的url,不共享3、urlhttp://localhost:8080/Struts2_02_Default/demo/hello.action4、路径http://localhost:8080/Struts2_02_Default/demo/a/b/c/hello.action1、原路径找不到,http://localhost:8080/Struts2_02_Default/demo/a/b/hello.action2、如果1找不到,http://localhost:8080/Struts2_02_Default/demo/a/hello.action3、如果2找不到,http://localhost:8080/Struts2_02_Default/demo/hello.action3、如果3找不到,http://localhost:8080/Struts2_02_Default/hello.action三、11、自定义action继承ActionSupport2、功能方法必须满足格式public String 名字()throws Exception{....};3、urlhttp://localhost:8080/Struts2_03_Action/demo/a.action四、1、如何给action传入参数注意:赋值的必须有封装的set方法,通过el表达式获取的时候,必须有封装的get 方法1、直接给单个参数赋值,在action里建立一个变量,名字与参数的名字一样2、为对象的某个属性赋值,在action里建立一个对象,将参数改为对象名.属性的格式五、1、转发和重定向的区别转发到下一次的时候,url依然是上一次的url,共享上一次的request重定向到下一次的时候,url是下一次的url,不共享上一次的request2、struts2的result的type转发:共享上一次action重定向:不共享上一次action1、转发到下一个jsp,html:dispatcher2、重定向到下一个jsp,html:redirect3、转发到下一个action:chain转到同一个包下的action转发到不同包下的action4、重定向到下一个action:redirectAction转到同一个包下的action转发到不同包下的action六、1、为了分模块开发,可以设置多个xmL文件。
Java开发框架中的重复提交处理技巧

Java开发框架中的重复提交处理技巧随着互联网和移动互联网的快速发展,越来越多的企业开始使用Java开发框架来构建自己的应用程序。
Java开发框架具有高效性和可重用性等优点,让软件开发人员在开发过程中节省了很多时间和精力。
但是,在Java开发框架中存在一些常见的问题,其中最突出的一个问题就是重复提交。
重复提交是指用户在不知情的情况下或者网络延迟等情况下,多次向服务器提交了相同的数据请求。
如果我们不加以处理,这些重复的请求可能会引发很多问题,例如重复加入购物车、重复交易等。
为了处理这个问题,Java开发框架中采取了一些技巧,本文将对这些技巧进行详细介绍。
1. Token机制Token机制是一种常用的防止重复提交的技术。
当客户端第一次请求服务器时,服务器会生成一个Token并返还给客户端,在客户端请求数据时将该Token携带一同提交到服务器,服务器负责验证Token的唯一性和有效性。
在Java开发框架中,Token机制最常用于Web应用程序中,可以通过在http请求中添加Token参数来确保数据的唯一性。
在Spring框架中,我们可以使用Spring的@Token注解来声明Token机制。
2. 多次提交间隔时间限制许多Java开发框架也采用了限制多次提交的时间间隔的方法。
这种策略可以在服务器端生成一个唯一的标识符,并将其存储在Session中,然后在相同标识符的请求之间加入一个间隔时间,如果两次请求之间的时间间隔小于指定的时间,则视为重复提交。
在Spring框架中,我们可以使用Intercepter拦截器来实现此技术。
通过在请求前检查Session中的标识符,然后在处理之前设置新的标识符,这样可以保证每个请求都是唯一的。
3. 数据库表锁数据库表锁是另一种有效的防止重复提交的技术。
在此策略中,当一个请求到达服务器时,它会创建并锁定一个表,防止其他请求进一步更新或访问此表。
如果重复请求同一操作,则由于表已被锁定,导致操作无效。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
由于struts2标签的性能不好,项目组决定不使用,但是如果用struts2自带的拦截器防止重复提交又必须struts标签,所以只好自定拦器实现,具体步骤如下:新建拦截器类:public class TokenAtionInterceptor extends AbstractInterceptor {public String intercept(ActionInvocation invocation) throws Exception {Map<String, Object> session =invocation.getInvocationContext().getSession();HttpServletRequest request = ServletActionContext.getRequest();String strGUID = RandomGUIDUtil.newGuid();//生成令牌String strRequestToken = (String)session.get("request_token");//取出会话中的令牌String strToken = request.getParameter("token"); //页面中的令牌if(strRequestToken != null&& !strRequestToken.equals(strToken)){ //重复提交,重置令牌session.put("request_token", strGUID);request.setAttribute("token", strGUID);return"invalidToken";}session.put("request_token", strGUID);request.setAttribute("token", strGUID);return invocation.invoke(); //否则正常运行}}建一个生成令牌的工具类:public class RandomGUIDUtil extends Object {/**日志管理类对象*/private Logger logger= Logger.getLogger(this.getClass().getName());public String valueBeforeMD5 = "";public String valueAfterMD5 = "";private static Random myRand;private static SecureRandom mySecureRand;private static String s_id;/** 静态块初始化*/static {mySecureRand = new SecureRandom();long secureInitializer = mySecureRand.nextLong();myRand = new Random(secureInitializer);try {s_id = InetAddress.getLocalHost().toString();} catch (UnknownHostException e) {System.out.println("构造带指定详细消息和嵌入异常!");}}public RandomGUIDUtil() throws Exception {getRandomGUID(false);}public RandomGUIDUtil(boolean secure) throws Exception { getRandomGUID(secure);}/** 随机生成GUID*/private void getRandomGUID(boolean secure) throws Exception { MessageDigest md5 = null;StringBuffer sbValueBeforeMD5 = new StringBuffer();try {md5 = MessageDigest.getInstance("MD5");} catch (NoSuchAlgorithmException e) {logger.error("初始化MD5出错!");throw new NoSuchAlgorithmException("初始化MD5出错!");}try {long time = System.currentTimeMillis();long rand = 0;if (secure) {rand = mySecureRand.nextLong();} else {rand = myRand.nextLong();}sbValueBeforeMD5.append(s_id);sbValueBeforeMD5.append(":");sbValueBeforeMD5.append(Long.toString(time));sbValueBeforeMD5.append(":");sbValueBeforeMD5.append(Long.toString(rand));valueBeforeMD5 = sbValueBeforeMD5.toString();md5.update(valueBeforeMD5.getBytes());byte[] array = md5.digest();StringBuffer sb = new StringBuffer();for (int j = 0; j < array.length; ++j) {int b = array[j] & 0xFF;if (b < 0x10) sb.append('0');sb.append(Integer.toHexString(b));}valueAfterMD5 = sb.toString();} catch (Exception e) {logger.error("获得MD5加密码出错!");throw new Exception("初始化MD5出错!");}}/***生成一个GUID串*@return GUID*@throws Exception*/public static String newGuid() throws Exception{ RandomGUIDUtil rdmGUID = new RandomGUIDUtil();return rdmGUID.toString();}/** 生成以主机串号、显卡串号、主板号,以保证唯一性的32位编码*/public String toString() {String raw = valueAfterMD5.toUpperCase();StringBuffer sb = new StringBuffer();sb.append(raw.substring(0, 8));sb.append(raw.substring(8, 12));sb.append(raw.substring(12, 16));sb.append(raw.substring(16, 20));sb.append(raw.substring(20));return sb.toString();}}在struts配置文件中对应的包下定义拦截器,注意顺序,package里元素必须按照一定的顺序排列。
这个顺序就是result-typesinterceptorsdefault-interceptor-refdefault-action-refdefault-class-refglobal-resultsglobal-exception-mappingsaction*(就是所有的action放到最后)<action>配置中加上名为” invalidToken”的result,就是拦截器中,重复提交跳转的路径如:<package name="template" extends="struts-default" namespace="/"> <interceptors><interceptor name="invocationToken"class="com.tydic.ppm.util.TokenAtionInterceptor"></interceptor> </interceptors><global-results><result name="error">/error.jsp</result><result name="openError">/openError.jsp</result> </global-results><action name="addTemplate" class="templateConfigAction"> <interceptor-ref name="defaultStack"></interceptor-ref><interceptor-ref name="invocationToken"></interceptor-ref><result name="input">/content/templateManage/configTemplate/templateBaseInfo.jsp </result><result name="success">/content/templateManage/configTemplate/templateBaseInfo.jsp </result><result name="invalidToken">/content/templateManage/configTemplate/templateBaseInfo.jsp </result></action></package>最后在页面上加一个隐藏域,用来保存页面令牌的,如:<input type="hidden" name="token" value="${token }"/><!-- 防止重复提交所用 -->经过上面的步骤就可以实现防止重复提交了,要注意拦截器在struts配置文件中定义的位置。