通过AOP拦截所有请求,控制在规定时间内请求次数。
1:添加maven
<dependency>
<groupId>net.jodah</groupId>
<artifactId>expiringmap</artifactId>
<version>0.5.10</version>
</dependency>
2:全局注解
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
/**
* @Description 是否重复提交注解(在方法上,例: @IsRepeatSubmit 或者 @IsRepeatSubmit(count = 2,time = 2000),参数不写使用默认值)
* @Author WangKun
* @Date 2024/5/22 16:52
* @Version
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IsRepeatSubmit {
/**
* 限制时间单位 单位:毫秒
**/
TimeUnit TIME_UNIT = TimeUnit.MILLISECONDS;
/**
* 限制时间 单位:毫秒
**/
long time() default 1000;
/**
* 限制时间内允许请求的次数
**/
int count() default 1;
}
3:AOP切面
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.harmonywisdom.requestaop.IsRepeatSubmit;
import com.harmonywisdom.response.ResponseResult;
import com.harmonywisdom.utils.HttpContextUtil;
import com.harmonywisdom.utils.RequestUtil;
import lombok.extern.slf4j.Slf4j;
import net.jodah.expiringmap.ExpirationPolicy;
import net.jodah.expiringmap.ExpiringMap;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Description 重复提交切面
* @Author WangKun
* @Date 2024/5/22 16:57
* @Version
*/
@Slf4j
@Aspect
@Component
public class RepeatSubmitAspect {
/**
* 全局缓存
**/
private static final ConcurrentHashMap<String, ExpiringMap<String, Integer>> CE = new ConcurrentHashMap<>();
/**
* @Description 切点
* @param irs
* @Throws
* @Return void
* @Date 2024-05-28 15:41:56
* @Author WangKun
**/
@Pointcut("@annotation(irs)")
public void excludeService(IsRepeatSubmit irs) {
}
/**
* @Description 切面
* @param pjp
* @param irs
* @Throws
* @Return java.lang.Object
* @Date 2024-05-28 15:41:42
* @Author WangKun
**/
@Around("excludeService(irs)")
public Object doAround(ProceedingJoinPoint pjp, IsRepeatSubmit irs) throws Throwable {
// 从上下文获取request
HttpServletRequest request = HttpContextUtil.getHttpServletRequest();
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
Object[] args = pjp.getArgs();
//获取request中数据(获取@RequestBody ,@RequestParam注解的参数)
String data = RequestUtil.getParameter(request, method, args);
JSONObject obj = JSON.parseObject(data);
/** 以下根据自己的业务调整**/
//ip
String ip = request.getRemoteAddr();
//uri
String uri = request.getRequestURI();
//getOrDefault方法,没有该key则使用该key
ExpiringMap<String, Integer> em = CE.getOrDefault(uri+"_"+ip, ExpiringMap.builder().variableExpiration().build());
Integer count = em.getOrDefault(ip, 0);
if (count >= irs.count()) {
return ResponseResult.error(500,"请勿重复提交");
} else if (count == 0) {
em.put(ip, count + 1, ExpirationPolicy.CREATED, irs.time(), irs.TIME_UNIT);
} else {
em.put(ip, count + 1);
}
CE.put(uri+"_"+ip, em);
return pjp.proceed();
}
}
RequestUtil.getParameter(request, method, args)
获取@RequestBody ,@RequestParam注解的参数-CSDN博客
HttpServletRequest request = HttpContextUtil.getHttpServletRequest();