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

表单的重复提交

  • 重复提交的情况:

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

(0)

相关推荐

  • NetCore WebSocket即时通讯示例

    NetCore WebSocket 即时通讯示例,供大家参考,具体内容如下 1.新建Netcore Web项目 2.创建简易通讯协议 public class MsgTemplate { public string SenderID { get; set; } public string ReceiverID { get; set; } public string MessageType { get; set; } public string Content { get; set; } } Se

  • java使用HttpSession实现QQ访问记录

    java如何使用HttpSession实现QQ的访问记录,本文为大家揭晓答案,具体内容如下 1. 编写QQ空间数据类(QQS.java) public class QQS { private static LinkedHashMap<Integer, String> qqs = new LinkedHashMap<Integer, String>(); static{ qqs.put(10001, "张三"); qqs.put(10002, "李四&q

  • express框架实现基于Websocket建立的简易聊天室

    最近想写点有意思的,所以整了个这个简单的不太美观的小玩意 首先你得确认你的电脑装了node,然后就可以按照步骤 搞事情了~~ 1.建立一个文件夹 2.清空当前文件夹地址栏,在文件夹地址栏中输入cmd.exe 3.我们需要下载点小东西 ,需要在命令行输入 npm install express 回车 等待一会 npm install express-session 回车 等待一会 npm install ejs 回车 等待一会 npm install socket.io 回车 等待一会 叮~~~

  • java使用websocket,并且获取HttpSession 源码分析(推荐)

    一:本文使用范围 此文不仅仅局限于spring boot,普通的spring工程,甚至是servlet工程,都是一样的,只不过配置一些监听器的方法不同而已. 本文经过作者实践,确认完美运行. 二:Spring boot使用websocket 2.1:依赖包 websocket本身是servlet容器所提供的服务,所以需要在web容器中运行,像我们所使用的tomcat,当然,spring boot中已经内嵌了tomcat. websocket遵循了javaee规范,所以需要引入javaee的包 <

  • 详解spring boot实现websocket

    前言 QQ这类即时通讯工具多数是以桌面应用的方式存在.在没有websocket出现之前,如果开发一个网页版的即时通讯应用,则需要定时刷新页面或定时调用ajax请求,这无疑会加大服务器的负载和增加了客户端的流量.而websocket的出现,则完美的解决了这些问题. spring boot对websocket进行了封装,这对实现一个websocket网页即时通讯应用来说,变得非常简单.  一.准备工作 pom.xml引入 <dependency> <groupId>org.spring

  • java 在Jetty9中使用HttpSessionListener和Filter

    java 在Jetty9中使用HttpSessionListener和Filter HttpSessionListener 当Session创建或销毁的时候被调用 示例代码: class MyHttpSessionListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent httpSessionEvent) { System.out.println("session

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

    表单的重复提交 重复提交的情况: ①. 在表单提交到一个 Servlet,而 Servlet 又通过请求转发的方式响应了一个 JSP(HTML)页面,此时地址栏还保留着 Servlet 的那个路径,在响应页面点击 "刷新". ②. 在响应页面没有到达时,重复点击 "提交按钮" ③. 点击返回,再点击提交 不是重复提交的情况:点击 "返回","刷新" 原表单页面,再点击提交. 如何避免表单的重复提交:在表单中做一个标记,提交到

  • php中如何防止表单的重复提交

    复制代码 代码如下: <?php/* * php中如何防止表单的重复提交 */session_start();if (empty($_SESSION['ip'])) {//第一次写入操作,判断是否记录了IP地址,以此知道是否要写入数据库    $_SESSION['ip'] = $_SERVER['REMOTE_ADDR']; //第一次写入,为后面刷新或后退的判断做个铺垫    //...........//写入数据库操作} else {//已经有第一次写入后的操作,也就不再写入数据库   

  • JavaWeb 中Cookie实现记住密码的功能示例

    本文主要内容: •1.什么是Cookie •2.Cookie带来的好处 •3.Cookie的主要方法 一.什么是Cookie cookie是一种WEB服务器通过浏览器在访问者的硬盘上存储信息的手段.Cookie的目的就是为用户带来方便,为网站带来增值.虽然有着许多误传,事实上Cookie并不会造成严重的安全威胁.Cookie永远不会以任何方式执行,因此也不会带来病毒或攻击你的系统.另外,由于浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为

  • jQuery UI Dialog控件中的表单无法正常提交的解决方法

    最近使用jQuery UI的Dialog控件时发现如果在此控件放置表单,则所有表单均无法正常提交,具体表现为: 1.提交按钮失效,点击后无任何反应. 2.即便是使用其它手段使页面产生提交,服务器端也无法取到Dialog中的表单数据. 研究了页面源码后发现,jQuery UI Dialog控件初始化时动态生成的HTML元素被添加到页面的尾部.form元素的后面,而原始的Dialog模板部分(其内包含表单元素)也被移到了 动态生成的HTML元素内.也就是说,原先在form内的表单在Dialog初始化

  • Yii框架中jquery表单验证插件用法示例

    本文实例讲述了Yii框架中jquery表单验证插件用法.分享给大家供大家参考,具体如下: 运行效果图如下: 视图层: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtm

  • IE 下Enter提交表单存在重复提交问题的解决方法

    在submit()后加个return false就可以了.如: 复制代码 代码如下: document.formname.submit(); return false; 以后要注意了 后面尝试了另一种方法: 复制代码 代码如下: if ($("#formid").validationEngine("validate")){ document.getElementById("formid").submit(); } 也是可以的

  • Laravel中表单size验证数字示例详解

    前言 要验证一个数字的确定值,看了表单验证文档 size:value验证的字段必须具有与给定值匹配的大小.对于字符串来说,value 对应于字符数.对于数字来说,value 对应于给定的整数值.对于数组来说, size 对应的是数组的 count 值.对文件来说,size 对应的是文件大小(单位 kb ). 写的验证规则是这样的 $data = ['age' => 9]; $validator = \Illuminate\Support\Facades\Validator::make($data

  • asp.net页面防止重复提交示例分享

    先放javascript代码: 复制代码 代码如下: <script type="text/javascript">        var clicks = 0;        function checkclick(obj) {            clicks = clicks + 1;            if (clicks>1) {                alert("请勿重复点击!");                ret

  • 浅谈利用Session防止表单重复提交

    解决项目中表单重复提交的问题,在平常的项目中有以下几种可能出现表单重复提交的情况,比如说: 1.由于服务器缓慢或者网络延迟的原因,重复点击提交按钮 2.已经提交成功,但是还不停刷新成功页面 3.已经提交成功,通过回退,再次点击提交按钮. 这些情况都可能使数据库中产生过多相同的冗余数据,浪费数据库资源.只有转发才会出现,重定向则不会. 针对第一种情况的解决方案(使用JavaScript),对后面两种无效: 首先在页面中添加如下格式的JavaScript代码 var submitFlag=false

  • 在ASP应用程序中限制重复提交同一表单

    在Internet上我们每天都会遇到数不清的表单,也看到其中大部分并没有限制用户多次提交同一个表 单.缺乏这种限制有时候会产生某些预料不到的结果,如重复订阅邮件服务或重复投票等.或许一些 asp初学者并不清楚在asp应用中如何限制重复提交同一表单,所以在这里向大家介绍在ASP应用中防止 用户在当前会话期间多次提交同一表单的一个简单方法. 这个工作主要由四个子程序组成,在较为简单的应用场合,你只要将这些代码放在包含文件中直 接引用即可:对于那些较为复杂的环境,我们在文章的最后给出一些改进建议. 一

随机推荐