代码借鉴的别人的,自己做过部分修改
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 = https://www.it610.com/article/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());
}
调用 【javaweb|jeecgboot接口限制每ip每分钟访问次数——限制ip请求频率【伸手党福利】】关键词:
@RequestLimit(count = 3)
示例:
@RequestLimit(count = 3)
@AutoLog(value = "https://www.it610.com/article/测试频率")
@ApiOperation("测试频率(组件化版)")
@GetMapping(value = "https://www.it610.com/testlimit")
public Result> testlimit(
HttpServletRequest request) {
System.out.println("测试频率!!");
return Result.OK("ans");
}
效果:结果 成功
文章图片
失败
文章图片
效果:每分钟限制访问次数,该限制在每分钟的0秒时刷新(不是在第一次请求时刷新)。
示例: 以3次每ip每分钟为例:
文章图片
推荐阅读
- JavaWeb|JavaScript(8)深入理解作用域
- 使用@SpringBootApplication注解
- springboot自定义SpringApplication启动类
- springboot配置mybatis的mapper路径
- @SpringBootApplication无法被解析引入
- 关于SpringBoot集成myBatis时,mapper接口注入失败的问题
- 安卓其他SpringBoot官网快速集成方法
- @SpringBootApplication的说明
- SpringBoot无法访问webapp目录下的文件