java 防抖注解处理

第一步 创建 CurrentLimi注释
	@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentLimit {

    /**
     * 请求次数
     * @return
     */
    int number();

    /**
     * 时间限制
     *
     * @return
     */
    long time();
}

第二步 创建拦截器的类 CurrentLimitInterceptor

	@Slf4j
@Component
public class CurrentLimitInterceptor implements HandlerInterceptor {

    private final static String SEPARATOR = "-";

    private final static String COMMA = ",";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ApplicationException {
        RedisTemplate<String, Integer> redisTemplate = SpringBeanFactory.getBean("redisTemplate");
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            //通过HandlerMethod获取方法CurrentLimit注解
            CurrentLimit currentLimit = handlerMethod.getMethodAnnotation(CurrentLimit.class);
            //如果此方法存在限流注解
            if (currentLimit != null) {
                int number = currentLimit.number();
                long time = currentLimit.time();
                //如果次数和时间限制都大于0证明此处需要限流
                if (time > 0 && number > 0) {
                    //这里的可以定义的是项目路径+API路径+ip。key可以根据项目实际场景去设定
                    String key = request.getContextPath() + SEPARATOR + request.getServletPath() + SEPARATOR + getIPAddress(request);
                    //获取reids缓存中的访问次数
                    Integer numberRedis = redisTemplate.opsForValue().get(key);
                    //如果是第一次访问,则设置此ip访问此API次数为1,并设置失效时间为注解中的时间
                    if (null == numberRedis) {
                        redisTemplate.opsForValue().set(key, 1, time, TimeUnit.SECONDS);
                        return true;
                    }
                    //如果访问次数大于注解设定则抛出异常
                    if (numberRedis >= number) {
                        throw new ApplicationException(I18nDbUtils.getI18nValue("request.frequently"));
                    }
                    //如果满足限流条件则更新缓存次数
                    redisTemplate.opsForValue().set(key, numberRedis + 1);
                }
            }
        }
        return true;
    }

    /**
     * 获取当前网络 ip
     * @param request HttpServletRequest
     * @return 真实的 ip 地址
     */
    private String getIPAddress(HttpServletRequest request) {
        String ipAddress = request.getHeader("HTTP_X_FORWARDED_FOR");
        if (isIpAddressBoolean(ipAddress)) {
            ipAddress = request.getHeader("x-forwarded-for");
        }
        if (isIpAddressBoolean(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (isIpAddressBoolean(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (isIpAddressBoolean(ipAddress)) {
            ipAddress = request.getRemoteAddr();
        }
        // 对于通过多个代理的情况,第一个 IP 为客户端真实 IP,多个 IP 按照','分割
        // "***.***.***.***".length() = 15
        if (ipAddress != null && ipAddress.length() > 15) {
            if (ipAddress.indexOf(COMMA) > 0) {
                ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
            }
        }
        log.info("当前请求的ip地址是:" + ipAddress);
        return ipAddress;
    }

    private boolean isIpAddressBoolean(String ipAddress) {
        return ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress);
    }
}

第三步 创建拦截器的配置文件 InterceptorConfig

	@Slf4j
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Autowired
    private CurrentLimitInterceptor currentLimitInterceptor;

    /**
     * 将自定义的限流拦截器添加到配置中
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //此处也可以通过addPathPatterns方法添加此拦截器对部分请求路径有效,也可以通过excludePathPatterns过滤请求路径
        registry.addInterceptor(currentLimitInterceptor);
    }
}

最后一步就是把注解添加到需要的接口上面,如下图所示:

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值