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

2023-11-12

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

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");
    }

效果:结果

成功
在这里插入图片描述
失败
在这里插入图片描述

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

示例:

以3次每ip每分钟为例:

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • 【Unity3D】如何在uniyt中切换画布实现切换界面的交互操作

    我们在切换不同界面的时候 时常会用到切换场景的操作 如果在一个场景里就可以去实现切换界面的时候 若再使用切换场景来实现 会占用很大的空间 不妨在一个场景里使用切换画布的方法来实现切换界面的交互操作 1 在unity场景中添加两个画布以及文本
  • 汽车LiDAR的“先行者”——机械式LiDAR

    转自 http www mems me mems system integrator 201711 5547 html http www mems me mems system integrator 201711 5636 html 机械式
  • (一)硬件制作--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>

    目录 一 工作环境及项目简介 二 原理图设计 1 核心板 电源电路 板对板连接器 复位电路 晶振电路 主控电路 2 底板 串口转USB电路 TF卡电路 WIFI电路 TFT屏幕 音频 板对板连接器 40Pin4 3寸屏幕 三 PCB展示 四
  • [spring处理webservice报文] 1 spring如何搭建webservice服务

    目录 1 背景 2 sping里头搭建webservice 2 1 wsapplication 2 2 futurwebservice 2 3 futurewebserviceimpl 2 4 webserviceconfig 3 soap
  • 画心形图 C#

    public static PointF Random PointF P PointF Center float R float Math Sqrt P X Center X P X Center X P Y Center Y P Y Ce
  • Redis(主从复制、哨兵模式、集群)概述及部署

    Redis主从复制 Redis主从复制的概念 主从复制 是指将一台Redis服务器的数据 复制到其他的Redis服务器 前者称为主节点 Master 后者称为从节点 Slave 数据的复制是单向的 只能由主节点到从节点 默认情况下 每台Re
  • Python练习题——阶乘累计求和

    题目来源 Python语言程序设计 中国大学MOOC 授课老师 嵩天 黄天羽 礼欣 题目描述 获得用户输入的整数n 输出 1 2 n 的值 如果输入数值为0 负数 非数字或非整数 输出提示信息 输入有误 请输入正整数 方法一 factTes
  • vue : 无法加载文件 C:\Users\jianfei\AppData\Roaming\npm\vue.ps1,因为在此系统上禁止运行脚本。...

    背景 在新电脑上配置vue环境 PS E CODE PROJ myvue vue23 P61 使用脚手架 vue test gt npm install g vue cli npm WARN deprecated source map ur
  • python——class类和方法的用法详解

    因为一直不太清楚面向对象的类和方法的编程思想 所以特地补了一下python class的知识 在这里记录和分享一下 文章目录 类和方法的概念和实例 1 python类 class 2 类的构造方法 init 3 类中方法的参数 self 4
  • Redis持久化机制

    目录 Redis的持久化 RDB Redis会在以下几种情况下对数据进行快照 AOF append only file AOF的实现 AOF的重写原理 Redis的持久化 Redis支持两种方式的持久化 一种是RDB方式 另一种是AOF a
  • 一个完整的性能测试流程

    下午逛一个测试交流群时 聊起性能测试 然后某位群成员说他们用的loadrunner做性能 当时觉得这话有点偏颇 虽然我也是一个性能测试道路上的摸索前进者 诚然 我们在进行性能测试工作的过程中 需要借助工具的辅助来帮我们完成一些工作 但loa
  • 计算机存储容量单位读法及换算B、KB、MB、GB、TB、PB、EB、ZB、YB、RB、QB

    1KB 1024B 1MB 1024KB 1024 1024B 1B byte 字节 8 bit 位 比特 1KB Kilobyte 千字节 1024 B 2 10 B 1MB Megabyte 兆字节 百万字节 简称 兆 1024 KB
  • 2023国赛数学建模B题思路代码 - 多波束测线问题

    1 赛题 B 题 多波束测线问题 单波束测深是利用声波在水中的传播特性来测量水体深度的技术 声波在均匀介质中作匀 速直线传播 在不同界面上产生反射 利用这一原理 从测量船换能器垂直向海底发射声波信 号 并记录从声波发射到信号接收的传播时间
  • C++ 中栈对象的使用总结、RAII

    背景 栈区用于存放函数的参数 局部变量 返回值等 栈区的数据由编译器自动进行分配 在作用域内有效 在超出变量作用域后 栈中数据由编译器自动释放 栈内存分配运算内置于处理器的指令集 效率高 但是分配的内存容量有限 栈对象 栈对象在创建时会自动
  • yagmail发送附件

    效果图 经测试代码 导入yagmail第三方库 import yagmail yagmail SMTP user 邮箱名 host SMTP服务器域名 yag yagmail SMTP user 284036658 qq com host
  • 程序员的自我修养——链接,装载与库(一)

    程序员的自我修养 链接 装载与库这本书看了差不多有一个多月了 这本书讲了很多计算机底层的知识 也补充了我的知识盲区 但是感觉看完以后前面有的知识有遗忘 因此就想好好的总结一下 也可以更好的理解这本书 计算机三个最重要的硬件是 中央处理器CP
  • Linux用户与用户组

    Linux目录详解 目录名 说明 bin 重要的二进制 binary 应用程序 包含二进制文件 系统的所有用户使用的命令都在这个目录下 boot 启动 boot 配置文件 包含引导加载程序相关的文件 开机时用到的引导文件 data 数据存储
  • 事件驱动框架(五)——框架的实现

    事件驱动框架 五 框架的实现 说明 这里先描述一下QP的一些策略和源码 因为某原因这个系列先停更 后面主要是内核介绍 实现 1 临界区 临界区内每次只准许一个线程 进程 进入 进入后不允许其他线程 进程 进入 因此临界区的代码不可分割 在嵌
  • 【axios】get/post请求params/data传参总结

    axios中get post请求方式 1 前言 最近突然发现post请求可以使用params方式传值 然后想总结一下其中的用法 2 1 分类 get请求中没有data传值方式 经过查阅资料 get请求是可以通过body传输数据的 但是许多工
  • jeecgboot接口限制每ip每分钟访问次数——限制ip请求频率【伸手党福利】

    代码借鉴的别人的 自己做过部分修改 1 新建文件夹并新建文件 jeecg boot base jeecg boot base core src main java org jeecg common accesslimit RequestLi