`
botan1314
  • 浏览: 24718 次
  • 性别: Icon_minigender_1
  • 来自: 湖南
社区版块
存档分类
最新评论

使用struts的同步令牌避免form的重复提交

阅读更多

一、使用方法

1   假如你要提交的页面为toSubmit.jsp

2   在打开toSubmit.jspAction1 中加入:saveToken(request) ,例如

public ActionForward execute(

    ActionMapping mapping,

    ActionForm form,

    HttpServletRequest request,

    HttpServletResponse response)

    throws Exception {

   

        // 生成同步令牌

        saveToken(request);    

 

        return mapping.findForward("toSubmit");

}

3   在提交toSubmit.jspAction2 中加入: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> 时,便会调用strutsFormTag 类,其中有一个方法:

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);

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics