表单重复提交的概述
若刷新表单页面,再提交表单不算重复提交。
若是重定向,已经提交成功后再刷新不算重复提交。
以下几种情况算是表单重复提交
多次点击提交按钮
已经提交成功,按"回退"之后,再点击"提交按钮"
在控制器响应页面的形式为转发情况下,若已经提交成功,然后点击"刷新"重复提交的缺点
加重了服务器的负担
可能导致错误操作
Struts2解决表单重复提交
在
<s:form >
标签中添加<s:token>
子标签
生成一个隐藏域
在session
添加一个属性值
隐藏域的值和session
的属性值是一致的使用
Token
或TokenSession
拦截器
这两个拦截器均不在默认的拦截器栈中,所以需要手工配置一下
若使用Token
拦截器,则需要配置一个token.valid
的result
若使用TokenSession
拦截器,则不需要配置任何其它的result
Token
与TokenSession
区别
都是解决表单重复提交问题,但是使用token
拦截器会转到token.valid
这个result
,使用tokenSession
拦截器则还会响应那个目标页面,但不会执行tokenSession
的后续拦截器。可以使用
<s:actionerror>
标签来显示重复提交的错误消息,该错误消息可以在国际化资源文件中覆盖,该字段名为struts.messages.invalid.token
,可以在struts-messages.properties
文件中找到。
使用token拦截器的配置示例:
<action name="testToken" class="com.cerr.struts2.TokenAction">
<interceptor-ref name="token"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
<result>/success.jsp</result>
<result name="invalid.token">/token-error.jsp</result>
</action>
在token-error.jsp中打印错误消息:
<%@ taglib prefix="s" uri="/struts-tags" %>
<%--
Created by IntelliJ IDEA.
User: 白菜
Date: 2019/8/7
Time: 21:25
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<s:actionerror></s:actionerror>
</body>
</html>
Struts2拦截器概述
拦截器在访问某个Action方法之前或之后实施拦截
拦截器是可拔插的,拦截器是AOP的一种实现。
拦截器栈将拦截器按一定的顺序联结成一条链,在访问被拦截的方法时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被依次调用。
-
拦截器的调用流程
Interceptor接口
Struts会依次调用为某个Action而注册的每一个拦截器的
intercept
方法每次调用
intercept
方法时,Struts会传递一个ActionInvocation
接口的实例ActionInvocation
代表一个给定ActionAction
的执行状态,拦截器可以从该类的对象里获得与该Action相关联的Action对象和Result对象,在完成拦截器自己的任务之后,拦截器将调用ActionInvocation
对象的invoke
方法前进到Action处理流程的下一个环节AbstractInterceptor
类实现了Interceptor
接口,并为init
,destory
提供了一个空白的实现。
自定义拦截器
定义一个拦截器的类
可以实现Interceptor
接口
也可以继承AbstractInterceptor
抽象类在
struts.xml
文件中配置注意:在自定义的拦截器中可以选择不调用
ActionInvocation
的invoke()
方法,那么后续的拦截器和Action方法将不会被调用。Struts2会渲染自定义拦截器intercept
方法返回值对应的result
示例:
定义拦截器类myInterceptor:
package com.cerr.struts2.interceptors;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class myInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation actionInvocation) throws Exception {
System.out.println("调用actionInvocation.invoke之前");
String result = actionInvocation.invoke();
System.out.println("调用actionInvocation.invoke之后");
return result;
}
}
配置及使用:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<package name="default" namespace="/" extends="struts-default">
<interceptors>
<!-- 配置-->
<interceptor name="hello" class="com.cerr.struts2.interceptors.myInterceptor"></interceptor>
</interceptors>
<action name="testToken" class="com.cerr.struts2.TokenAction">
<!-- 使用-->
<interceptor-ref name="hello"></interceptor-ref>
<interceptor-ref name="token"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
<result>/success.jsp</result>
<result name="invalid.token">/token-error.jsp</result>
</action>
</package>
</struts>