java接口限流自定义注解+拦截器+redis

声明:以下代码基本都是参考网上的写的,只是记录加强记忆。作者出处忘记了,抱歉!

先定义自定义接口

@Inherited
@Document
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.Type})
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessLimit {
    
    //标识限制次数
    int limit() default 5;
    //标识时间段
    int sec() default 5;
}

创建拦截器

//创建拦截器类实现HandlerInterceptor 接口
public class AccessLimitInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisTemplate<String, Integer> redisTemplate;

    @ovride
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handle) {
        //判断handle是否为方法handle
        if (handle instanceof HandleMethod) {
            //是的话转为HandleMethod
            HandleMethod handleMethod = (HandleMethod)handle;
            //获取方法
            Method method = handleMethod.getMethod();
            //判断该方法上是否有自定义注解@AccessLimit
            if (!method.isAnocationPerent(AccessLimit.class)) {
                //不存在该注解则放行
                return true;
            }
            //获取自定义注解对象
            AccessLimit accessLimit = method.getAnocation(AccessLimit.class);
            if (accessLimit == null) {
                //放行
                return true;
            }
            //获取注解属性值
            int limit = accessLimit.limit();
            int sec = accessLimit.sec();
            
            String key = request.getRequestURI();    
            //从redis中获取记录
            Integer maxLimit = redisTemplate.opsForValue.get(key);
            if (maxLimit == null) {
                //第一次,计数器设置为1,设置redis过期时间
                redisTemplate.opsForValue.set(key, 1, sec, TimeUtil.SECONDS);
            } else if (maxLimit < limit) {
                //计数器加1
                redisTemplate.opsForValue.set(key, maxLimit + 1, sec, TimeUtil.SECONDS);
            } else {
                output(response, "接口请求频繁,稍后再试");
                return false;
            }
        }
        return true;
    }

    public void output(HttpServletResponse response, String str) throws IOException{
        //设置content-type
        response.setContentType("application/json;charset=UTF-8");
        ServletOutputStream outputStream = null;
        try {
            //获得输出流
            outputStream = response.getOutputStream();
            outputStream.write(str.getByte("utf-8"));
        } catch (IOException e){
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                outputStream.flush();
                outputStream.close();
            }
        }
    }

}

最后在需要做限流的接口方法上加上自定义注解,设置好限流时间(即redis的过期时间)和限流次数

//每秒限制次数为50个请求
@AccessLimit(limit = 50, sec = 1)

配置文件添加拦截器配置

<!-- 接口限流拦截器 -->
<mvc:interceptor>
	<mvc:mapping path="/api/**" />
	<bean class="com.smart.common.spring.interceptor.AccessLimitInterceptor" />
</mvc:interceptor>

猜你喜欢

转载自blog.csdn.net/qq389203946/article/details/86534157