jeecgboot接口限制每ip每分钟访问次数——限制ip请求频率【伸手党福利】

代码借鉴的别人的,自己做过部分修改

1. 新建文件夹并新建文件

\jeecg-boot-base\jeecg-boot-base-core\src\main\java\org\jeecg\common\accesslimit\
RequestLimit.java

package org.jeecg.common.accesslimit;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

import java.lang.annotation.*;

/**
 * @author wangdeqiu
 * @date 2018年11月2日 下午2:19:05
 * 类说明:自定义注解限制访问时间长度最多访问次数
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface RequestLimit {

    /**
     * 允许访问的最大次数
     */
    int count() default Integer.MAX_VALUE;

    /**
     * 时间段,单位为毫秒,默认值一分钟
     */
    long time() default 60000;
}

RequestLimitContract.java

package org.jeecg.common.accesslimit;
/**
 * @Author: wcb
 * @Date: 2020/7/8 0008 17:05
 * @Title: RequestLimitContract
 * @Version 1.0
 */

//import com.suoeryun.website.utils.RedisUtil;
//import com.suoeryun.website.utils.oConvertUtils;

import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


@Aspect
@Component
public class RequestLimitContract {

    private static final Logger logger = LoggerFactory.getLogger(RequestLimitContract.class);
    @Autowired
    private RedisUtil redis;


    private ScheduledExecutorService executorService2;

    public RequestLimitContract() {
        executorService2 = new ScheduledThreadPoolExecutor(8,
                new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
    }

    @Before("within(@org.springframework.web.bind.annotation.RestController *) && @annotation(limit)")
    public void requestLimit(final JoinPoint joinPoint, RequestLimit limit) throws RequestLimitException {
        try {
            Object[] args = joinPoint.getArgs();
            HttpServletRequest request = null;
            for (int i = 0; i < args.length; i++) {
                if (args[i] instanceof HttpServletRequest) {
                    request = (HttpServletRequest) args[i];
                    break;
                }
            }
            if (request == null) {
                throw new RequestLimitException("方法中缺失HttpServletRequest参数");
            }
//            如果不限定ip,则设定ip为本机ip
//            String ip = request.getLocalAddr();
//            如果限定ip,则设定ip为客户端的ip
            String ip = request.getRemoteAddr();

            String url = request.getRequestURL().toString();
            System.out.println(ip);
            System.out.println(url);
            String key = "req_limit_".concat(url).concat(ip);
            if (!redis.hasKey(key) || oConvertUtils.isEmpty(redis.get(key))) {
                redis.set(key, String.valueOf(1));
            } else {
                Integer getValue = Integer.parseInt((String) redis.get(key)) + 1;
                redis.set(key, String.valueOf(getValue));
            }
            int count = Integer.parseInt((String) redis.get(key));
            if (count > 0) {
                //创建一个定时器
//                Timer timer = new Timer();
                TimerTask timerTask = new TimerTask() {
                    @Override
                    public void run() {
                        redis.del(key);
                    }
                };
                //这个定时器设定在time规定的时间之后会执行上面的remove方法,也就是说在这个时间后它可以重新访问
//                timer.schedule(timerTask, limit.time());
                // 利用线程池
                executorService2.schedule(timerTask, limit.time() / 1000, TimeUnit.SECONDS);
            }
            System.out.println(count);
            if (count > limit.count()) {
              /*logger.info("用户IP[" + ip + "]访问地址[" + url + "]超过了限定的次数[" + limit.count() + "]");
              throw new RequestLimitException();
              String toLomitPath ="http://" + request.getServerName()+ ":" + request.getServerPort()+limitPath;   //端口号
              response.sendRedirect(toLomitPath);
              */
                logger.info("用户IP[" + ip + "]访问地址[" + url + "]超过了限定的次数[" + limit.count() + "]");
                throw new RequestLimitException("您的请求次数超限!");
            }
        } catch (RequestLimitException e) {
            throw e;
        } catch (Exception e) {
            logger.error("警告,RequestLimit(次数限制)发生致命异常:", e);
        }
    }


}

RequestLimitException.java

package org.jeecg.common.accesslimit;

/**
 * @author wangdeqiu
 * @date 2018年11月2日 下午2:22:28
 * 类说明:
 */
public class RequestLimitException extends RuntimeException{

    private static final long serialVersionUID = 1555967171104727461L;

    public RequestLimitException(){
        super("HTTP请求超出设定的限制");
    }

    public RequestLimitException(String message){
        super(message);
    }

}

原作者的注释我没有去掉,但是原作者给出的代码无法限定每ip,只能限制访问次数。

2. jeecgboot全局添加错误形式

\jeecg-boot-base\jeecg-boot-base-core\src\main\java\org\jeecg\common\exception\JeecgBootExceptionHandler.java

	@ExceptionHandler(RequestLimitException.class)
	public Result<?> requestLimitException(RequestLimitException e) {
		log.error(e.getMessage() + "***********---------------", e);
		// 返回错误信息
		return Result.error(CommonConstant.SC_INTERNAL_SERVER_ERROR_500, e.getMessage());
	}

调用

关键词:

@RequestLimit(count = 3)

示例:

	@RequestLimit(count = 3)
    @AutoLog(value = "测试频率")
    @ApiOperation("测试频率(组件化版)")
    @GetMapping(value = "/testlimit")
    public Result<?> testlimit(
                        HttpServletRequest request

    ) {
    System.out.println("测试频率!!");
    return Result.OK("ans");
    }

效果:结果

成功
jeecgboot接口限制每ip每分钟访问次数——限制ip请求频率【伸手党福利】_第1张图片
失败
jeecgboot接口限制每ip每分钟访问次数——限制ip请求频率【伸手党福利】_第2张图片

效果:每分钟限制访问次数,该限制在每分钟的0秒时刷新(不是在第一次请求时刷新)。

示例:

以3次每ip每分钟为例:

jeecgboot接口限制每ip每分钟访问次数——限制ip请求频率【伸手党福利】_第3张图片

你可能感兴趣的:(javaweb,jeecgboot,springboot,限制访问频率,次数,接口)