Struts2框架学习之七:避免表单重复提交

前言

防止表单重复提交在web开发中是一个经常遇到的问题,一般来避免重复提交有两种方式:客户端JavaScript代码实现和服务端代码实现。这里主要介绍服务端的实现方式。在服务端实现表单重复提交的基本原理是:通过创建一个Session对象,并产生一个令牌值,将这个令牌值作为隐藏域随表单一起发送给客户端,同时在Session中保存令牌值。在用户提交表单的时候判断提交参数的令牌值与Session中的是否相等,如果相等则清除,不再使用这个令牌值,,然后执行后续的处理;如果两者不相等,表示已经提交过表单,服务端产生一个新的令牌值并保存到Session中。当用户下次访问的的时候,将新产生的领牌值发送到客户端。

Struts2的实现方式

在Struts2中通过使用拦截器来实现的,机制与前言中采用令牌的方式是一样的。可以通过两种方式实现避免重复表单(实际上就是两个不同的拦截器):token拦截器和tokenSession拦截器。由于在struts-default.xml的默认拦截器栈中并没有将这两个拦截器作为默认实现,所以需要在action中手动添加这两个拦截器。这两种方式的区别在于:使用token拦截器重复提交表单的时候,浏览器会跳转到一个错误页面,而使用更tokenSession拦截器重复提交表单的话是不会跳转的,仍然在成功之后页面。需要注意的是,使用者两个拦截器重复提交表单的时候,都只会向服务器提交一次请求,所以这种方式可以有效降低服务器的负担。

具体的例子

在使用以上拦截器进行测试的时候,需要如下步骤:
步骤一:编写login.jsp、success.jsp和error.jsp三个页面
login.jsp

...
<s:form action="tokenWait" namespace="/" method="post">
        <s:textfield label="用户名" name="user.username"></s:textfield>
        <s:password label="密码" name="user.password"></s:password>
        <!-- 这个标签不能少 -->
        <%-- <s:token></s:token> --%>
        <s:submit value="登录"></s:submit>
    </s:form>
 ...

success.jsp

...
<s:property value="user.username"/>,<%=new Date() %>
...

error.jsp

<html>
<body>
    <!-- 登录失败,请重新登录
    <a href="login.jsp">返回</a> -->
    您已经提交过表单了!
</body>
</html>

步骤二:编写action

package action;

import java.util.ArrayList;
import java.util.List;

import bean.User;

import com.opensymphony.xwork2.ActionSupport;

public class TokenAction extends ActionSupport {

    private static final long serialVersionUID = 1L;
    private User user;

    @Override
    public String execute() throws Exception {
        Thread.sleep(3000);
        List<User> users = new ArrayList<User>();
        users.add(user);
        for (User user : users) {
            System.out.println(user);
        }
        return SUCCESS;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

}

步骤三:配置struts.xml

<!-- 避免表单重复提交 -->
        <action name="token" class="action.TokenAction">
            <!-- 配置Token拦截器 -->
            <interceptor-ref name="defaultStack"></interceptor-ref>
            <interceptor-ref name="token"></interceptor-ref>
            <!-- 如果重复提交,则跳转到error.jsp -->
            <result name="invalid.token">/error.jsp</result>
            <result>/success.jsp</result>
        </action>

        <action name="tokenSession" class="action.TokenAction">
            <!-- 配置TokenSession拦截器 -->
            <interceptor-ref name="defaultStack"></interceptor-ref>
            <interceptor-ref name="tokenSession"></interceptor-ref>
            <!-- 如果重复提交,则跳转到error.jsp -->
            <result name="invalid.token">/error.jsp</result>
            <result>/success.jsp</result>
        </action>

这里需要提出的是,action中name属性为invalid.token的result是不可少的。

步骤四:发布测试
经过测试,发现使用token拦截器在重复提交表单的时候会转到error.jsp,而使用tokenSession拦截器在重复提交表单的时候不会转到error.jsp。

显示等待页面

有时候在action需要处理较长时间的时候,一般是5到10分钟,在这种情况下向用户显示一个等待页面可能会比较友好一些。在Struts2中通过使用execAndWait拦截器就可以非常轻松实现这点。

execAndWait的工作机制:

execAndWait拦截器能够让一个A执行时间超过5分钟的Action在后台运行,并向用户显示一个等待页面。之所以是5分钟是因为这样防止HTTP请求超时。当一个请求到来的时候,execAndWait拦截器会创建一个线程来执行Session,然后返回一个等待页面,这样用户就知道请求在处理中。等待页面包含了自动刷新功能,在超时之前,浏览器会向初始请求的action再次发起请求,以便知道后台action是否已经执行完毕。如果action仍然没有执行完毕,则继续显示等待页面,如果action已经执行完毕,则等待页面将发生跳转,向用户处理结束之后的页面。

execAndWait拦截器有以下几个参数:

  • threadPriority:执行线程的优先级
  • delay:指定在显示等待页面前初始的延迟加载时间,单位是毫秒
  • delaySleepInternal:指定检查后台线程是否执行完毕的时间间隔,必须和delay参数一起使用,单位是毫秒,默认是100毫秒。表示每100毫秒进行一次检查

使用execAndWait拦截器显示等待页面,首先需要编写一个等待页面:

...
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>等待页面</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="refresh" content="3;url=tokenWait.action">
</head>

<body>
    您的请求正在处理,请稍等。
    <span id="time" style="font-size:30px;color:red;font-face:隶书"></span>秒后页面将自动跳转
    <script type="text/javascript">
       var start = 3;
       var step = -1;
       function timer () {
         document.getElementById("time").innerHTML = start;
         if(start > 0){
            start = start + step;
         }
         setTimeout("timer()",1000);
       }
       window.onload = timer;
    </script>
</body>
</html>

在head 标签中需要添加自动刷新meta标签,不然是不会出发自动检查的。在这个等待页面中,表示3秒后就会跳转到成功页面。

之后是添加execAndWait拦截器的配置:

<!-- 显示自动等待页面 -->
        <action name="tokenWait" class="action.TokenAction">
            <result name="wait">/wait.jsp</result>
            <result>/success.jsp</result>
            <interceptor-ref name="defaultStack">
                <!-- 把default方法排序在外,表示不拦截!default.action -->
                <param name="excludeMethods">default</param>
            </interceptor-ref>
            <interceptor-ref name="execAndWait">
                <!-- 把default方法排序在外,表示不拦截!default.action -->
                <param name="excludeMethods">default</param>
                <!-- 等待延迟时间 -->
                <param name="delay">1000</param>
            </interceptor-ref>
        </action>

注意到TokenAction类中,使用Tread.sleep(3000),表示通过让线程休眠的方式延长action的处理时间,还有一点要注意的是struts.xml中execAndWait拦截器的delay参数的值需要小于Thread.sleep(time)的时间。这样就能保证在action处理结束之前完成显示等待页面,不然很可能会直接success.jsp页面了。

时间: 2024-11-01 02:08:58

Struts2框架学习之七:避免表单重复提交的相关文章

一脸懵逼学习Struts数据校验以及数据回显,模型驱动,防止表单重复提交的应用。

1:Struts2表单数据校验: (1)前台校验,也称之为客户端校验,主要是通过Javascript编程的方式进行数据的验证. (2)后台校验,也称之为服务器校验,这里指的是使用Struts2通过xml配置的方式进行表单数据的校验. (3)代码方式验证Action中所有的方法:代码方式验证Action中指定的方法:xml方式验证Action中所有的方法:xml方式验证Action中指定的方法: 2:代码方式验证Action中所有的方法(自己记得导jar包和我配置web.xml文件,自己脑补吧):

Struts2防止表单重复提交

最近开发中涉及到了表单重复提次的问题,通过研究做个总结.   防止表单重复提交主要用的到 标签: <s: token /> 拦截器: <interceptor-ref name="token" /> 默认的返回值: <result name="invalid.token">/input.jsp</result>   在页面加载时<s:token />产生一个GUID(Globally Unique Iden

Struts2 &amp;amp;lt;s:token&amp;amp;gt;防止表单重复提交 &amp;amp;nbsp; %{}

token是为了防止表单重复提交,token 原理大致为: 1:显示表单的那个 action 中使用 createToken() 生成一个随机的 token值,并存放在服务端(session或者cache中),并且传递一份到页面中 2:表单页面使用一个隐藏表单域获取后端传过来的 token值,该表单页面提交时会将此 token 值一同提交到后端 3:在表单页面提交到的 actioin 中使用 validateToken() 将服务端与表单隐藏域中的 token 值进行对比,如果服务端存在 tok

Struts2框架,s:form表单标签使用theme=&amp;amp;quot;ajax&amp;amp;quot;报错

问题描述 Struts2框架,s:form表单标签使用theme="ajax"报错 已经导入struts2-dojo-plugin-2.3.24.1.jar,jsp页面如下: <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//

struts2之防止表单重复提交

struts.xml配置文件 <?xml version="1.0" encoding="utf-8" ?><!doctype struts public "-//apache software foundation//dtd struts configuration 2.0//en" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts&

java Struts2防止表单重复提交代码

先要配置拦截器,拦截器用于控制重复提交内容!其实原理很简单,就是在表单内生成一个序列,判断是否为新的序列,如果是之前的序列,则证明是一个重复提交内容!  代码如下 复制代码 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC     "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN&q

JSP学习之------&amp;gt;客户端防表单重复提交和服务器端session防表单重复提交

1.什么叫表单重复提交:      所谓表单重复提交,是指用户通过多次点击提交按钮或多次刷新表单提交页面等造成用户表单重复提交的现象 2.表单重复提交有哪些情况:      (1)用户在程序提交表单的时间段里多次提交表单      (2)重复刷新提交后的表单      (3)用户点击浏览器回退按钮,然后再次提交 3.如果解决表单重复提交:     (1)方法1:客户端防表单重复提交:  一般通过js代码防止第一种情况的发生,对于第二种和第三种的情况很难避免,并且稍微有经验的用户可以通过去掉页面j

php解决和避免form表单重复提交的几种方法_php技巧

前言 为什么要避免form表单被重复提交呢?因为我们不想让我们的服务器重复处理没必要的数据,同时我们也是避免我们的数据库产生重复的数据,避免表单重复提交也是让我们的网站更安全的一种表现. 先看一下有哪些情况下回导致表单重复提交呢,知道哪些情况下可能会出现表单重复提交就可以从根源处理表单重复提交的情况了. 下面的情况就会导致表单重复提交:       点击提交按钮两次.       点击刷新按钮.       使用浏览器后退按钮重复之前的操作,导致重复提交表单.       使用浏览器历史记录重复

Sturt2做表单重复提交

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <!-- 默认