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

来源:互联网 发布:抢票软件 知乎 编辑:程序博客网 时间:2024/05/19 12:41

一、使用方法

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

}

原创粉丝点击