Spring Boot 自定义注解实现Api接口访问次数限制

1、首先建一个注解类AccessLimit

/**
 *  @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 5;

    //标识 时间段 分钟
    int time() default 1;
}

2、Aop切面代码

/**
 *  @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(com.hr.framework.interceptor.accessLimit.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(msg.getBytes("UTF-8"));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            outputStream.flush();
            outputStream.close();
        }
    }
}

3、在项目中新建InterceptorConfig配置配置类实现WebMvcConfigurer接口

/**
 *  @Author 彭小康
 *  @Description 拦截器
 *  @Date Create by 2020年05月20日
 */
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {

    }

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

    }

    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {

    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {

    }

    @Override
    public void addFormatters(FormatterRegistry registry) {

    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {

    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {

    }

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {

    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {

    }

    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {

    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {

    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {

    }

    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {

    }

    @Override
    public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {

    }

    @Override
    public Validator getValidator() {
        return null;
    }

    @Override
    public MessageCodesResolver getMessageCodesResolver() {
        return null;
    }

    @Bean
    public IPLimitInterceptor ipLimitInterceptor(){
        return new IPLimitInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        /**
        * - /**: 匹配所有路径
        * - /admin/**:匹配 /admin/ 下的所有路径
        * - /secure/*:只匹配 /secure/user,不匹配 /secure/user/info
        *          //可以同时配置多个
        *         String[] addPathPatterns = {
        *                  "/hellojsp/**",
        *                     "/userApi/**"
        *         };
        */
        registry.addInterceptor(ipLimitInterceptor()).addPathPatterns("/mobile/**");
    }
}

3、在API上加上刚次自定的注解

@AccessLimit(limit=2,time=1)一分钟只允许调用两次 ,默认是1分钟五次

@AccessLimit(limit=2,time=1)
@GetMapping("/getUserInfo")
@ApiOperation("获取用户信息")
public String getUserInfo() {
    return "Welcome to Guang Zhou";
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容