一、问题:项目中有一些重复操作的情况,比如:

1.从场景有用户快速点击提交按钮,或者postMan测试时快速点击

2.从业务上来说,用户注册、用户下单等

3.黑客攻击

二、解决办法

1、使用springAop、Redis

2、代码

/**
* 2020/7/22 9:59 AM
*
* @author shoo
* @describe 校验重复操作 (aop实现)
*/
@Aspect
@Component
public class ParaLogAspect { private static final Logger logger = LoggerFactory.getLogger(ParaLogAspect.class); @Autowired
private RedisTemplate<String, Object> redisTemplate; //定义一个切点,要切的类、方法
@Pointcut("execution(* com.meritdata.cloud.middleplatform.dataservice.account.integral.controller.*.*(..))" +
"||execution(* com.meritdata.cloud.middleplatform.dataservice.account.platformBase.controller.*.*(..))" +
"||execution(* com.meritdata.cloud.middleplatform.dataservice.account.storeConsume.controller.*.*(..))" +
"||execution(* com.meritdata.cloud.middleplatform.dataservice.account.vipcard.controller.*.*(..))" +
"||execution(* com.meritdata.cloud.middleplatform.dataservice.shell.controller.*.*(..))")
public void authRepeat(){ } @Around("authRepeat()")
public Object authRepeat(ProceedingJoinPoint joinPoint) throws Throwable{ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
StringBuffer body = new StringBuffer();
Object[] arguments = joinPoint.getArgs();
//获取方法的参数
//注意这里只取了第一个参数,如果想兼容多个参数的方法请自行处理
if(arguments.length!=0){
try {
Map<String, Object> params = params = (Map<String, Object>)arguments[0];
for (String key:params.keySet()
) {
body.append(key).append("=").append(params.get(key)).append("&");
} }catch (Exception ex){
logger.info("=====方法接收参数[{}]",arguments[0].toString());
}
}
// key:请求者IP+请求URL+参数
String key = request.getRemoteAddr() + ";" + request.getRequestURL().toString() + "?" + body.toString();
logger.info("====key[{}]",key.substring(0,key.length()-1)); Object obj = null;
Object[] args = joinPoint.getArgs();
//重复提交校验
if(!authRepeat(key)){
logger.info("重复提交,key[{}]",key);
return MapResult.build("请勿频繁操作",false);
}
//不是重复提交则继续主进程
try {
obj = joinPoint.proceed(args);
} catch (Throwable e) {
logger.error("重复操作校验环绕通知出错", e);
}
return obj;
} //重复提交校验
// Redis的increment方法:把key的值加上指定数值,如果key不存在则默认创建,该操作是单线程的
private boolean authRepeat(String key){ long repeat = redisTemplate.opsForValue().increment(key,1);
logger.info("repeat:[{}]",repeat);
if(repeat>1){
return false;
}
redisTemplate.expire(key,1, TimeUnit.SECONDS);
return true;
}
}

3.说明

a、首先用springAop切入需要校验的类或者方法,这里用的是环绕通知(around),如果一秒内操作次数超过一次则返回错误提示请勿频繁操作

b、校验规则是 请求者IP+请求URL+方法参数

c、Redis的increment是单线程的原子操作

三、测试

用locust启动十个用户同时访问用户注册接口,数据库中只注册成功了一个数据,剩余的都提示请勿频繁操作

