SSM框架防止重复请求

编者: wRitchie(吴理琪) 来源:http://www.bj9420.com

SSM框架,即Spring+Spring MVC+Mybatis,在实践中由于网络延迟或多次点击提交等原因产生一个请求发送多次的情况,实际上,第一个请求才是客户端发送的,后面的请求对客户端并无意义。比如,客户端发送了三次保存的请求,实际上,客户端只想保存一条记录,而服务端却保存了三条,这导致重复数据,并且这些数据会对系统造成不必要的影响。另一种典型场景,用户提现,如重复提交,会导致多次提现,会带来巨大的经济损失,为了防止此类情况发生,需解决重复提交表单,解决方式思路,验证同一个URL及数据参数是否相同,如相同,则重复提交,否则,正常提交。

SSM框架后端解决

1、 自定义防止重复的注解

1. package com.bj9420.framework.interceptor;  2.   3. import java.lang.annotation.ElementType;  4. import java.lang.annotation.Retention;  5. import java.lang.annotation.RetentionPolicy;  6. import java.lang.annotation.Target;  7.   8. /** 9.  * @author :wRitchie 10.  * @Description :自定义防止重复的注解 11.  * @Title :PreventRepeat.java 12.  * @date 2020/12/7 13:45 13.  * @Version :V1.0 14.  * @Copyright (c):http://www.bj9420.com 2020 All rights reserved. 15.  */  16. @Target(ElementType.METHOD)  17. @Retention(RetentionPolicy.RUNTIME)  18. public @interface PreventRepeat {  19. }  

2、 自定义拦截器

