每次填写完表单后单击提交后,struts中action执行相关业务逻辑,通过forward对象转到某个页面。这时若刷新页面后,会再执行同样的逻辑。比如录数据到数据库,按照上面的情况,数据库中会有两条同样的数据。为了避免这种情况,有几种解决办法:
1 :在执行业务逻辑后,返回一个Forward对象,这个forward对象的path属性应该配置一个幂等的XXX.do操作,这样可以解决,但是有可能不符合用户的要求,所以还有其他方法。
2:重定向,在配置文件里配置redirect属性,重定向到xxx.jsp。这种情况下会丢失request范围内的参数,若xxx.jsp不要求这些参数就可以,如操作的数据保存在session范围内,就不会影响整体效果。但还是有弊端。
3:利用struts1.x令牌能很好解决这类问题。
必要条件:在表单内,必须使用struts的库标签如:。
如下例子:
LoginAction:
package com.web.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;
public class LoginAction extends DispatchAction {
public ActionForward get(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
//保存令牌(保存在jsp动态生成的32位jsessionid)\
this.saveToken(request);
System.out.println("begin save");
return mapping.findForward("login");
}
public ActionForward login(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
/**//*if(this.isTokenValid(request))
{
System.out.println("valid");
this.resetToken(request);
return mapping.findForward("ok");
}*/
//这个写法和上面注释部分一样效果
if(this.isTokenValid(request,true))
{
System.out.println("valid");
return mapping.findForward("ok");
}
else
{
System.out.println("invalid");
return mapping.findForward("error");
}
}
}
struts-config.xml:
type="com.web.action.LoginAction">
index.jsp:
My Jsplogin.jsp:
My Jsp当你运行第一次的时候,会提示你"成功".这时我们退到login.jsp查看一下源代码:
My Jsp对比一下我们写的login.jsp多了一个隐藏域:
此时生成了一个32位的唯一的JsessionID做为值.与LoginAction中的get方法的saveToken(request)是一样的.此句的作用就是把一个jsessionid保存到request范围里.在我们后退重新调用:
if(this.isTokenValid(request,true))
{
System.out.println("valid");
return mapping.findForward("ok");
}
时,就会拿login.jsp里传过来的jsessionid和request的进行比较,如果一样,说明不合法.因为我们的操作都是在一个请求会话里操作的.说明你在重复提交.如果不一样,说明重新生成了一个唯一的jsessionid(新开一个浏览器),开启了一个新会话,重新提交,这是合法的.这样就防止了表单重复提交问题. 为了防止表单重复提交,一般在设计action方法时:如录入数据,设计成两个方法,add()和insert(),在add方法中保存令牌并转到页面,在页面提交到insert方法中,判断令牌。