com.google.guava
guava
27.1-jre
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
/**
* @author EDZ
* @Classname RequestLimiter
* @Description TODO
* @Date 2020/6/29 17:46
* @Created zzf
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestLimiter {
/**
* 每秒创建令牌个数,默认:10
*/
double QPS() default 10D;
/**
* 获取令牌等待超时时间 默认:500
*/
long timeout() default 500;
/**
* 超时时间单位 默认:毫秒
*/
TimeUnit timeunit() default TimeUnit.MILLISECONDS;
/**
* 无法获取令牌返回提示信息
*/
String msg() default "服务器繁忙,请稍后重试!";
}
/**
* @Classname ResponseEnum
* @Description TODO
* @Date 2020/6/29 17:52
* @Created zzf
*/
public enum ResponseEnum {
SUCCESS("200", "000000", "请求成功"),
FAIL("200", "100000", "请求失败"),
FAIL_BY_PARAMS("200", "200000", "请求参数异常"),
FAIL_IN_SERVER("200", "300000", "服务器内部异常"),
RATE_LIMIT("200", "400000", "限流中");
public String status;
public String code;
public String message;
ResponseEnum(String s, String s1, String s2) {
this.status = s;
this.code = s1;
this.message = s2;
}
}
import com.alibaba.fastjson.JSON;
import com.ils.intelab.common.result.CommonResult;
import com.ils.intelab.openapi.client.enums.ResponseEnum;
import com.ils.intelab.openapi.client.result.OpenApiResultCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/**
* 抽象拦截器
*/
public abstract class AbstractInterceptor extends HandlerInterceptorAdapter {
private Logger logger = LoggerFactory.getLogger(AbstractInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
ResponseEnum result;
try {
result = preFilter(request, response, handler);
} catch (Exception e) {
logger.error("preHandle catch a exception:" + e.getMessage());
result = ResponseEnum.FAIL;
}
if (ResponseEnum.SUCCESS.code.equals(result.code)) {
return true;
}
handlerResponse(result, response);
return false;
}
/**
* 自定义pre处理
*
* @param request
* @return
*/
protected abstract ResponseEnum preFilter(HttpServletRequest request, HttpServletResponse response, Object handler);
/**
* 错误处理事件
*
* @param result
* @param response
*/
private void handlerResponse(ResponseEnum result, HttpServletResponse response) {
CommonResult commonResult = new CommonResult();
commonResult.setData(null);
CommonResult
实现
import com.google.common.util.concurrent.RateLimiter;
import com.ils.intelab.openapi.annotation.RequestLimiter;
import com.ils.intelab.openapi.client.enums.ResponseEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 请求限流器
* @Classname RequestLimiterInterceptor
* @Description TODO
* @Date 2020/6/29 17:47
* @Created zzf
*/
@Slf4j
@Component
public class RequestLimiterInterceptor extends AbstractInterceptor {
/**
* 不同的方法存放不同的令牌桶
*/
private final Map rateLimiterMap = new ConcurrentHashMap<>();
@Override
protected ResponseEnum preFilter(HttpServletRequest request, HttpServletResponse response, Object handler) {
try {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
RequestLimiter rateLimit = handlerMethod.getMethodAnnotation(RequestLimiter.class);
//判断是否有注解
if (rateLimit != null) {
// 获取请求url
String key = request.getMethod() + request.getRequestURI();
RateLimiter rateLimiter;
// 判断map集合中是否有创建好的令牌桶
if (!rateLimiterMap.containsKey(key)) {
// 创建令牌桶,以n r/s往桶中放入令牌
rateLimiter = RateLimiter.create(rateLimit.QPS());
rateLimiterMap.put(key, rateLimiter);
}
rateLimiter = rateLimiterMap.get(key);
// 获取令牌
boolean acquire = rateLimiter.tryAcquire(rateLimit.timeout(), rateLimit.timeunit());
if (acquire) {
//获取令牌成功
return ResponseEnum.SUCCESS;
} else {
log.warn("请求被限流,url:{}", request.getServletPath());
return ResponseEnum.RATE_LIMIT;
}
}
}
return ResponseEnum.SUCCESS;
} catch (Exception var6) {
var6.printStackTrace();
return ResponseEnum.RATE_LIMIT;
}
}
}
import com.ils.intelab.openapi.aspect.RequestLimiterInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 注册拦截器
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/**
* 请求限流拦截器
*/
@Autowired
protected RequestLimiterInterceptor requestLimiterInterceptor;
public WebMvcConfig() {
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 请求限流
registry.addInterceptor(requestLimiterInterceptor).addPathPatterns("/**");
}
}
import com.ils.intelab.common.result.CommonResult;
import com.ils.intelab.openapi.annotation.RequestLimiter;
import io.swagger.annotations.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
/**
* @Classname TestController
* @Description TODO
* @Date 2020/5/27 9:50
* @Created zzf
*/
@RestController
@RequestMapping("/api/v3/")
@Api(value = "open_api", description = "open_api基础接口", tags = {"open_api"})
public class TestController {
@ApiOperation(value = "测试", notes = "测试")
@ApiResponses({
@ApiResponse(code = 400, message = "参数非法"),
@ApiResponse(code = 500, message = "服务器错误"),
@ApiResponse(code = 200, message = "成功")
})
@ApiImplicitParams({
})
@RequestLimiter(QPS = 1, timeout = 200, timeunit = TimeUnit.MILLISECONDS, msg = "服务器繁忙,请稍后再试")
@RequestMapping(value = "/test", method = RequestMethod.GET)
public CommonResult getUserInfo() {
return new CommonResult<>("999");
}
}