فهرست منبع

限流拦截器添加

wangjiang988 2 سال پیش
والد
کامیت
a02b7b4249

+ 16 - 0
src/main/java/platform/config/WebMvcConfig.java

@@ -25,6 +25,7 @@
 package platform.config;
 
 import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
 
@@ -42,4 +43,19 @@ public class WebMvcConfig extends WebMvcConfigurerAdapter {
     public void addResourceHandlers(ResourceHandlerRegistry registry) {
         registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
     }
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        /**
+         * - /**: 匹配所有路径
+         * - /admin/**:匹配 /admin/ 下的所有路径
+         * - /secure/*:只匹配 /secure/user,不匹配 /secure/user/info
+         *          //可以同时配置多个
+         *         String[] addPathPatterns = {
+         *                  "/hellojsp/**",
+         *                     "/userApi/**"
+         *         };
+         */
+//        registry.addInterceptor(ipLimitInterceptor()).addPathPatterns("/mobile/**");
+    }
 }

+ 20 - 0
src/main/java/platform/config/access/limit/AccessLimit.java

@@ -0,0 +1,20 @@
+package platform.config.access.limit;
+
+import java.lang.annotation.*;
+
+/**
+ *  @Author 彭小康
+ *  @Description 自定义注解, @AccessLimit(limit=5,time=1)访问次数,时间默认1分钟5次
+ *  @Date Create by 2020年05月20日
+ */
+@Inherited
+@Documented
+@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AccessLimit {
+    //标识 指定time时间段内的访问次数限制
+    int limit() default 20;
+
+    //标识 时间段 分钟
+    int time() default 1;
+}

+ 102 - 0
src/main/java/platform/config/access/limit/AccessLimitAspect.java

@@ -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();
+        }
+    }
+}

+ 5 - 0
src/main/java/platform/modules/home/HomeController.java

@@ -22,6 +22,7 @@ import platform.common.base.model.DictionaryItem;
 import platform.common.base.service.DictionaryItemService;
 import platform.common.exception.BaseException;
 import platform.common.util.*;
+import platform.config.access.limit.AccessLimit;
 import platform.modules.api.dto.SyncUserDto;
 import platform.modules.api.service.SkyImageApiService;
 import platform.modules.build.DTO.HomeSlideDto;
@@ -221,6 +222,7 @@ public class HomeController extends BaseController {
     }
 
     @GetMapping(value = "/informList/{id}")
+    @AccessLimit
     public String informList(@PathVariable Integer id, ModelMap modelMap) throws Exception {
         try {
             //	获取导航
@@ -239,6 +241,7 @@ public class HomeController extends BaseController {
     }
 
     @GetMapping(value = "/unionCompany")
+    @AccessLimit
     public String unionCompany(ModelMap modelMap) throws Exception {
         Navigation navigation = navigationService.findById(2);
         if (null != navigation) {
@@ -256,6 +259,7 @@ public class HomeController extends BaseController {
 
     @PostMapping(value = "/contentList")
     @ResponseBody
+    @AccessLimit
     public ResponseMessage findContents(FindRequest request) throws Exception {
         FindResponse response = new FindResponse();
         try {
@@ -268,6 +272,7 @@ public class HomeController extends BaseController {
 
     @PostMapping(value = "/activityList")
     @ResponseBody
+    @AccessLimit
     public ResponseMessage findActivity(FindRequest request) throws Exception {
         ListResponse response = new ListResponse();
         response.setFile_url(setFileUrl());

+ 2 - 0
src/main/java/platform/modules/home/web/HomeRefactorController.java

@@ -24,6 +24,7 @@ import platform.common.base.model.CheckResult;
 import platform.common.base.model.DictionaryItem;
 import platform.common.base.service.DictionaryItemService;
 import platform.common.util.*;
+import platform.config.access.limit.AccessLimit;
 import platform.config.redis.RedisService;
 import platform.modules.api.dto.SyncUserDto;
 import platform.modules.api.response.epoint.EpointTokenDto;
@@ -185,6 +186,7 @@ public class HomeRefactorController extends BaseController {
      * @return
      */
     @PostMapping("/contentList")
+    @AccessLimit
     public Object contentList(@RequestBody FindRequest request) {
         PageInfo<Content> info = homeRefactorService.findContentList(request);
         return ResponseMessage.success("success", info);