情景模拟:在实际应用中由于设备网速等原因导致用户在提交表单后服务器长时间未响应,此时用户可能会对表单进行重复提交。或是在用户提交完表单后服务器给出了响应,而另一端用户对响应页面进行反复多次刷新,此时也会出现表单重复提交的情况。
令牌机制(隐藏域)
用户在页面提交资源请求后,服务器当即产生一个随机字符串(此字符串即称为令牌)并为该字符串保留两个副本,其中一个保留在服务器,另一个则跟随响应返回给客户端。
原理解析:
① 在令牌机制的加持下用户对表单进行首次提交时,系统会将本地副本字符串与服务器副本字符串相比较,此时的比较结果一定相同。
② 系统判断比较结果相同后,服务器端会修改原先保留的副本字符串,而此修改并不会影响到浏览器端的原副本。
③ 用户在页面中对表单进行重复提交时,用户向服务器端发送的请求中仍带有原副本字符串,当原副本字符串与服务器端已修改的副本字符串相比较的结果不同时证明表单被重复提交。
Action类
package action;
import com.opensymphony.xwork2.ActionSupport;
public class TokenSysAction extends ActionSupport {
private String userName;
private String userPwd;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
public String execute() {
return "success";
}
}
struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="tokenSystem" namespace="/tokenSys" extends="struts-default">
<action name="tokenSysAction" class="action.TokenSysAction">
<result name="success">/welcome.jsp</result>
<!-- 配置表单重复提交时跳转的视图 -->
<result name="invalid.token">/message.jsp</result>
<!-- 令牌拦截器不在默认开启的20个拦截器中,因此需要显式声明 -->
<interceptor-ref name="token"/>
<!-- 显式声明任意的拦截器后默认的拦截器栈便不再生效,手动指定拦截器栈 -->
<interceptor-ref name="defaultStack"/>
</action>
</package>
</struts>
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Index</title>
<style type="text/css">
table {
width: 350px;
height: 200px;
text-align: center;
margin: 50px auto;
background-color: lightblue;
}
</style>
</head>
<body>
<form action="tokenSys/tokenSysAction.action" method="post">
<!-- 提示服务器此表单使用了通行令牌 -->
<s:token/>
<table border="0px" cellpadding="6px" cellspacing="6px">
<tr>
<td colspan="2">您好,请登录!</td>
</tr>
<tr>
<td>用户名:</td>
<td><input type="text" name="userName" placeholder="请输入用户名" /></td>
</tr>
<tr>
<td>密 码:</td>
<td><input type="password" name="userPwd" placeholder="请输入密码" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="登录" />
</td>
</tr>
</table>
</form>
</body>
</html>
message.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Message</title>
</head>
<body>
<h2 align="center">提示:您已提交过该请求,无需重复提交!</h2>
</body>
</html>
welcome.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Welcome</title>
</head>
<body>
<h2 align="center">请求已提交,请静候处理!</h2>
</body>
</html>
运行示例: