|
|
@@ -0,0 +1,102 @@
|
|
|
+package platform.config.access.limit;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import org.aspectj.lang.ProceedingJoinPoint;
|
|
|
+import org.aspectj.lang.Signature;
|
|
|
+import org.aspectj.lang.annotation.Around;
|
|
|
+import org.aspectj.lang.annotation.Aspect;
|
|
|
+import org.aspectj.lang.annotation.Pointcut;
|
|
|
+import org.aspectj.lang.reflect.MethodSignature;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.context.annotation.Scope;
|
|
|
+import org.springframework.data.redis.core.RedisTemplate;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+import platform.modules.sys.web.ResponseMessage;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import javax.servlet.ServletOutputStream;
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
+import java.io.IOException;
|
|
|
+import java.lang.reflect.Method;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @Author 彭小康
|
|
|
+ * @Description API访问次数控制 切面
|
|
|
+ * @Date Create by 2020年05月20日
|
|
|
+ */
|
|
|
+@Component
|
|
|
+@Scope
|
|
|
+@Aspect
|
|
|
+public class AccessLimitAspect {
|
|
|
+
|
|
|
+ private Logger logger = LoggerFactory.getLogger(AccessLimitAspect.class);
|
|
|
+
|
|
|
+ //注入RedisTemplate
|
|
|
+ @Resource
|
|
|
+ private RedisTemplate<String, Integer> redisTemplate;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private HttpServletResponse response;
|
|
|
+
|
|
|
+ @Pointcut("@annotation(platform.config.access.limit.AccessLimit)")
|
|
|
+ public void limitService() {}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 这里可以写具体的路径 module包下所有的方法都会调用这个方法 @Around("execution(* com.ehr.module.*.*(..))")
|
|
|
+ * @param joinPoint
|
|
|
+ * @return
|
|
|
+ * @throws Throwable
|
|
|
+ */
|
|
|
+ @Around("limitService()")
|
|
|
+ public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
|
|
|
+ //获取拦截的方法相关信息
|
|
|
+ Signature signature = joinPoint.getSignature();
|
|
|
+ MethodSignature methodSignature = (MethodSignature) signature;
|
|
|
+
|
|
|
+ Object target = joinPoint.getTarget();
|
|
|
+ //为了获取注解信息
|
|
|
+ Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
|
|
|
+ //获取注解信息
|
|
|
+ AccessLimit accessLimit = currentMethod.getAnnotation(AccessLimit.class);
|
|
|
+
|
|
|
+ // 限流策越,根据package和方法名称组成Key
|
|
|
+ String packageName = (methodSignature.getMethod().getDeclaringClass()).getName();
|
|
|
+ String functionKey = packageName +"_API>"+ methodSignature.getName();
|
|
|
+
|
|
|
+ //最大次数
|
|
|
+ int maxLimit = accessLimit.limit();
|
|
|
+ //多长时间的最大次数
|
|
|
+ int time = accessLimit.time();
|
|
|
+
|
|
|
+ Integer limit = redisTemplate.opsForValue().get(functionKey);
|
|
|
+ if (limit == null) {
|
|
|
+ redisTemplate.opsForValue().set(functionKey, 1, time, TimeUnit.MINUTES);
|
|
|
+ return joinPoint.proceed();
|
|
|
+ } else if (limit < maxLimit) {
|
|
|
+ redisTemplate.opsForValue().set(functionKey, (limit + 1), time, TimeUnit.MINUTES);
|
|
|
+ return joinPoint.proceed();
|
|
|
+ } else {
|
|
|
+ logger.info("当前 {} 请求超出设定的访问次数,请稍后再试!",functionKey);
|
|
|
+
|
|
|
+ output(response, "当前请求超出设定的访问次数,请稍后再试!");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void output(HttpServletResponse response, String msg) throws IOException {
|
|
|
+ response.setContentType("application/json;charset=UTF-8");
|
|
|
+ ServletOutputStream outputStream = null;
|
|
|
+ try {
|
|
|
+ outputStream = response.getOutputStream();
|
|
|
+ outputStream.write(JSON.toJSONString(ResponseMessage.error(msg)).getBytes(StandardCharsets.UTF_8));
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ } finally {
|
|
|
+ outputStream.flush();
|
|
|
+ outputStream.close();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|