在页面中使用WebWork的token标签解决表单重复提交问题
王保政
我们的项目是基于Struts开发的,在设计时没有考虑重复提交的问题,所以用户在点击页面的提交,然后在下一个浏览器页面点后退,或者点提交时没跳转到新页面,在当前页面多次点击提交按钮,这两种情况都会产生重复提交的问题,例如用户基本信息维护的新增页面,点两次保存会向数据库提交两次,这时数据库中会新增两条记录。
后来我们引入了Webwork框架(项目的主框架仍然是基于struts的,只是将webwork配置到当前项目中,就可以使用webwork的token标签),通过Webwork的token标签解决了这个问题(当然不是必须引入webwork才能解决,而是webwork提供了现成的token标签供我们使用),下面是引入了webwork的token标签的JSP代码:
<%@ taglib uri="webwork" prefix="ww" %>
Please enter your 姓名:
<%
String s = (String)session.getAttribute("UserInfo.token");
if(s!=null){
System.out.println(s);
}
%>
其中UserInfo.token是我们为当前表单的token定义了一个名字,不同的表单可以定义不同的token名。
访问此JSP,在浏览器中查看此JSP生成的html代码:
Please enter your 姓名:
可以看到webwork在表单中生成了一个webwork.token.name和UserInfo.token的隐藏列,webwork除了生成了隐藏列外,还将token值写入到了session中的UserInfo.token变量。
在录入页面中生成了token之后,在struts的控制层如何控制表单不重复提交?见下面的控制层的代码:
try
{
String requestToken = request.getParameter("UserInfo.token");
String sessionToken = (String)session.getAttribute("UserInfo.token"); //JSP中直接使用//session,在Struts的action类中用request.getSession()获取Session。
System.out.println("请求中的token为:");
System.out.println(requestToken);
if(sessionToken.equals(requestToken))
{
System.out.println("1:token值相同,下面处理正常业务,并删除Session中的token!!");
session.setAttribute("UserInfo.token","0"); //也可以直接removeAttribute,这样在异常里//提示session中的token为空,不能重复操作!设为0等同于清空,因为生成的token肯定不//是0,这样做是为了不抛出异常。
//session.removeAttribute(“UserInfo.token”);
}
else
{
System.out.println("2:token值不同,为重复提交!!");
}
}
catch(Exception ex)
{
System.out.println("session中的token被删除,为重复提交!");
}
用token防止重复提交的大致思路是这样的:
(1) 在开始访问一个页面时Webwork新建了一个token隐藏字段,另外将token写入到session中,例如上面的UserInfo.token字段和session中的UserIno.token字段,在一开始访问用户录入页面时,两个值相等。
(2) 在录入页面点提交,然后控制层的类就开始判断request参数中的UserInfo.token(对应的UserInfo.token隐藏字段)和session中的UserInfo.token的值是否相等,如果相等,则说明是第一次访问,可以提交,但处理完业务后,要将此token清空。
(3) 如果是录入页面通过后退或重复点击进行保存的操作,因为这两种情况都不会再次在Session中生成UserInfo.token值(此值已在处理完业务后被清空),所以控制层根据session中的此值为空或不等于request中的token值来判断是否为重复提交。
Webwork可以在控制层配置TokenInterceptor,可以不需要将token控制代码写到Action类中。以上实现方案供大家参考,在项目中如果需要用这种方式防止重复提交,实际上只需要在form中添加