diff --git a/servers/boe-server-all/src/main/java/com/xboe/school/aspect/LimitRequest.java b/servers/boe-server-all/src/main/java/com/xboe/school/aspect/LimitRequest.java new file mode 100644 index 00000000..6ff03484 --- /dev/null +++ b/servers/boe-server-all/src/main/java/com/xboe/school/aspect/LimitRequest.java @@ -0,0 +1,12 @@ +package com.xboe.school.aspect; + +import java.lang.annotation.*; + +@Documented +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface LimitRequest { + + long time() default 2000; + int count() default Integer.MAX_VALUE; +} diff --git a/servers/boe-server-all/src/main/java/com/xboe/school/aspect/LimitRequestAspect.java b/servers/boe-server-all/src/main/java/com/xboe/school/aspect/LimitRequestAspect.java new file mode 100644 index 00000000..8e2368fa --- /dev/null +++ b/servers/boe-server-all/src/main/java/com/xboe/school/aspect/LimitRequestAspect.java @@ -0,0 +1,59 @@ +package com.xboe.school.aspect; + + +import com.xboe.api.vo.Result; +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> 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 map = book.getOrDefault(request.getRequestURI(), ExpiringMap.builder().variableExpiration().build()); + Integer uCount = map.getOrDefault(request.getRemoteAddr(), 0); + + + if (uCount >= limitRequest.count()) { // 超过次数,不执行目标方法 + //这里的返回对象类型根据controller方法的返回方式一致 + return Result.error("请求过于频繁,请稍后再试"); + } else if (uCount == 0){ // 第一次请求时,设置开始有效时间 + map.put(request.getRemoteAddr(), uCount + 1, ExpirationPolicy.CREATED, limitRequest.time(), TimeUnit.MILLISECONDS); + } else { // 未超过次数, 记录数据加一 + map.put(request.getRemoteAddr(), uCount + 1); + } + book.put(request.getRequestURI(), map); + + // result的值就是被拦截方法的返回值 + Object result = pjp.proceed(); + + return result; + } + +} \ No newline at end of file