token 在struts裏的使用詳解!!!!!!!!!

1、你想發貼時,點擊“我要發貼”鏈接的代碼可以裏這樣的:
〈html:link action="subject.do?method=add"〉我要發貼〈/html:link〉
subject.do 和 method 這些在struct-config.xml如何定義我就不說了,點擊鏈接後,會執行subject.do的add方法,代碼如上面說的,跳轉到subjectAdd.jsp頁面。頁面的代碼大概如下:
〈html:form action="subjectForm.do?method=insert"〉
  〈html:text property="title" /〉
  〈html:textarea property="content" /〉
  〈html:submit property="發表" /〉
  〈html:reset property="重填" /〉
〈html:form〉
如果你在add方法里加了“saveToken(request);”這一句,那在subjectAdd.jsp生成的頁面上,會多一個隱藏字段,類似於這樣〈input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae"〉,

2、點擊發表後,表單提交到subjectForm.do裏的insert方法後,你在insert方法裏要將表單的數據插入到數據庫中,如果沒有進行重複提交的控制,那麼每點擊一次瀏覽器的刷新按鈕,都會在數據庫中插入一條相同的記錄,增加下面的代碼,你就可以控制用戶的重複提交了。
if (isTokenValid(request, true)) {
// 表單不是重複提交
//這裏是保存數據的代碼
} else {
//表單重複提交
saveToken(request);
//其它的處理代碼
}
注意,你必須在add方法裏使用了saveToken(request),你才能在insert裏判斷,否則,你每次保存操作都是重複提交。
記住一點,Struts在你每次訪問Action的時候,都會產生一個令牌,保存在你的Session裏面,如果你在Action裏的函數裏面,使用了saveToken(request);,那麼這個令牌也會保存在這個Action所Forward到的jsp所生成的靜態頁面裏。
如果你在你Action的方法裏使用了isTokenValid,那麼Struts會將你從你的request裏面去獲取這個令牌值,然後和Session裏的令牌值做比較,如果兩者相等,就不是重複提交,如果不相等,就是重複提交了。

由於我們項目的所有Action都是繼承自BaseDispatchAction這個類,所以我們基本上都是在這個類裏面做了表單重複提交的控制,默認是控制add方法和insert方法,如果需要控制其它的方法,就自己手動寫上面這些代碼,否則是不需要手寫的,控制的代碼如下:
public abstract class BaseDispatchAction extends BaseAction {
protected ActionForward perform(ActionMapping mapping, ActionForm form,
    HttpServletRequest request, HttpServletResponse response)
    throws Exception {
        String parameter = mapping.getParameter();
        String name = request.getParameter(parameter);
if (null == name) { //如果沒有指定 method ,則默認爲 list
            name = "list";
        }

        if ("add".equals(name)) {
            if ("add".equals(name)) {
                saveToken(request);
            }
        } else if ("insert".equals(name)) {
            if (!isTokenValid(request, true)) {
                resetToken(request);
                saveError(request, new ActionMessage("error.repeatSubmit"));
                log.error("重複提交!");
                return mapping.findForward("error");
            }
        }
        return dispatchMethod2(mapping, form, request, response, name);
    }

 

0、  使用注意: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 將不會起到避免重複提交的作用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章