1. package com.bj9420.framework.interceptor;  2.   3. import com.fasterxml.jackson.databind.ObjectMapper;  4. import lombok.extern.slf4j.Slf4j;  5. import org.springframework.web.method.HandlerMethod;  6. import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;  7.   8. import javax.servlet.http.HttpServletRequest;  9. import javax.servlet.http.HttpServletResponse;  10. import java.lang.reflect.Method;  11. import java.util.HashMap;  12. import java.util.Map;  13.   14. /** 15.  * @author :wRitchie 16.  * @Description :相同url和数据拦截器 为了防止重复提交等操作 17.  * 继承拦截器适配器 18.  * @Title :RepeatUrlDataInterceptor.java 19.  * @date 2020/12/7 13:47 20.  * @Version :V1.0 21.  * @Copyright (c):http://www.bj9420.com 2020 All rights reserved. 22.  */  23. @Slf4j  24. public class RepeatUrlDataInterceptor extends HandlerInterceptorAdapter {  25.     /** 26.      * @Author: wRitchie 27.      * @Description: preHandle  覆盖父类的preHandle方法 28.      * 预处理回调方法,实现处理器的预处理,验证是否为重复提交,第三个参数为响应的处理器,自定义Controller 29.      * 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应; 30.      * @Param: [request, response, handler] 31.      * @return: boolean 32.      * @Date: 2020/12/7 13:54 33.      */  34.     @Override  35.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  36.         // 1、判断handler参数是否为HandlerMethod类的实例  37.         if (handler instanceof HandlerMethod) {  38.             // 2、获取方法注解查看方式是否有PreventRepeat注解  39.             HandlerMethod handlerMethod = (HandlerMethod) handler;  40.             Method method = handlerMethod.getMethod();  41.             PreventRepeat annotation = method.getAnnotation(PreventRepeat.class);  42.             if (annotation != null) {  43.                 // 3、 调用重复数据验证方法  44.                 boolean result = repeatDataValidator(request);  45.                 if (result) {                        //重复提交,返回JSON信息                          response.setCharacterEncoding("UTF-8");                          response.setContentType("application/json;charset=utf-8");                          PrintWriter out=response.getWriter();                          JSONObject jsonObject = new JSONObject();                          jsonObject.put( "msgcode", SystemConstant.MSG_CODE_FAIL);                          jsonObject.put( "message", "请不要重复提交。");                          out.append(jsonObject.toString());                          out.flush();                          out.close();  //解决初次发布时,未返回给客户端信息46.                     return false;  47.                 } else {  48.                     return true;  49.                 }  50.             } else {  51.                 return true;  52.             }  53.         } else {  54.             // 4. 如果参数不是HandlerMethod类的实例,则调用父类的preHandle方法  55.             return super.preHandle(request, response, handler);  56.         }  57.     }  58.   59.   60.     /** 61.      * @Author: wRitchie 62.      * @Description: repeatDataValidator 验证请求的url+请求数据参数提交是否相同 63.      * 相同返回true,表示重复请求;否则返回false,表示不是重复提交 64.      * @Param: [httpServletRequest] 65.      * @return: boolean 66.      * @Date: 2020/12/7 13:53 67.      */  68.     public boolean repeatDataValidator(HttpServletRequest httpServletRequest) {  69.         try {  70.             // 1、将url+请求数据参数转换为json字符串,需pom内引用jackson-databind  71.             ObjectMapper objectMapper = new ObjectMapper();  72.             String params = objectMapper.writeValueAsString(httpServletRequest.getParameterMap());  73.             // 2、 获取当前请求的url地址,以url为key,请求数据参数为值存在map里  74.             String url = httpServletRequest.getRequestURI();  75.             Map map = new HashMap(4);  76.             map.put(url, params);  77.             String curUrlData = map.toString();  78.             log.info("**** curUrlData:"+curUrlData);  79.             // 3、从session中获取上一次请求存储的url和请求数据参数字符串  80.             Object preUrlData = httpServletRequest.getSession().getAttribute("preUrlData");  81.             // 4、若上次请求的url+数据为null,则表示尚未访问的页面,将当前请求的url+请求数据参数存储到session中  82.             if (preUrlData == null) {  83.                 httpServletRequest.getSession().setAttribute("preUrlData", curUrlData);  84.                 return false;  85.             } else {  86.                 // 5、若上次访问的url+请求数据参数与本次url+请求数据参数相同,则表示重复提交  87.                 if (preUrlData.toString().equals(curUrlData)) {  88.                     return true;  89.                 } else {  90.                     //6、若上次访问的url+请求数据参数和本次url+请求数据参数不同,则不是重复提交  91.                     httpServletRequest.getSession().setAttribute("preUrlData", curUrlData);  92.                     return false;  93.                 }  94.             }  95.         } catch (Exception e) {  96.             log.info("验证是否为重复请求异常。");  97.             return false;  98.         }  99.     }  100. }  

3、 Spring MVC 配置文件中添加配置

1.   2.       3.           4.               5.               6.               7.               8.           9.       

4、 使用方法,在Controller类的方法上,增加@PreventRepeat注解

1. /** 2.    * @Author: wRitchie 3.    * @Description: withdraw 提现 4.    * @Param: [type, userId,account,payType] 5.    * @return: com.bj9420.model.Result> 6.    * @Date: 2020-12-07 15:15 7.    */  8.    @RequestMapping("/withdraw")  9.    @ResponseBody  10.    @PreventRepeat  11.    public Result> withdraw(String type,String userId,String account,String payType) {  12.        //提现代码   13.        ......  14.   15.    }  

这样,基本实现了防止重复请求,但拦截器的方式需要优化的是将拦截重复请求的返回给请求端,目前的方式,只是不处理,没有返回信息。

附:补正未返回给客户端信息,2020-12-08

将拦截重复请求的返回给请求端,返回JSON信息,内容可根据自身需要而编写,代码发下:

                         //重复提交,返回JSON信息                          response.setCharacterEncoding("UTF-8");                          response.setContentType("application/json;charset=utf-8");                          PrintWriter out=response.getWriter();                          //PrintWriter out=new PrintWriter(response.getWriter());                          JSONObject jsonObject = new JSONObject();                          jsonObject.put( "msgcode", SystemConstant.MSG_CODE_FAIL);                          jsonObject.put( "message", "请不要重复提交。");                          out.append(jsonObject.toString());                          out.flush();                          out.close();  //解决初次发布时,未返回给客户端信息

重复提交时:

处理返回信息后,以拦截器的方式,SSM框架完美实现防止重复请求。

handlerinterceptoradapter 获取请求参数_SSM框架防止重复请求相关推荐

  1. SpringMVC的请求参数,类型转换器(日期格式),请求映射

    SpringMVC的请求参数,类型转换器(日期格式),请求映射 请求参数 springMVC将传递的参数封装到处理的方法形参中,达到快速访问参数的目的 普通参数类型 参数名与处理器方法形参名保持一致 ...

  2. java客户端重复请求_Java后台防止客户端重复请求、提交表单实现原理

    Java后台防止客户端重复请求.提交表单实现原理 发布于 2021-1-8| 复制链接 摘记: 这篇文章主要介绍了Java后台防止客户端重复请求.提交表单实现原理,文中通过示例代码介绍的非常详细,对大 ...

  3. Java发送Http请求之——发送请求参数在Body中Get请求

    1.背景要求 发送Get请求,但是请求参数要放在请求body内,所以经过多方查证后整理出来以下代码. 2.POM依赖 <dependency><groupId>org.apac ...

  4. c++ post请求_Golang GinWeb框架5绑定请求字符串/URI/请求头/复选框/表单类型

    简介 本文接着上文(Golang GinWeb框架4-请求参数绑定和验证)继续探索GinWeb框架 只绑定查询字符串 使用SholdBindQuery方法只绑定查询参数, 而不会绑定post的数据. ...

  5. python request请求参数_使用python将请求的requests headers参数格式化方法

    如下所示: import json # 使用三引号将浏览器复制出来的requests headers参数赋值给一个变量 headers = """ Host: zhan. ...

  6. vue 请求参数数组_vue中get请求如何传递数组参数

    前言: vue中在与后端进行数据交互时,使用axios发送请求,不做配置直接使用get请求传递数组类型参数的时候,后端是无法接收数据的,需要对axios一些简单的配置才能让后端完美的接收数组 1.问题 ...

  7. python post请求参数错误_python爬虫 post请求 参数错误

    [Python] 纯文本查看 复制代码#!/usr/bin/env python # -*- coding: utf-8 -*- import requests def test_request(): ...

  8. 设置公共请求参数_基于分布式锁的防止重复请求解决方案(值得收藏)

    关于重复请求,指的是我们服务端接收到很短的时间内的多个相同内容的重复请求.而这样的重复请求如果是幂等的(每次请求的结果都相同,如查询请求),那其实对于我们没有什么影响,但如果是非幂等的(每次请求都会对 ...

  9. SpringMVC框架 学习DAY_02 : 接收请求参数/向模板页面转发数据/重定向与转发 /Session

    1. 接收客户端提交的请求参数 1.1. 使用HttpServletRequest接收请求参数 在处理请求的方法的参数列表中,添加HttpServletRequest类型的参数,在处理请求的过程中,调 ...

最新文章

  1. python-正则表达式练习题
  2. Android布局管理器-从实例入手学习相对布局管理器的使用
  3. PyTorch机器学习从入门到实战
  4. 安装archlinux_archlinux/manjaro 上安装percona-server
  5. openresty配置部署
  6. 微软官宣:史上最贵开发工具 75亿美金收购GitHub
  7. Taro+react开发(20)--控制icon大小
  8. PRML-系列一之1.3~1.4
  9. python网络编程基础语法_python网络编程
  10. Atitit SpringCache缓存使用 艾提拉 attilax总结 1. Spring的抽象已经做得够好了,适合于大多数场景,非常复杂的就需要自己AOP实现了。 1 1.1. 设置配置文件支持
  11. python数据分析收获与心得体会_初次数据分析--我的心得体会
  12. 【天线】【2】一些名词和简单概念的解释,仍然
  13. 如何评价导师评价网?
  14. java获取oracle自增_Oracle自增列创建方法
  15. 加解密QQ旋风和迅雷链接地址
  16. 配置项目外网访问(公网IP+DDNS)
  17. 7_使用OGR模块操作矢量数据
  18. 什么是即时消息(IM)?
  19. Tomcat 报异常org.apache.catalina.core.standardwrappervalve invoke
  20. 【正点原子STM32连载】第四十七章 汉字显示实验 摘自【正点原子】MiniPro STM32H750 开发指南_V1.1

热门文章

  1. jsonProperty
  2. Linux--DHCP
  3. [数据库事务与锁]详解一: 彻底理解数据库事务
  4. 跨境电商Crazysales的高稳定性架构实践
  5. linux指令 find指令详解
  6. Struts2核心工作原理解析
  7. asp.net C# 将数据导出到Execl汇总
  8. 简单的家庭无线路由设置
  9. HtmlUnit动态执行js函数
  10. 算法导论之有关数论的算法