注解 + 拦截器:?秒防刷新

小工具篇:工具许多都是我以前在 github 之类开源平台找到的小工具类,作者的信息什么的许多都忘了。先说声不好意思了。若有相关信息,麻烦提醒一下~

解释

所谓的?秒防刷新,其实就是限制用户在某个时间内对某个 Controller 的访问时间限制。最常见的,比如学校教务系统(正方)的3s防刷新。虽然我不知道正方系统具体是如何实现的,不过可以通过 注解+拦截器 来实现。

前期准备

关于 注解+拦截器,我在上一篇小工具中已经有所介绍。
同时,关于系统轮询的问题,可以使用 @Scheduled 来进行一个全系统记录的轮询,但真的没必要……我觉得可以使用 java 自带的定时器小工具 TimerTimerTask
* Timer 是一种定时器工具,用来在一个后台线程计划执行指定任务。
* TimerTask 一个抽象类,它的子类或者重写run方法代表一个可以被Timer计划的任务

参考资料:(Timer与TimerTask详解)http://blog.csdn.net/ahxu/article/details/249610

正式开工

  • 自定义异常类
    HttpServletException : 用于记录http请求或响应异常。
    RequestLimitException : 用于记录用户HTTP请求超出设定的限制。
public class RequestLimitException extends Exception {
public RequestLimitException() {
super("HTTP请求超出设定的限制");
} public RequestLimitException(String message) {
super(message);
} public RequestLimitException(String message, Throwable cause){
super(message, cause);
}
}
  • 注解类 RequestLimit.java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface RequestLimit { //允许访问的次数,默认值MAX_VALUE
int count() default Integer.MAX_VALUE; // 时间段,单位为毫秒,默认值一分钟
long time() default 60000; }
  • 拦截器 RequestLimitContract.java
@Aspect
@Component
public class RequestLimitContract {
private static final Logger logger = LoggerFactory.getLogger(RequestLimitContract.class); //用于存储记录
private Map<String, Integer> redisTemplate=new HashMap<String,Integer>(); @Before("within(@org.springframework.stereotype.Controller *) && @annotation(limit)")
public void requestLimit(final JoinPoint joinPoint, RequestLimit limit) throws RequestLimitException {
try {
//获取 HttpServletRequest 参数
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) {
logger.error("方法中缺失HttpServletRequest参数");
throw new HttpServletException("方法中缺失HttpServletRequest参数");
} String ip = request.getLocalAddr();
String url = request.getRequestURL().toString();
final String key = "req_limit_".concat(url).concat(ip); System.out.println("ip = "+ip+"\n"+" url = "+url+"\n"+" key = "+key); if(redisTemplate.get(key)==null || redisTemplate.get(key)==0){
redisTemplate.put(key,1);
}else{
redisTemplate.put(key,redisTemplate.get(key)+1);
}
int count = redisTemplate.get(key);
if (count > 0) {
Timer timer= new Timer();
TimerTask task = new TimerTask(){ //创建一个新的计时器任务。
@Override
public void run() {
if(!key.equals("")) {
redisTemplate.remove(key);
}
}
};
timer.schedule(task, limit.time());
//安排在指定延迟后执行指定的任务。task : 所要安排的任务。limit.time() : 执行任务前的延迟时间,单位是毫秒。
}
if (count > limit.count()) {
logger.info("用户IP[" + ip + "]访问地址[" + url + "]超过了限定的次数[" + limit.count() + "]");
throw new RequestLimitException();
}
} catch (RequestLimitException e) {
throw e;
} catch (Exception e) {
logger.error("发生异常: ", e);
}
}
}
  • 控制器
    注意方法中一定要有 HttpServletRequest 参数!!!不然会抛出 HttpServletException 异常。
   @ResponseBody
@RequestMapping("/hello")
@RequestLimit(count = 10)
public String hello(HttpServletRequest request) {
return "Hello World";
}

效果截图

  1. 正常访问

  1. 访问受限

  2. 服务器后台

