自定义注解限制重复提交
最后更新于:2022-04-02 07:12:24
@author [ksf](https://blog.csdn.net/sinat_19528249)
处理的方式有两种,本次介绍普适性方案,解决问题1。
1.正常业务请求的防止限制
2.极端情况下的请求,rediskey过期带来的重复请求。
**代码结构比较清晰,直接贴代码啦:**
```java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface LimitSubmit {
String key() ;
/**
* 默认 10s
*/
int limit() default 10;
/**
* 请求完成后 是否一直等待
* true则等待
* @return
*/
boolean needAllWait() default true;
}
```
```java
Component
@Aspect
@Slf4j
public class LimitSubmitAspect {
//封装了redis操作各种方法
@Autowired
private RedisUtil redisUtil;
@Pointcut("@annotation(org.jeecg.common.aspect.annotation.LimitSubmit)")
private void pointcut() {}
@Around("pointcut()")
public Object handleSubmit(ProceedingJoinPoint joinPoint) throws Throwable {
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
//获取注解信息
LimitSubmit limitSubmit = method.getAnnotation(LimitSubmit.class);
int submitTimeLimiter = limitSubmit.limit();
String redisKey = limitSubmit.key();
boolean needAllWait = limitSubmit.needAllWait();
String key = getRedisKey(sysUser,joinPoint, redisKey);
Object result = redisUtil.get(key);
if (result != null) {
throw new JeecgBootException("请勿重复访问!");
}
redisUtil.set( key, sysUser.getId(),submitTimeLimiter);
try {
Object proceed = joinPoint.proceed();
return proceed;
} catch (Throwable e) {
log.error("Exception in {}.{}() with cause = \'{}\' and exception = \'{}\'", joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(), e.getCause() != null? e.getCause() : "NULL", e.getMessage(), e);
throw e;
}finally {
if(!needAllWait) {
redisUtil.del(redisKey);
}
}
}
/**
* 支持多参数,从请求参数进行处理
*/
private String getRedisKey(LoginUser sysUser,ProceedingJoinPoint joinPoint ,String key ){
if(key.contains("%s")) {
key = String.format(key, sysUser.getId());
}
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
String[] parameterNames = discoverer.getParameterNames(method);
if (parameterNames != null) {
for (int i=0; i < parameterNames.length; i++ ) {
String item = parameterNames[i];
if(key.contains("#"+item)){
key = key.replace("#"+item, joinPoint.getArgs()[i].toString());
}
}
}
return key.toString();
}
}
```
**使用效果:**
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200702225400154.png)
```java
使用:
@LimitSubmit(key = "testLimit:%s:#orderId",limit = 10,needAllWait = true)
%S 代表当前登录人
#参数 代表从参数中获取,支持多个参数
生成的redis key: testLimit:e9ca23d68d884d4ebb19d07889727dae:order1123123
```
1.限制对某个接口的访问,针对所有人 ,则去除%S
2.限制某个人对某个接口的访问,则 %S
3.限制某个人对某个接口的业务参数的访问,则 %S:#参数1:#参数2
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200702225331667.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NpbmF0XzE5NTI4MjQ5,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200702225345331.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NpbmF0XzE5NTI4MjQ5,size_16,color_FFFFFF,t_70)
';