spring aop 、Redis实现拦截重复操作的更多相关文章

  1. 今日份学习:写一些代码 (Spring+AOP+Redis+MySQL练习)

    笔记 Spring+AOP+Redis+MySQL练习 1. 启动docker->mysql docker run --name mysql -v e:\docker:/var/lib/mysq ...

  2. TinyFrame再续篇:整合Spring AOP实现日志拦截

    上一篇中主要讲解了如何使用Spring IOC实现依赖注入的.但是操作的时候,有个很明显的问题没有解决,就是日志记录问题.如果手动添加,上百个上千个操作,每个操作都要写一遍WriteLog方法,工作量 ...

  3. Spring AOP原理及拦截器

    原理 AOP(Aspect Oriented Programming),也就是面向方面编程的技术.AOP基于IoC基础,是对OOP的有益补充. AOP将应用系统分为两部分,核心业务逻辑(Core bu ...

  4. Spring aop 实现异常拦截

    使用aop异常挂载功能可以统一处理方法抛出的异常,减少很多重复代码,实现如下: 1.实现ThrowAdvice public class ExceptionHandler implements Thr ...

  5. 从零开始学 Java - Spring AOP 拦截器的基本实现

    一个程序猿在梦中解决的 Bug 没有人是不做梦的,在所有梦的排行中,白日梦最令人伤感.不知道身为程序猿的大家,有没有睡了一觉,然后在梦中把睡之前代码中怎么也搞不定的 Bug 给解决的经历?反正我是有过 ...

  6. Java - Spring AOP 拦截器的基本实现

    一个程序猿在梦中解决的 Bug 没有人是不做梦的,在所有梦的排行中,白日梦最令人伤感.不知道身为程序猿的大家,有没有睡了一觉,然后在梦中把睡之前代码中怎么也搞不定的 Bug 给解决的经历?反正我是有过 ...

  7. Spring学习总结(15)——Spring AOP 拦截器的基本实现

    一个程序猿在梦中解决的 Bug 没有人是不做梦的,在所有梦的排行中,白日梦最令人伤感.不知道身为程序猿的大家,有没有睡了一觉,然后在梦中把睡之前代码中怎么也搞不定的 Bug 给解决的经历?反正我是有过 ...

  8. Spring AOP无法拦截内部方法调用

    当在同一个类中,A方法调用B方法时,AOP无法工作的问题 假设一个接口里面有两个方法: package demo.long; public interface CustomerService { pu ...

  9. 【Spring AOP】AOP介绍(一)

    AOP(Aspect Oriented Programming) 面向切面编程,是Spring框架的一个重要组件. AOP应该算是对OOP(面向对象编程)的补充和完善.OOP引入封装.继承.多态等概念 ...

随机推荐

  1. win10安装linux子系统(wsl)

    win10安装linux子系统(wsl) 1.打开Microsoft Store 方式一:在电脑左下角打开 方式二:在电脑左下角的搜索里里输入Microsoft Store 打开Microsoft S ...

  2. [Luogu P2014]选课 (树形DP)

    题面 传送门:https://www.luogu.org/problemnew/show/P2014 Solution 这是一道十分经典的树形DP题,这种类型的树形DP有一种很普遍的解法. 首先,观察 ...

  3. 834. Sum of Distances in Tree —— weekly contest 84

    Sum of Distances in Tree An undirected, connected tree with N nodes labelled 0...N-1 and N-1 edges a ...

  4. 直播软件开发关于Android、iOS中的视频采集步骤

    很多人对直播软件开发还是抱有想法的,但是在这个资本冷静的市场下,直播平台该怎么玩,在直播软件开发过程中哪些功能是必须具备的,这都是值得关注的话题.今天我们给大家分享一份详细的直播软件开发关于Andro ...

  5. javascript-闭包【面试必备】

    闭包 定义:内层函数可以访问外层函数作用域的变量 意义/用途: 1.封装细节 2.实现模块化 3.常用实战li列表 // querySelectorAll es5支持的一个类似于jq的复杂选择器选取d ...

  6. mysql上月最后一天,当月最后一天

    select last_day(DATE_SUB(now(),INTERVAL 1 MONTH)) #上月最后一天日期 %Y-%m-%d select last_day(curdate()) #当月最 ...

  7. c语言 字符指针数组的用法

    #include <stdio.h> #include <stdlib.h> int main(){ //字符数组的使用 char str[] = {'z','b','c',' ...

  8. ceph的pg平衡插件balancer

    前言 ceph比较老的版本使用的reweight或者osd weight来调整平衡的,本篇介绍的是ceph新的自带的插件balancer的使用,官网有比较详细的操作手册可以查询 使用方法 查询插件的开 ...

  9. Linux_CentOS 7下Nginx服务器的安装配置

    1.安装 1.1 配置epel yum 源 wget http://dl.Fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm rpm ...

  10. Distributing Custom Apps

    Distributing Custom Apps 分配自定义应用程序 November 10, 2020 2020年11月10日 Custom apps let you meet the unique ...