防重复提交(注解+AOP)
恶意请求,服务有瓶颈、复杂业务等!
让某个接口某个人(ip)在某段时间内只能请求N次。
在项目中比较常见的问题也有,那就是连点按钮导致请求多次。
全部由后端来控制,大致方案有使用拦截器、过滤器、切面。
某些场景幂等性。
大致思路:请求的时候,服务器通过redis 记录下你请求信息。
在redis 保存的key 是有时效性的,过期就会删除。
示例注解+AOP方式的防刷实现
第一步:定义防刷注解、启动类开启切面支持、pom引入依赖
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestRepeatAnnotation {//允许访问的次数,默认值MAX_VALUEint count() default Integer.MAX_VALUE;// 时间段,单位为毫秒,默认值一分钟long time() default 60000;
}
第二步:定义切面和防刷逻辑实现
/*** 请求重复拦截* * @author Be.insighted**/
@Aspect
@Component
public class RequestRepeatAspect {private static final Logger logger = LoggerFactory.getLogger(RequestRepeatAspect.class);@Autowiredprivate CacheManager cacheManager;// 接口超时时间为5s 可以配置在配置文件里private static final int DEFAULT_EXPIRE_TIME = 5;private static final String LOCK_TITLE = "biz_Lock_";@Pointcut("@annotation(cn.ccccltd.smp.interceptor.ann.RequestRepeatAnnotation)")private void requestRepeatCheck() {}@Around(value = "requestRepeatCheck()")public Object excute(ProceedingJoinPoint pjp) throws Throwable {Signature signature = pjp.getSignature();// String className = pjp.getTarget().getClass().getName();String method = signature.getName();MethodSignature methodSignature = (MethodSignature) signature;Method targetMethod = methodSignature.getMethod();if (targetMethod.isAnnotationPresent(RequestRepeatAnnotation.class)) {Object[] objects = pjp.getArgs();for (int i = 0; i < objects.length; i++) {Object item = objects[i];if (item != null && item instanceof ReqInfo) {ReqInfo tmp = (ReqInfo) item;String agentId = tmp.getAgentId();
// String jsonStr = JSONObject.toJSONString(tmp);logger.info("RequestRepeatAspect------->method:{},agentId:{}", method, agentId);
// key->value=当前时间long timestamp = System.currentTimeMillis();
// 获取redis key 的组成String redisKeyCode= getCode(tmp);String key = targetMethod.getName() + "_" + redisKeyCode+ "_" + agentId ;boolean flag = lock(key, timestamp);if (flag) {throw new BusinessException("重复提交,稍后再试");}break;}}}return pjp.proceed();}/*** 根据注解,获取请求参数,根据参数类型获取响应的合同编码,将合同编码作为redis 的key,* 如果请求类型非注解这几种,redisKey 为请求参数所有属性序列化值* @param item* @return*/private String getCode(Req item) {if (item == null) {return "";}String key="";try {key=item.getUserId()+":token:"+item.getUserToken();
// key= JSONObject.toJSONString(item);} catch (Exception e) {e.printStackTrace();throw new BusinessException("请求参数未填写");}logger.info("RequestRepeatAspect 获取Code------->getCode:{}",key);return key;}/*** 锁定redis* * @param key* @param value* @return*/private boolean lock(String key, long value) {// 获取redis keybyte[] redisKey = getRedisKeys(key);byte[] existsValue = cacheManager.get(redisKey);// redis 超时时间long expireTime = value;if (existsValue != null) {expireTime = (Long) SerializeUtils.unSerializeAndGunzip(existsValue, Long.class);}logger.info("lock--->key:{},existsValue:{},value-expireTime:{}",SerializeUtils.unSerializeAndGunzip(redisKey, String.class), value, value - expireTime);// key 超时if (value - expireTime > DEFAULT_EXPIRE_TIME * 60 * 1000) {logger.info("lock redis key 超时:--->key:{},expireTime:{}",SerializeUtils.unSerializeAndGunzip(redisKey, String.class), expireTime);// 移出redis key 信息cacheManager.del(redisKey);}Long existsFlag = cacheManager.setnx(redisKey, SerializeUtils.serializeAndGzip(value));logger.info("lock--->existsFlag:{}", existsFlag);if (existsFlag == 1) {cacheManager.setValueExpireTime(redisKey, DEFAULT_EXPIRE_TIME);return false;} else {return true;}}/*** 获取redis key* * @param key* @return*/private static byte[] getRedisKeys(String key) {key = StringUtils.isEmpty(key) ? "" : key;key = LOCK_TITLE + key;return SerializeUtils.serializeAndGzip(key);}}
实现方式二:
注解+拦截器https://blog.csdn.net/Be_insighted/article/details/119085723?spm=1001.2014.3001.5502
防重复提交(注解+AOP)相关推荐
- redis+aop防重复提交
文章目录 1.防重复提交注解 2.redis分布式锁 3.防止重复提交Aop 之前有记录一篇用redis+拦截器防重复提交的内容: redis+拦截器防重复提交 1.防重复提交注解 @Target(E ...
- springBoot防重复提交
一.重复提交原因 由于客户端抖动,人为快速点击,造成服务器重复处理 二.后端防重复提交 1.基于token 访问请求到达服务器,服务器端生成token,分别保存在客户端和服务器.提交请求到达服务器,服 ...
- Java实现防重复提交
欢迎访问我的个人博客:www.ifueen.com 防重复提交的重要性? 在业务开发中,为什么我们要去想办法解决重复提交这一问题发生?网上的概念很多:导致表单重复提交,造成数据重复,增加服务器负载,严 ...
- 工作中的亮点事情-防重复提交
防重复提交(aop): 1.自定义注解,在需要防重的接口添加注解,默认时间200毫秒 2.url+sessionId +关键字 为主键设置一个缓存,存在则直接返回错误信息 定义redis锁 切面.切点 ...
- AOP+自定义注解token令牌和参数防重复提交实战
目录 一.哪些因素会引起重复提交? 二.重复提交会带来哪些问题? 三.订单的防重复提交你能想到几种方案? 四.自定义注解方式 4.1Java核心知识-自定义注解(先了解下什么是自定义注解) 4.1.1 ...
- Spring MVC表单防重复提交
转载自 Spring MVC表单防重复提交 利用Spring MVC的过滤器及token传递验证来实现表单防重复提交. 创建注解 @Target(ElementType.METHOD) @Retent ...
- 架构设计 | 接口幂等性原则,防重复提交Token管理
本文源码:GitHub·点这里 || GitEE·点这里 一.幂等性概念 1.幂等简介 编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同.就是说,一次和多次请求某一个资源会产 ...
- Java的token解决方案,SpringMVC后台token防重复提交解决方案
思路1.添加拦截器,拦截需要防重复提交的请求 2.通过注解@Token来添加token/移除token 3.前端页面表单添加(如果是Ajax请求则需要在请求的json数据中添加token值) 核 ...
- 防止跨站请求伪造(CSRF)攻击 和 防重复提交 的方法的实现
CSRF的概念可以参考:http://netsecurity.51cto.com/art/200812/102951.htm 本文介绍的是基于spring拦截器的Spring MVC实现 首先配置拦截 ...
- java后端 防重复提交_后台防止表单重复提交
具体的做法: 1.获取用户填写用户名和密码的页面时向后台发送一次请求,这时后台会生成唯一的随机标识号,专业术语称为Token(令牌). 2.将Token发送到客户端的Form表单中,在Form表单中使 ...
最新文章
- 一个经典例子让你彻彻底底理解java回调机制
- 云计算 java go c_面向对象编程的面向过程表示:c java go
- canvas 中的元素拖拽
- 16年寒假随笔(2)
- iOS Storyboard创建APP 的国际化操作
- android模拟手指滑动,Android Accessibility 模拟界面滑动
- what should you do if you want to become an expert in one domain
- 【小白学习PyTorch教程】三、Pytorch中的NN模块并实现第一个神经网络模型
- Java设置软件图标即窗口上角图标
- final const java_Java中的final关键字 与 C#中的const, readonly关键字
- 为啥 .NET 自带的 JsonSerializer 无法序列化 Field ?
- GIL对多线程的影响
- PowerShell实现“机器人定时在企业微信群中发送消息”功能(上)
- Vue快速上手笔记2 - 开发环境的搭建
- HRBEU 字符串 1003
- define语句换行\后不能有空格
- java语言数据库课程设计_数据库课程设计 人事管理系统 (一)
- latex图像注释位置
- 贵州省计算机职称考试时间2015年,关于2015年8月份贵州贵阳职称计算机考试安排通知...
- Xcode8 及 iOS 10 的适配