溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaWeb中HttpSession中表單的重復提交示例

發(fā)布時間:2020-08-24 19:31:44 來源:腳本之家 閱讀:132 作者:http://blog.csdn.net 欄目:編程語言

表單的重復提交

  • 重復提交的情況:

①. 在表單提交到一個 Servlet,而 Servlet 又通過請求轉(zhuǎn)發(fā)的方式響應了一個 JSP(HTML)頁面,此時地址欄還保留著 Servlet 的那個路徑,在響應頁面點擊 “刷新”。

②. 在響應頁面沒有到達時,重復點擊 “提交按鈕”

③. 點擊返回,再點擊提交

  • 不是重復提交的情況:點擊 “返回”,“刷新” 原表單頁面,再點擊提交。
  • 如何避免表單的重復提交:在表單中做一個標記,提交到 Servlet 時,檢查標記是否存在且和預定義的標記一樣,若一致,則受理請求,并銷毀標記,若不一致或沒有標記,則直接響應提示信息:“重復提交”

①僅提供一個隱藏域不行:<input type="hidden" name="token" value="lsy">

②把標記放在 Request 中 , 行不通,表單頁面刷新后,request 已經(jīng)被銷毀,再提交表單是一個新的 request 的。

③把標記放在 Session 中,可以

1. 在原表單頁面,生成一個隨機值 token
2. 在原表單頁面,把 token 值放入 session 屬性中

3. 在原表單頁面,把 token 值放入到隱藏域

4. 在目標的 Servlet 中:獲取 session 和隱藏域中的 token 值

比較兩個值是否一致,受理請求,且把 session 域中的 token 屬性清除,若不一致,則直接響應提示頁面:“重復提交”

我們可以通過 Struts1 中寫好的類 TokenProcessor 來重構(gòu)代碼, 面向組件編程

package com.lsy.javaweb;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class TokenProcessor {
  private static final String TOKEN_KEY = "TOKEN_KEY";
  private static final String TRANSACTION_TOKEN_KEY = "TRANSACTION_TOKEN_KEY";
  /**
   * The singleton instance of this class.
   */
  private static TokenProcessor instance = new TokenProcessor();
  /**
   * The timestamp used most recently to generate a token value.
   */
  private long previous;
  /**
   * Protected constructor for TokenProcessor. Use
   * TokenProcessor.getInstance() to obtain a reference to the processor.
   */
  protected TokenProcessor() {
    super();
  }
  /**
   * Retrieves the singleton instance of this class.
   */
  public static TokenProcessor getInstance() {
    return instance;
  }
  /**
   * <p>
   * Return <code>true</code> 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 <code>false</code> under any of the
   * following circumstances:
   * </p>
   *
   * <ul>
   *
   * <li>No session associated with this request</li>
   *
   * <li>No transaction token saved in the session</li>
   *
   * <li>No transaction token included as a request parameter</li>
   *
   * <li>The included transaction token value does not match the transaction
   * token in the user's session</li>
   *
   * </ul>
   *
   * @param request
   *      The servlet request we are processing
   */
  public synchronized boolean isTokenValid(HttpServletRequest request) {
    return this.isTokenValid(request, false);
  }
  /**
   * Return <code>true</code> 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 <code>false</code>
   *
   * <ul>
   *
   * <li>No session associated with this request</li>
   * <li>No transaction token saved in the session</li>
   *
   * <li>No transaction token included as a request parameter</li>
   *
   * <li>The included transaction token value does not match the transaction
   * token in the user's session</li>
   *
   * </ul>
   *
   * @param request
   *      The servlet request we are processing
   * @param reset
   *      Should we reset the token after checking it?
   */
  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(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(TOKEN_KEY);
    if (token == null) {
      return false;
    }
    return saved.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
   */
  public synchronized void resetToken(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
   */
  public synchronized String saveToken(HttpServletRequest request) {
    HttpSession session = request.getSession();
    String token = generateToken(request);
    if (token != null) {
      session.setAttribute(TRANSACTION_TOKEN_KEY, token);
    }
    return token;
  }
  /**
   * Generate a new transaction token, to be used for enforcing a single
   * request for a particular transaction.
   *
   * @param request
   *      The request we are processing
   */
  public synchronized String generateToken(HttpServletRequest request) {
    HttpSession session = request.getSession();
    return generateToken(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.
   */
  public synchronized String generateToken(String id) {
    try {
      long current = System.currentTimeMillis();
      if (current == previous) {
        current++;
      }
      previous = current;
      byte[] now = new Long(current).toString().getBytes();
      MessageDigest md = MessageDigest.getInstance("MD5");
      md.update(id.getBytes());
      md.update(now);
      return toHex(md.digest());
    } catch (NoSuchAlgorithmException e) {
      return null;
    }
  }
  /**
   * Convert a byte array to a String of hexadecimal digits and return it.
   *
   * @param buffer
   *      The byte array to be converted
   */
  private String toHex(byte[] buffer) {
    StringBuffer sb = new StringBuffer(buffer.length * 2);
    for (int i = 0; i < buffer.length; i++) {
      sb.append(Character.forDigit((buffer[i] & 0xf0) >> 4, 16));
      sb.append(Character.forDigit(buffer[i] & 0x0f, 16));
    }
    return sb.toString();
  }
}

以上所述是小編給大家介紹的JavaWeb中HttpSession中表單的重復提交示例,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對億速云網(wǎng)站的支持!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI