1.创建注解
package com.kova.api.limit;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface RequestLimit {
long time() default 5000; //time是调用接口的间隔时间,默认是 5000 毫秒。
}
2.创建允许访问判断类
package com.kova.api.limit;
import java.util.concurrent.ConcurrentHashMap;
public class RequestLimiter {
private ConcurrentHashMap<String,Long> requestMap = new ConcurrentHashMap<>();
private static volatile RequestLimiter instance;
private RequestLimiter() {}
public static RequestLimiter getInstance() {
if (instance == null) {
synchronized (RequestLimiter.class) {
if (instance == null) {
instance = new RequestLimiter();
}
}
}
return instance;
}
//接口访问判断
public boolean allowRequest(String userId,long timeLimit) {
Long lastRequestTime = requestMap.get(userId);
long currentTime = System.currentTimeMillis();
if (lastRequestTime == null || (currentTime - lastRequestTime) > timeLimit)
{ // 允许请求并更新请求时间
requestMap.put(userId, currentTime);
return true;
}
return false; // 拒绝请求
}
}
3.创建aop处理类
package com.kova.api.limit;
import com.kova.api.common.Result;
import com.kova.api.common.ResultEnum;
import com.kova.api.exception.CommonException;
import com.kova.api.utils.IpUtil;
import com.kova.api.verify.ParamsVerify;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
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.lang.annotation.Annotation;
import java.lang.reflect.Method;
//限制接口调用频率处理
@Aspect
@Component
@Slf4j
public class RequestLimitAspect {
@Synchronized // 作用是创建一个互斥锁,保证只有一个线程对 RequestLimiter.getInstance() 这个变量进行修改。
@Around("execution(* com.kova.api.controller..*.*(..)) && @annotation(nrs)") // 这里要根据自己项目中的controller包路径来配置好
public Object arround(ProceedingJoinPoint pjp, RequestLimit nrs) throws Throwable {
if(nrs == null){
return pjp.proceed();
}
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Object[] args = pjp.getArgs();
String key = IpUtil.getIpAddr(request) + " :" + request.getServletPath();
Long time = nrs.time();
Object o = null;
//可以改为redis保存处理
if(RequestLimiter.getInstance().allowRequest(key,time)){
o = pjp.proceed();
return o;
}else{
log.error("操作过于频繁 {}", key);
return Result.failed(ResultEnum.REQUEST_LIMIT);
}
}
}
4.创建controller类,添加测试方法
package com.kova.api.controller;
import com.kova.api.common.Result;
import com.kova.api.common.ResultEnum;
import com.kova.api.limit.RequestLimit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
@Slf4j
@RestController
@RequestMapping("/api/user")
public class UserController {
/**
* 接口频率访问测试
*
* 测试: curl http://localhost:8080/api/user/limit -X POST -H "Content-Type:application/json" -d '{"name":"kingboyrang"}'
*
*
* @return
*/
@ResponseBody
@RequestMapping(value = "/limit", method = RequestMethod.POST)
@RequestLimit //接口频率访问时间设置,默认值为5000
//@RequestLimit(time = 1000) //接口频率访问时间设置
public Result getReuqestLimitInfo(@RequestBody Map<String,Object> params){
Map<String, Object> resultParams = new HashMap<String, Object>();
resultParams.put("info", "接口访问限制测试");
return Result.ok(resultParams);
}
}
5.测试
curl http://localhost:8080/api/user/limit -X POST -H "Content-Type:application/json" -d '{"name":"kingboyrang"}'
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END

















暂无评论内容