使用session在服务端防止表单重复提交

本文介绍一种利用Session和Token机制防止Web表单重复提交的方法。通过在客户端生成唯一Token,并将其存入Session,再通过表单提交验证客户端Token与Session中Token的一致性来确保表单不会被重复提交。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相较于在客户端使用js等方式防止用户重复点击或者通过别的方式重复提交表单,在服务端使用session防止表单重复提交更能解决问题。当然前后端结合使用会给用户更好的体验

这里写图片描述

思路:

1、获取一个独一无二的token(防止重复提交的key),我们这里使用一个自己封装好的方(TokenProccessor),把获取到的token加到session中。

2、新建form.jsp页面。使用servlet将token转发(必须是转发)到form表单页面,在页面上使用隐藏域的方式把后台传来的token放到form标签<input type="hidden" name="token" value="${token}">中,提交时随表单一起提交。

3、在后台分三种情况

3.1首先验证传来的token是否为空,为空的情况意思是用户没有通过正常的操作获取到表单,故表单中提交的token为空,这种情况我们认为不合法,此处return false处理。(防盗链也是这么搞得,这里就不细讲了,感兴趣的同学可以自己看看,结合本文,很容易就搞出来了)
3.2验证服务端中session里存的token是否为空(当第一次验证通过后会把session中的token清掉),为空说明已经提交过一次了,所以是重复提交,这里return false处理
3.3验证获取到的token是否与session中的token一致,一致则通过验证提交表单,同时清掉session里的token。下面该干嘛干嘛。不一致的情况就不聊了

思路理清后,下面上代码,顺序都一样的哦。

目录结构
这里写图片描述

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <servlet>
        <servlet-name>formSession</servlet-name>
        <servlet-class>ser.david.useSessionFormRepeatDemo.FormSession</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>formSession</servlet-name>
        <url-pattern>/formSession</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>doformSession</servlet-name>
        <servlet-class>ser.david.useSessionFormRepeatDemo.DoFormServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>doformSession</servlet-name>
        <url-pattern>/doformSession</url-pattern>
    </servlet-mapping>
</web-app>

TokenProccessor.java 使用单例模式

package ser.david.useSessionFormRepeatDemo;

import sun.misc.BASE64Encoder;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

public class TokenProccessor {
    /*
    单例化
    1、构造方法私有
    2、自己创建自己对象
    3、对外暴露一个方法,可以获取上面自己创建的自己的对象
     */

    private TokenProccessor(){};
    private static final TokenProccessor instance=new TokenProccessor();
    public static TokenProccessor getInstance(){
        return instance;
    }


    public String generatetoken(){
        String token=System.currentTimeMillis()+new Random().nextInt()+"";

        try {
            MessageDigest md=MessageDigest.getInstance("md5");
            byte[] md5=md.digest(token.getBytes());
            //base64编码
            BASE64Encoder encoder=new BASE64Encoder();
            return encoder.encode(md5);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
}

FormSession.java

package ser.david.useSessionFormRepeatDemo;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


public class FormSession extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //产生随机数
        TokenProccessor tp=TokenProccessor.getInstance();
        String token=tp.generatetoken();

        request.getSession().setAttribute("token",token);
        request.getRequestDispatcher("/form.jsp").forward(request,response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

Form.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
  <form action="/doformSession" method="post">
      <input type="hidden" name="token" value="${token}">
      用户名:<input type="text" name="username"><br/>
      <input type="submit" value="提交">
  </form>
</body>
</html>

DoFormServlet.java

package ser.david.useSessionFormRepeatDemo;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//使用session在服务端防止表单重复提交
public class DoFormServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        boolean b=isTokenValid(request);
        if (!b){
            System.out.println("请不要重复提交");
            return;
        }

        request.getSession().removeAttribute("token");
        System.out.println("向数据库中注册数据。。。。。");
    }

    private boolean isTokenValid(HttpServletRequest request){
        String client_token =request.getParameter("token");

        if (client_token==null){
            return false;
        }

        String server_token=(String)request.getSession().getAttribute("token");
        if (server_token==null){
            return false;
        }

        if (!client_token.equals(server_token)){
            return false;
        }
        return true;
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

效果图:

1、访问/session,跳转到form.jsp页面、填写并提交
这里写图片描述
2、可以看到已经提交成功
这里写图片描述
3、刷新页面或者后退重新点击提交按钮,可以看到表单提交被拦截,后台输出提示信息
这里写图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值