转载请注明出处:http://blog.csdn.net/qq_15002323/article/details/51253303
注:本章内容基于struts2框架,action就相当于servlet
哎,今天遇到这个问题快把我搞崩溃了咯,但是,注意只是快,并没有- -,感觉自己就像卡卡罗特一样啊,只要不把我拍死,我只会变得更强噢。
场景重现
上网最痛苦的事莫过于网速慢了,这个玩lol的自然懂~~~。打个粗糙的比方吧,一个登陆页面,你很急,但是网很卡,登了半天没卵用,你连点了几次登录①。你登录进去了,刷新了浏览器页面②。登陆成功后,你后退,再次点击登录③。
上述三种情况都会导致表单数据的重复提交,这样直接的后果便是服务器的多次响应,这当然不是我们程序猿想看到的。好了,我要开始装X模式了,先搭建相关开发环境,一个登陆页面login.jsp,一个login.action,一个跳转的main.jsp,配置好相关映射关系:
login.jsp:
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>登陆</title>
</head>
<body>
<form action="login.action" method="post">
<input type="text" name="name"/>
<br/>
<input type="password" name="age"/>
<br/>
<input type="submit" />
</form>
</body>
</html>
login.action:
import com.opensymphony.xwork2.ActionSupport;
public class Login extends ActionSupport {
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String execute() throws Exception {
// 休眠三秒,模拟网速很慢
Thread.sleep(1500);
System.out.println("姓名:" + name + "年龄:" + age);
return "success";
}
}
main.jsp 这个是个空的页面
网速较慢重复提交
提交完成再次刷新
后退页面再次提交
解决之道
其实文章开头就说了本文是基于Struts2的,这里就说说理由吧,不吹牛。解决上述问题的根本方法就是在服务器做处理,只对用户响应一次,最好的办法就是采取token的方式。
token,其实就是用户自定义的字符串,可以保存在session里面,在Struts2中加上<s:token />
当该页面渲染就会生成一个token(令牌),会随着form参数一起提交到服务器,生成机制可以自己编写。
那Struts2就可真是方便的不要不要的,内部已经封装好了token机制,调用起来也非常简单。首先引入struts2标签,然后在form内部加上<s:token />
,再修改struts.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="default" extends="struts-default">
<action name="login" class="com.cjt.test.Login">
<result name="success">/main.jsp</result>
<interceptor-ref name="tokenSession"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
</package>
</struts>
这样就可以了,是不是很神奇。我们看看效果图:
只有第一次打印了表单数据,后面都是提示“form中的token与session中的token->null不匹配”,这个是struts2做的,在第一次提交表单成功后,会删掉session中的token值,这样只有在第一次提交表单的时候session中的token没有被删除,与form传来的token一致,才会执行打印。具体实现可以在struts2的源码中找到,我这种小白就说说而已~(~ ̄▽ ̄)~
上面只是演示了那三种情况中的一种,其他都是一样的,就不做重复了。贴点有意思的吧,看看加了<s:token />
后提交表单的请求数据:
这样就很清楚了吧,有兴趣的大牛想钻研更深可以去看看源码,顺便贴一个参考的大牛水文:JavaWeb学习总结
又到了说再见的时候,拜了个拜。