java 自定义注解方式 实现限制接口请求次数
注解类RequestLimit
package com.cujia.user.common.annotation;
import java.lang.annotation.*;
@documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestLimit {
long time() default 2000;
int count() default 1;
}
自定义切面RequestLimitAspect
package com.cujia.user.common.aop;
import com.cujia.user.common.DTO.Result;
import com.cujia.user.common.DTO.ResultCodeEnum;
import com.cujia.user.common.annotation.RequestLimit;
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.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 RequestLimitAspect {
private static ConcurrentHashMap book = new ConcurrentHashMap<>();
@Pointcut("@annotation(requestLimit)")
public void excudeService(RequestLimit requestLimit) {
}
@Around("excudeService(requestLimit)")
public Result doAround(ProceedingJoinPoint proceedingJoinPoint, RequestLimit requestLimit) throws Throwable {
// 获得request对象
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();
// 获取Map对象,如果没有则返回默认值,第一个参数是key,第二个参数是默认值
ExpiringMap expiringMap = book.getOrDefault(request.getRequestURI(), ExpiringMap.builder().variableExpiration().build());
Integer requestCount = expiringMap.getOrDefault(request.getRemoteAddr(), 0);
// 如果请求超过次数,不执行目标方法
if (requestCount >= requestLimit.count()) {
return Result.fail(ResultCodeEnum.REQUEST_FREQUENCY_FAST);
} else if (requestCount == 0) {
// 第一次请求时,设置有效时间
expiringMap.put(request.getRemoteAddr(), requestCount + 1, ExpirationPolicy.CREATED, requestLimit.time(),
TimeUnit.MILLISECONDS);
} else {
// 未超过请求次数,记录+1
expiringMap.put(request.getRemoteAddr(), requestCount + 1);
}
book.put(request.getRequestURI(), expiringMap);
// result的值就是被拦截方法的返回值
Object result = proceedingJoinPoint.proceed();
return Result.success(result);
}
}
在接口方法上使用
@AllowDontLogIn
@ResponseBody
@ApiOperation("用户订阅类目列表")
@PostMapping("/getUserSubscribeList")
@RequestLimit(count = 2)
public Result> getUserSubscribeList() {
// return Result.ok(dbPushSubscribeBizService.getUserSubscribeList(ForeignAccessUserDTO.getCJUserId()));
return Result.ok(dbPushSubscribeBizService.getUserSubscribeList("0264b5ef04e944509eaf2f790119b800"));
}
连续请求两次结果