javaWeb应用后端防止表单重复提交

正常我们防止一个页面的表单重复提交有2种途径
1:客户端控制(比如js判断,按钮置灰不可用等等这个大家自行网上查询)

2:服务器端针对api自己多业务逻辑判断

实际使用的场景中,我们大多是2者结合起来做,不能把所有的判断逻辑都扔到服务器端,这对服务器端也是一种压力,能再客户端做一层拦截的,尽量先在客户端做掉。

客户端分别是基于两种方式实现:redis和session,个人倾向于redis

----------------------------------------------------------------------分割线------------redis版----------------------------------------------------------

1:redis方式,直接贴代码

    private static String FORMTOKE = "form_token";
    @Autowired
    @Qualifier("forObject")
    private RedisTemplate redisTemplate;
    
    /**
     * 基于redis的放置表单重复提交的demo
     * */
    @RequestMapping("/testRedisform")
    public String index(HttpServletRequest request) {
        String formToken = UUID.randomUUID().toString();//创建令牌
        
        System.out.println("在FormServlet中生成的formToken:" + formToken);
        
        // 使用redis来存储这个 令牌
        redisTemplate.opsForValue().set(FORMTOKE, formToken);
        
       
//由于我这里的项目不是前后端分离的, 这里仍然借助session 把值方法页面上。当然前后端分离的情况下,这个值,直接可以通过返回值的dto 返回给客户端,无须用到seesion,客户端拿到放到页面的隐藏域里保存起来
        request.getSession().setAttribute("formToken", formToken); 

        return "testForm";
    }
    /**
     * 第二步 对提交过来的表单进行验证
     * */
    @RequestMapping("/vaRedisSubmiit")
    public String vaSubmiit(HttpServletRequest request) {
        boolean b = isRepeatSubmit(request);//判断用户是否是重复提交
        if(b==true){
            System.out.println("请不要重复提交--跳转一个提示的页面提示不允许重复提交");
            return "cfSumiit";
        }
        //------doSomeThing---处理允许提交的逻辑------
        // 处理完毕之后,一定记得要在redis里移除这个key值,不然就发生重复提交了
        redisTemplate.delete(FORMTOKE); //移除redis中的token
        System.out.println("否则提示成功---处理用户提交请求!!--比如跳转到提交成功的页面");
        return "formSucc";
    }
    /**
     * 判断客户端提交上来的令牌和服务器端生成的令牌是否一致
     * @param request
     * @return 
     *         true 用户重复提交了表单 
     *         false 用户没有重复提交表单
     */
    private boolean isRepeatSubmit(HttpServletRequest request) {
        String client_token = request.getParameter("formToken");
        //1、如果用户提交的表单数据中没有token,则用户是重复提交了表单
        if(client_token==null){
            return true;
        }
        //取出存储在redis中的token
        String server_token = (String) redisTemplate.opsForValue().get(FORMTOKE);
        //2、如果redis里的中不存在Token(令牌),则用户是重复提交了表单
        if(server_token==null){
            return true;
        }
        //3、存储在Session中的Token(令牌)与表单提交的Token(令牌)不同,则用户是重复提交了表单
        if(!client_token.equals(server_token)){
            return true;
        }
        return false;
    }

// jsp的代码我就不贴了,类似下面的session,后面的我把代码直接放到github上,大家如果需要自行下载

----------------------------------------------------------------------分割线------------session版----------------------------------------------------------

2:seesion方式,直接贴代码

/**
     * 第一步在跳转到保存的表单界面的时候 先生成toke
     * 放到session里存储起来,用于后面的表单提交的时候,做比对,同时这个值要放到页面的隐藏域上
     * 下次提交表单的时候把这个隐藏域里的值也必须一起提交过来
     * 这个放到session里是否可以考虑用redis里扩展?因为在分布式的情况下,还要考虑分布式的seeson
     * */
    @RequestMapping("/testform")
    public String index(HttpServletRequest request) {
        String formToken = UUID.randomUUID().toString();//创建令牌
        System.out.println("在FormServlet中生成的token:" + formToken);
        request.getSession().setAttribute("formToken", formToken);  //在服务器使用session保存token(令牌)

        return "testForm";
    }

/**
     * 第二步 对提交过来的表单进行验证
     * */
    @RequestMapping("/vaSubmiit")
    public String vaSubmiit(HttpServletRequest request) {
        boolean b = isRepeatSubmit(request);//判断用户是否是重复提交
        if(b==true){
            System.out.println("请不要重复提交--跳转一个提示的页面提示不允许重复提交");
            return "cfSumiit";
        }
        //------doSomeThing---处理允许提交的逻辑------
        // 处理完毕之后,一定记得要在session里移除这个key值,不然就发生重复提交了,关于这里,尽量考虑用redis来替换
        request.getSession().removeAttribute("token");//移除session中的token
        System.out.println("否则提示成功---处理用户提交请求!!--比如跳转到提交成功的页面");
        return "formSucc";
    }
    /**
     * 判断客户端提交上来的令牌和服务器端生成的令牌是否一致
     * @param request
     * @return 
     *         true 用户重复提交了表单 
     *         false 用户没有重复提交表单
     */
    private boolean isRepeatSubmit(HttpServletRequest request) {
        String client_token = request.getParameter("formToken");
        //1、如果用户提交的表单数据中没有token,则用户是重复提交了表单
        if(client_token==null){
            return true;
        }
        //取出存储在Session中的token
        String server_token = (String) request.getSession().getAttribute("formToken");
        //2、如果当前用户的Session中不存在Token(令牌),则用户是重复提交了表单
        if(server_token==null){
            return true;
        }
        //3、存储在Session中的Token(令牌)与表单提交的Token(令牌)不同,则用户是重复提交了表单
        if(!client_token.equals(server_token)){
            return true;
        }
        return false;
    }

// 下面贴出对应的jsp页面:


        <%--使用EL表达式取出存储在session中的token,实际情况下,请用 hidden属性 隐藏--%>
        
        
        userName:
        
   

整个源码下载地址:https://github.com/gitlyb2080/webFormVaDemo

启动之后:先访问:http://localhost:8080/testRedisform ,得到表单的提交页面

javaWeb应用后端防止表单重复提交_第1张图片

然后,点击 submmit

javaWeb应用后端防止表单重复提交_第2张图片

你可能感兴趣的:(java开发)