spring boot 学习(九)小工具篇:?秒防刷新的更多相关文章

  1. spring boot 学习(七)小工具篇:表单重复提交

    注解 + 拦截器:解决表单重复提交 前言 学习 Spring Boot 中,我想将我在项目中添加几个我在 SpringMVC 框架中常用的工具类(主要都是涉及到 Spring AOP 部分知识).比如 ...

  2. Spring boot 学习 九

    一:经过试验发现,如果使用如下的Controller(@RequestBody), 前台POST的请求body只能是JSON,如果是form-data, X-www-form-urlencoded 或 ...

  3. 学习 Spring Boot 知识看这一篇就够了

    从2016年因为工作原因开始研究 Spring Boot ,先后写了很多关于 Spring Boot 的文章,发表在技术社区.我的博客和我的公号内.粗略的统计了一下总共的文章加起来大概有六十多篇了,其 ...

  4. Spring boot学习1 构建微服务:Spring boot 入门篇

    Spring boot学习1 构建微服务:Spring boot 入门篇 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框 ...

  5. spring boot 结合Redis 实现工具类

    自己整理了 spring boot 结合 Redis 的工具类引入依赖 <dependency> <groupId>org.springframework.boot</g ...

  6. Spring Boot学习笔记2——基本使用之最佳实践[z]

    前言 在上一篇文章Spring Boot 学习笔记1——初体验之3分钟启动你的Web应用已经对Spring Boot的基本体系与基本使用进行了学习,本文主要目的是更加进一步的来说明对于Spring B ...

  7. spring boot 学习(十四)SpringBoot+Redis+SpringSession缓存之实战

    SpringBoot + Redis +SpringSession 缓存之实战 前言 前几天,从师兄那儿了解到EhCache是进程内的缓存框架,虽然它已经提供了集群环境下的缓存同步策略,这种同步仍然需 ...

  8. 我的Spring Boot学习记录(二):Tomcat Server以及Spring MVC的上下文问题

    Spring Boot版本: 2.0.0.RELEASE 这里需要引入依赖 spring-boot-starter-web 这里有可能有个人的误解,请抱着怀疑态度看. 建议: 感觉自己也会被绕晕,所以 ...

  9. Spring Boot 学习方法论-如何正确的入门 Spring Boot

    想要入门 Spring Boot,那么什么样的教程是符合初学者学习的(没有太多的Java基础但有一些程序基础或者软件编程知识). 这恰好能够勾出很多问题,比如是文章图文教程适合还是视频教程适合零基础初 ...

随机推荐

  1. 07:urllib与urllib2基本使用

    参考博客:https://blog.csdn.net/chendong_/article/details/51973499 1.1 urllib2发送get请求 # -*- coding:UTF-8 ...

  2. TensorFlow 之 手写数字识别MNIST

    官方文档: MNIST For ML Beginners - https://www.tensorflow.org/get_started/mnist/beginners Deep MNIST for ...

  3. BZOJ 2141 排队(树状数组套treap)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2141 题意:给出一个数列A,每次交换两个数的位置.输出交换后逆序对的个数. 思路:首先, ...

  4. git如何生成指定两个commit之间的补丁

    答:git format-patch <base commit id>..<latest commit id> 如git log输出以下内容: commit 2222222 y ...

  5. JavaScript replaceAll

    网上的: String.prototype.replaceAll = function(str1, str2) { var str = this; var result = str.replace(e ...

  6. 精巧好用的DelayQueue 转

    我们谈一下实际的场景吧.我们在开发中,有如下场景 a) 关闭空闲连接.服务器中,有很多客户端的连接,空闲一段时间之后需要关闭之.b) 缓存.缓存中的对象,超过了空闲时间,需要从缓存中移出.c) 任务超 ...

  7. 论文笔记之:UNSUPERVISED REPRESENTATION LEARNING WITH DEEP CONVOLUTIONAL GENERATIVE ADVERSARIAL NETWORKS

    UNSUPERVISED REPRESENTATION LEARNING WITH DEEP CONVOLUTIONAL GENERATIVE ADVERSARIAL NETWORKS  ICLR 2 ...

  8. ZOJ 3469 Food Delivery(区间DP)

    https://vjudge.net/problem/ZOJ-3469 题意:在一条直线上有一个餐厅和n个订餐的人,每个人都有随时间上升的不满意值,从餐厅出发,计算出送完时最小的不满意值总和. 思路: ...

  9. django 数据库同步

    python manage.py makemigrations python manage.py migrate

  10. python 函数返回函数

    def hi(name="yasoob"): def greet(): return "now you are in the greet() function" ...