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

发布时间 - 2026-01-10 23:21:35    点击率:

表单的重复提交

  • 重复提交的情况:

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

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

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

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

①仅提供一个隐藏域不行:<input type="hidden" name="token" value="lsy">

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

③把标记放在 Session 中,可以

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

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

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

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

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

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中表单的重复提交示例,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!


# javaweb  # httpsession表单  # 表单重复提交  # 浅谈利用Session防止表单重复提交  # 表单  # 放在  # 若不  # 小编  # 再点  # 是一个  # 在此  # 提示信息  # 我们可以  # 给大家  # 提供一个  # 所述  # 给我留言  # 写好  # 感谢大家  # 是否存在  # 再提  # 中做  # 重构  # 疑问请 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Laravel表单请求验证类怎么用_Laravel Form Request分离验证逻辑教程  昵图网官网入口 昵图网素材平台官方入口  Windows10怎样连接蓝牙设备_Windows10蓝牙连接步骤【教程】  动图在线制作网站有哪些,滑动动图图集怎么做?  简单实现Android文件上传  电商网站制作多少钱一个,电子商务公司的网站制作费用计入什么科目?  齐河建站公司:营销型网站建设与SEO优化双核驱动策略  android nfc常用标签读取总结  C#如何调用原生C++ COM对象详解  详解一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)  历史网站制作软件,华为如何找回被删除的网站?  如何快速辨别茅台真假?关键步骤解析  如何在阿里云高效完成企业建站全流程?  详解jQuery中基本的动画方法  Laravel如何操作JSON类型的数据库字段?(Eloquent示例)  如何用美橙互联一键搭建多站合一网站?  Laravel如何实现用户注册和登录?(Auth脚手架指南)  laravel怎么使用数据库工厂(Factory)生成带有关联模型的数据_laravel Factory生成关联数据方法  如何在自有机房高效搭建专业网站?  UC浏览器如何设置启动页 UC浏览器启动页设置方法  网站优化排名时,需要考虑哪些问题呢?  Laravel如何生成和使用数据填充?(Seeder和Factory示例)  HTML 中动态设置元素 name 属性的正确语法详解  打造顶配客厅影院,这份100寸电视推荐名单请查收  🚀拖拽式CMS建站能否实现高效与个性化并存?  详解vue.js组件化开发实践  Laravel怎么导出Excel文件_Laravel Excel插件使用教程  如何快速查询网站的真实建站时间?  如何快速搭建高效简练网站?  ,交易猫的商品怎么发布到网站上去?  Laravel如何处理JSON字段_Eloquent原生JSON字段类型操作教程  如何在企业微信快速生成手机电脑官网?  米侠浏览器网页图片不显示怎么办 米侠图片加载修复  Laravel如何使用Scope本地作用域_Laravel模型常用查询逻辑封装技巧【手册】  香港服务器租用费用高吗?如何避免常见误区?  Laravel怎么生成URL_Laravel路由命名与URL生成函数详解  夸克浏览器网页跳转延迟怎么办 夸克浏览器跳转优化  jQuery中的100个技巧汇总  Laravel如何为API编写文档_Laravel API文档生成与维护方法  javascript如何操作浏览器历史记录_怎样实现无刷新导航  Windows驱动无法加载错误解决方法_驱动签名验证失败处理步骤  Laravel怎么判断请求类型_Laravel Request isMethod用法  EditPlus中的正则表达式实战(5)  html如何与html链接_实现多个HTML页面互相链接【互相】  米侠浏览器网页背景异常怎么办 米侠显示修复  百度浏览器ai对话怎么关 百度浏览器ai聊天窗口隐藏  如何用好域名打造高点击率的自主建站?  武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?  深圳网站制作设计招聘,关于服装设计的流行趋势,哪里的资料比较全面?  如何在建站之星绑定自定义域名?