天天看點

使用struts的同步令牌避免form的重複送出

一、使用方法

1、  假如你要送出的頁面為toSubmit.jsp;

2、  在打開toSubmit.jsp的Action1中加入:saveToken(request),例如

public ActionForward execute(

    ActionMapping mapping,

    ActionForm form,

    HttpServletRequest request,

    HttpServletResponse response)

    throws Exception {

        //生成同步令牌

        saveToken(request);    

        return mapping.findForward("toSubmit");

}

3、  在送出toSubmit.jsp的Action2中加入:isTokenValid(request, true),例如:

public ActionForward execute(

    ActionMapping mapping,

    ActionForm form,

    HttpServletRequest request,

    HttpServletResponse response)

    throws Exception {

    // 驗證同步令牌

        if (isTokenValid(request, true)) { 

            //執行送出操作 

        }else {

            // 重複送出        

            return mapping.findForward("Error");

        }

}

4、  使用注意:toSubmit.jsp中的form必須使用struts的标簽<html:form>。

二、基本原理

第一步、在session中放入同步令牌

在Action1中加入了saveToken(request)的方法後,調用TokenProcessor類的saveToken方法如下:

public synchronized void saveToken(HttpServletRequest request) {

    HttpSession session = request.getSession();

    String token = generateToken(request);

    if (token != null) {

        session.setAttribute(Globals.TRANSACTION_TOKEN_KEY, token);

    }

}

很明顯在session中放入了同步令牌,名稱為Globals.TRANSACTION_TOKEN_KEY。

第二步、在頁面建立hidden元素

當應用伺服器初始化toSubmit.jsp頁面遇到标簽<html:form>時,便會調用struts的FormTag類,其中有一個方法:

protected String renderToken() {

    StringBuffer results = new StringBuffer();

    HttpSession session = pageContext.getSession();

    if (session != null) {

        String token =

            (String) session.getAttribute(Globals.TRANSACTION_TOKEN_KEY);

        if (token != null) {

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

            results.append(Constants.TOKEN_KEY);

            results.append("\" value=\"");

            results.append(token);

            if (this.isXhtml()) {

                results.append("\" />");

            } else {

                results.append("\">");

            }

        }

    }

    return results.toString();

}

其意為:當檢測到session中的Globals.TRANSACTION_TOKEN_KEY不為空時,在toSubmit.jsp頁面建立元素:

<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="">

名稱為:org.apache.struts.taglib.html.TOKEN就是Constants.TOKEN_KEY;

值為:session中的Globals.TRANSACTION_TOKEN_KEY的值,即為同步令牌值。

第三步、驗證同步令牌

在Action2中加入isTokenValid方法,實際上是調用TokenProcessor類的isTokenValid方法如下:

public synchronized boolean isTokenValid(

    HttpServletRequest request,

    boolean reset) {

    // Retrieve the current session for this request

    HttpSession session = request.getSession(false);

    if (session == null) {

        return false;

    }

    // Retrieve the transaction token from this session, and

    // reset it if requested

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

    if (saved == null) {

        return false;

    }

    if (reset) {

        this.resetToken(request);

    }

    // Retrieve the transaction token included in this request

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

    if (token == null) {

        return false;

    }

    return saved.equals(token);

}

它首先取得session中的令牌值,然後resetToken,再從頁面hidden元素取來令牌值,進行比較,如果相等則為第一次,不等則為重複送出。

其中resetToken方法如下:

public synchronized void resetToken(HttpServletRequest request) {

  HttpSession session = request.getSession(false);

  if (session == null) {

      return;

  }

  session.removeAttribute(Globals.TRANSACTION_TOKEN_KEY);

}