@Component
@Slf4j
public class AccessLimitIntercept implements HandlerInterceptor {
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String macParam = request.getParameter("mac");
String requestURI = request.getRequestURI();
try {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
if (!method.isAnnotationPresent(MACAccessLimit.class)) {
return true;
}
MACAccessLimit MACAccessLimit = method.getAnnotation(MACAccessLimit.class);
if (MACAccessLimit == null) {
return true;
}
if (StringUtils.isEmpty(macParam)) {
return true;
}
log.info("mac:[{}],requestURI:[{}]", macParam, requestURI);
String key = macParam + requestURI;
int limitCount = MACAccessLimit.maxAccess();
Integer timeoutSecond = MACAccessLimit.second();
synchronized (this) {
Integer maxAccess = null;
String value = redisTemplate.opsForValue().get(key);
if (StringUtils.isNotEmpty(value)) {
maxAccess = Integer.valueOf(value);
}
if (maxAccess == null) {
redisTemplate.opsForValue().set(key, "1", timeoutSecond, TimeUnit.SECONDS);
} else if (maxAccess < limitCount) {
redisTemplate.opsForValue().set(key, (++maxAccess) + "", timeoutSecond, TimeUnit.SECONDS);
} else {
log.info("mac=[{}]请求[{}]太频繁了 被拦截!!!", macParam, requestURI);
ResultDTO results = new ResultDTO();
results.setCode(ErrorCodeEnum.ACCESS_LIMIT.getCode());
results.setMsg(ErrorCodeEnum.ACCESS_LIMIT.getMsg());
results.setData("frequently");
setResponse(results, response);
return false;
}
}
}
} catch (Exception e) {
log.error("API请求限流拦截异常,异常原因:", e);
return true;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
private void setResponse(ResultDTO results, HttpServletResponse response) throws IOException {
ServletOutputStream outputStream = null;
try {
response.setHeader("Content-type", "application/json; charset=utf-8");
outputStream = response.getOutputStream();
outputStream.write(JSON.toJSONString(results).getBytes("UTF-8"));
} catch (Exception e) {
log.error("setResponse方法报错", e);
} finally {
if (outputStream != null) {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
@Inherited
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MACAccessLimit {
int maxAccess() default 3;
int second() default 60;
}