1、添加依赖
<dependency> <groupId>net.jodah</groupId> <artifactId>expiringmap</artifactId> <version>0.5.10</version> </dependency>
2、新建注解
package com.qax.situation.transmission.application.annoation; import java.lang.annotation.*; @Documented @Target(ElementType.METHOD) // 说明该注解只能放在方法上面 @Retention(RetentionPolicy.RUNTIME) public @interface LimitRequest { long time() default 60000; // 限制时间 单位:毫秒 int count() default Integer.MAX_VALUE; // 允许请求的次数 }
3、自定义AOP切面
package com.qax.situation.transmission.application.annoation; import com.qax.needle.common.constant.HttpStatus; import com.qax.needle.framework.boot.exception.BaseException; 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.springframework.stereotype.Component; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; @Aspect @Component public class LimitRequestAspect { private static ConcurrentHashMap<String, ExpiringMap<String, Integer>> book = new ConcurrentHashMap<>(); // 定义切点 // 让所有有@LimitRequest注解的方法都执行切面方法 @Pointcut("@annotation(limitRequest)") public void excudeService(LimitRequest limitRequest) { } @Around("excudeService(limitRequest)") public Object doAround(ProceedingJoinPoint pjp, LimitRequest limitRequest) throws Throwable { // 获得request对象 RequestAttributes ra = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes sra = (ServletRequestAttributes) ra; HttpServletRequest request = sra.getRequest(); // 获取Map对象, 如果没有则返回默认值 // 第一个参数是key, 第二个参数是默认值 ExpiringMap<String, Integer> uc = book.getOrDefault(request.getRequestURI(), ExpiringMap.builder().variableExpiration().build()); Integer nowCount = uc.getOrDefault(request.getRemoteAddr(), 0); if (nowCount >= limitRequest.count()) { // 超过次数,不执行目标方法 throw new BaseException(HttpStatus.PERMISSION_DENIED, "", "接口请求超过次数"); //return JsonResult.error("请求次数过多,已经限制"); } else if (nowCount == 0) { // 第一次请求时,设置有效时间 // /** Expires entries based on when they were last accessed */ // ACCESSED, // /** Expires entries based on when they were created */ // CREATED; uc.put(request.getRemoteAddr(), nowCount + 1, ExpirationPolicy.CREATED, limitRequest.time(), TimeUnit.MILLISECONDS); } else { // 未超过次数, 记录加一 uc.put(request.getRemoteAddr(), nowCount + 1); } book.put(request.getRequestURI(), uc); // result的值就是被拦截方法的返回值 return pjp.proceed(); } }
4、在函数上添加注解
@LimitRequest(count = 10)
标签:java,request,接口,频次,LimitRequest,org,limitRequest,import From: https://www.cnblogs.com/shangwei/p/16783792.html