您的位置:首页 > 编程语言 > Java开发

使用struts同步令牌机制避免表单的重复提交

2006-12-19 17:22 531 查看
一、使用方法 

1、假设你要提交的叶面为usermesg.jsp。

2、在打开usermesg.jsp的SaveTokenAction中加入saveToken(request),源码如下:

 


import javax.servlet.http.HttpServletRequest;


import javax.servlet.http.HttpServletResponse;




import org.apache.struts.action.Action;


import org.apache.struts.action.ActionForm;


import org.apache.struts.action.ActionForward;


import org.apache.struts.action.ActionMapping;








public class SaveToken extends Action ...{






    /**//* forward name="usermesg" path="/usermesg.jsp" */


    private final static String USERMESG = "usermesg";




    public ActionForward execute(ActionMapping mapping, ActionForm form,


            HttpServletRequest request, HttpServletResponse response)




            throws Exception ...{


        


         // 在session中放入同步令牌


        saveToken(request);




        // TODO process request and return an ActionForward instance, for example:


        // return mapping.findForward(USERMESG);


        return mapping.findForward(USERMESG);


    }


}

3、在叶面提交的ValidatorAction中加入isTokenValid(request,true)源码如下:

 


import javax.servlet.http.HttpServletRequest;


import javax.servlet.http.HttpServletResponse;




import org.apache.struts.action.Action;


import org.apache.struts.action.ActionForm;


import org.apache.struts.action.ActionForward;


import org.apache.struts.action.ActionMapping;






public class Validator extends Action ...{


    private final static String ERROR="error";


    private final static String WELCOME="welcome";


    public ActionForward execute(ActionMapping mapping, ActionForm form,


            HttpServletRequest request, HttpServletResponse response)




            throws Exception ...{


        


         // 验证同步令牌




        if(isTokenValid(request,true))...{


            return mapping.findForward(WELCOME);




        }else...{


            return mapping.findForward(ERROR);


        }


        // TODO process request and return an ActionForward instance, for example:


        // return mapping.findForward("forward_name");


    }


}

4、  使用注意:usermesg.jsp中的form表单必须使用struts的标签<html:form>。

二、基本原理

1、在session中放入同步令牌。原理:调用TokenProcessor类的saveToken(HttpServletRequest arg0);源码如下:

在sesssion中放入名称为Globale.TRANSACTION_TOKEN_KEY的同步令牌:token




          public synchronized void saveToken(HttpServletRequest request)...{


            HttpSession session=request.getSession();


            String token=generateToken(request);




            if(token!=null)...{


               session.setAttribute(Globale.TRANSACTION_TOKEN_KEY,token);


            }


         }

 

2、在打开usermesg.jsp时,应用服务器遇到<html:form>时,便会调用FormTag类的renderToken()方法创建hidden元素。源码如下:

 




protected String renderToken()...{


               StringBuffer result=new StringBuffer();


               HttpSession session=pageContext.getSession();




               if(session!=null)...{


                  String token=(String)session.getAttribute(Globale.TRANSACTION_TOKEN_KEY);




                  if(token!=null)...{


                    result.append("<input type="hidden" name="");


                    result.append(Constants.TOKEN_KEY);


                    result.append("" value="");


                    result.append(token);




                    if(this.isXhtml)...{


                      result.append("" />");




                    }else...{


                      result.append("" >");


                    }


                  }


               }


               return result.toStriong();


         }

hidden元素Constants.TOKEN_KEY的值就是session中的名称为Globale.TRANSACTION_TOKEN_KEY的同步令牌值

3、验证同步令牌,原理:调用TokenProcessor的isTokenValid(HttpServletRequest arg0,boolean arg1)源码如下:

 




public synchronized boolean isTokenValid(HttpServletRequest request,boolean reset)...{


            HttpSession session request.getSession(false);


            if(session==null) return false;


            


            String saved=(String)session.getAttribute(Globale.TRANSACTION_TOKEN_KEY);


            


            if(saved==null) return false;


            


            if(reset) this.resetToken(request);






            String token=request.getParameter(Constants.TOKEN_KEY);


             


             if(token==null) return false;


             


             return saved.equals(token);


          }

从叶面取出同步令牌值和session中的进行比较。如果相等则为第一次,不等就是重复提交。前提就是传进来的参数reset必须是true。不然每次都相同。其中resetToken()方法如下:

 






                public synchronized void resetToken(HttpServletRequest request)...{


                    HttpSession session request.getSession(false);




                    if(session==null)...{


                      return;


                    }


                    session.removeAttribute(Globale.TRANSACTION_TOKEN_KEY);


                }

这就是在isTokenValid方法中boolean参数的作用:清除session中的同步令牌,避免重复提交。如果把true改为false 将不会起到避免重复提交的作用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息