jc_dreaming 发表于 2013-2-6 10:00:38

Struts1.x 重复提交剖析

在某些情况下,如果用户对一个HTML表单重复提交,Web应用应该必须能够判断用户的重复提交行为,以做相应的处理。

Struts给出了一个参考实现。org.apache.struts.action.Action类中提供了一系列和Token有关的方法:

1.protected boolean isTokenValid(javax.servlet.http.HttpServletRequest request)
判断存储在当前用户会话中的令牌值和请求参数中的令牌值是否匹配,如果匹配就返回true,否则返回false.
2.protected void resetToken(javax.servlet.http.HttpServletRequest request) 从当前session中删除令牌值。

3. protected void saveToken(javax.servlet.http.HttpServletRequest request)
创建一个新令牌,并把他保存在session范围内。

提示:具体的Token处理逻辑是org.apache.struts.util.TokenProcesor类完成的,大家可以反编译看看这个类的处理逻辑。它的generateToken(request)方法根据用户会话ID和当前的系统时间来生成一个唯一的令牌值。

流程:
比如一个注册流程,在用户请求注册页面之前,是由一个Action转发给到这个注册页面,在这个Action中加入saveToken(request)方法,创建一个Token,并把它保存在session中。然后转发给注册页面。在注册页面的<html:form>标签的处理类会判断session中是否存在Token,如果存在就在表单中生成一个隐藏域,隐藏域的值就是利用Struts的Token机制算出来的那个值。当用户接收到注册页面后就会发现在FORM表单中存在的Token的隐藏域。在用户提交了注册信息到另一个Action中时,在这个Action中用isTokenValid(request)来判断是否是重复提交,如果用户是第一次提交表单返回true,如果用户通过浏览器返回按扭,返回该页再次提交则返回false;进行错误处理。

例子:Action1:public class RegAction extends Action{                public ActionForward execute(               ActionMapping mapping,                  ActionForm form,                  HttpServletRequest request,                  HttpServletResponse response)          {                      //调用方法生成Token                     saveToken(request);                     // TODO Auto-generated method stub                      return mapping.findForward("register");             }    }   public class RegAction extends Action {      public ActionForward execute(                  ActionMapping mapping,                  ActionForm form,                  HttpServletRequest request,                  HttpServletResponse response)         {                //调用方法生成Token                saveToken(request);                // TODO Auto-generated method stub                return mapping.findForward("register");      }}
Action1转发给JSP页面:

<html:form action="/tokenAction.do" method="poset">    <html:submit>Submit</html:submit>    </html:form>   <html:form action="/tokenAction.do" method="poset"><html:submit>Submit</html:submit></html:form>
在这里会自动生成Token的隐藏域:

<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="164fcc77cafd18db1011da3d8ab868e5">   <input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="164fcc77cafd18db1011da3d8ab868e5">
Action2: jsp页面提交给过来请求

if(!isTokenValid(request))    {               System.out.println("重复提交TokenAction");               saveToken(request);               return (new ActionForward(mapping.getInput()));    }    else   {               resetToken(request);               System.out.println("重新设置Token!   TokenAction");    }   if(!isTokenValid(request)){    System.out.println("重复提交TokenAction");    saveToken(request);    return (new ActionForward(mapping.getInput()));}else{    resetToken(request);    System.out.println("重新设置Token!   TokenAction");}判断是否是重复提交,如果重复提交就转发到默认在struts-config.xml中为Action2配置的错误页面中,并重新建立一个Token。如果不是重复提交就就从当前session中删除Token.
OK,就是这些了,如果你的应用中可以返回一个错误页面,那么你也可以在filter中应用Token这些方法,只不过需要对struts的jar包进行反编译,拿到自己的类中来用。
页: [1]
查看完整版本: Struts1.x 重复提交剖析