一聚教程网:一个值得你收藏的教程网站

热门教程

JavaWeb中HttpSession中表单的重复提交示例

时间:2022-06-29 01:34:06 编辑:袖梨 来源:一聚教程网

表单的重复提交

  • 重复提交的情况:

①. 在表单提交到一个 Servlet,而 Servlet 又通过请求转发的方式响应了一个 JSP(HTML)页面,此时地址栏还保留着 Servlet 的那个路径,在响应页面点击 “刷新”。

②. 在响应页面没有到达时,重复点击 “提交按钮”

③. 点击返回,再点击提交

  • 不是重复提交的情况:点击 “返回”,“刷新” 原表单页面,再点击提交。

  • 如何避免表单的重复提交:在表单中做一个标记,提交到 Servlet 时,检查标记是否存在且和预定义的标记一样,若一致,则受理请求,并销毁标记,若不一致或没有标记,则直接响应提示信息:“重复提交”

①仅提供一个隐藏域不行:

②把标记放在 Request 中 , 行不通,表单页面刷新后,request 已经被销毁,再提交表单是一个新的 request 的。

③把标记放在 Session 中,可以

1. 在原表单页面,生成一个随机值 token
2. 在原表单页面,把 token 值放入 session 属性中

3. 在原表单页面,把 token 值放入到隐藏域

4. 在目标的 Servlet 中:获取 session 和隐藏域中的 token 值

比较两个值是否一致,受理请求,且把 session 域中的 token 属性清除,若不一致,则直接响应提示页面:“重复提交”

我们可以通过 Struts1 中写好的类 TokenProcessor 来重构代码, 面向组件编程

 

 代码如下复制代码

packagecom.lsy.javaweb;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpSession;

importjava.security.MessageDigest;

importjava.security.NoSuchAlgorithmException;

publicclassTokenProcessor {

  privatestaticfinalString TOKEN_KEY ="TOKEN_KEY";

  privatestaticfinalString TRANSACTION_TOKEN_KEY ="TRANSACTION_TOKEN_KEY";

  /**

   * The singleton instance of this class.

   */

  privatestaticTokenProcessor instance =newTokenProcessor();

  /**

   * The timestamp used most recently to generate a token value.

   */

  privatelongprevious;

  /**

   * Protected constructor for TokenProcessor. Use

   * TokenProcessor.getInstance() to obtain a reference to the processor.

   */

  protectedTokenProcessor() {

    super();

  }

  /**

   * Retrieves the singleton instance of this class.

   */

  publicstaticTokenProcessor getInstance() {

    returninstance;

  }

  /**

   *


   * Return true if there is a transaction token stored in the

   * user's current session, and the value submitted as a request parameter

   * with this action matches it. Returns false under any of the

   * following circumstances:

   *

   *

   *

       *

       *

    • No session associated with this request

       *

       *

    • No transaction token saved in the session

       *

       *

    • No transaction token included as a request parameter

       *

       *

    • The included transaction token value does not match the transaction

       * token in the user's session

       *

       *

       *

       * @param request

       *      The servlet request we are processing

       */

      publicsynchronizedbooleanisTokenValid(HttpServletRequest request) {

        returnthis.isTokenValid(request,false);

      }

      /**

       * Return true if there is a transaction token stored in the

       * user's current session, and the value submitted as a request parameter

       * with this action matches it. Returns false

       *

       *

         *

         *

      • No session associated with this request

         *

      • No transaction token saved in the session

         *

         *

      • No transaction token included as a request parameter

         *

         *

      • The included transaction token value does not match the transaction

         * token in the user's session

         *

         *

         *

         * @param request

         *      The servlet request we are processing

         * @param reset

         *      Should we reset the token after checking it?

         */

        publicsynchronizedbooleanisTokenValid(HttpServletRequest request,booleanreset) {

          // Retrieve the current session for this request

          HttpSession session = request.getSession(false);

          if(session ==null) {

            returnfalse;

          }

          // Retrieve the transaction token from this session, and

          // reset it if requested

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

          if(saved ==null) {

            returnfalse;

          }

          if(reset) {

            this.resetToken(request);

          }

          // Retrieve the transaction token included in this request

          String token = request.getParameter(TOKEN_KEY);

          if(token ==null) {

            returnfalse;

          }

          returnsaved.equals(token);

        }

        /**

         * Reset the saved transaction token in the user's session. This indicates

         * that transactional token checking will not be needed on the next request

         * that is submitted.

         *

         * @param request

         *      The servlet request we are processing

         */

        publicsynchronizedvoidresetToken(HttpServletRequest request) {

          HttpSession session = request.getSession(false);

          if(session ==null) {

            return;

          }

          session.removeAttribute(TRANSACTION_TOKEN_KEY);

        }

        /**

         * Save a new transaction token in the user's current session, creating a

         * new session if necessary.

         *

         * @param request

         *      The servlet request we are processing

         */

        publicsynchronizedString saveToken(HttpServletRequest request) {

          HttpSession session = request.getSession();

          String token = generateToken(request);

          if(token !=null) {

            session.setAttribute(TRANSACTION_TOKEN_KEY, token);

          }

          returntoken;

        }

        /**

         * Generate a new transaction token, to be used for enforcing a single

         * request for a particular transaction.

         *

         * @param request

         *      The request we are processing

         */

        publicsynchronizedString generateToken(HttpServletRequest request) {

          HttpSession session = request.getSession();

          returngenerateToken(session.getId());

        }

        /**

         * Generate a new transaction token, to be used for enforcing a single

         * request for a particular transaction.

         *

         * @param id

         *      a unique Identifier for the session or other context in which

         *      this token is to be used.

         */

        publicsynchronizedString generateToken(String id) {

          try{

            longcurrent = System.currentTimeMillis();

            if(current == previous) {

              current++;

            }

            previous = current;

            byte[] now =newLong(current).toString().getBytes();

            MessageDigest md = MessageDigest.getInstance("MD5");

            md.update(id.getBytes());

            md.update(now);

            returntoHex(md.digest());

          }catch(NoSuchAlgorithmException e) {

            returnnull;

          }

        }

        /**

         * Convert a byte array to a String of hexadecimal digits and return it.

         *

         * @param buffer

         *      The byte array to be converted

         */

        privateString toHex(byte[] buffer) {

          StringBuffer sb =newStringBuffer(buffer.length *2);

          for(inti =0; i < buffer.length; i++) {

            sb.append(Character.forDigit((buffer[i] &0xf0) >>4,16));

            sb.append(Character.forDigit(buffer[i] &0x0f,16));

          }

          returnsb.toString();

        }

      }

       

      热门栏目