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

小工具篇:工具许多都是我以前在 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. 01: 企业微信API开发前准备

    目录:企业微信API其他篇 01: 企业微信API开发前准备 02:消息推送 03: 通讯录管理 04:应用管理 目录: 1.1 术语介绍 1.2 开发步骤 1.1 术语介绍返回顶部 参考文档:htt ...

  2. 20145105 《Java程序设计》实验三总结

    实验三 一.       实验内容 结对修改实验一代码,重点学习重构 二.       实验步骤 下载结伴同学的实验一代码 初始代码 进行整数.小数和负数的多组数据测试,发现一个运行错误的例子 分析后 ...

  3. jquery插件--问题类(新增&&删除)简易版

    HTML: <!doctype html> <head> <meta charset="utf-8" /> <script src=&qu ...

  4. List集合实现简易学生管理

    题目: 代码: package org.wlgzs; import java.util.ArrayList; import java.util.List; import java.util.Scann ...

  5. ubuntu下桌面假死处理方法(非重启)

    一.背景 2018/05/22,就在这一天,进入ubuntu的桌面后随便点击任何位置均无法响应,此时又不想重启,遂出此文 二.解决方案 2.1 关掉Xorg进程 2.1.1按下ctrl+alt+F1进 ...

  6. SQL NULL

    表 select CHARACTER_MAXIMUM_LENGTH from information_schema.columns where table_name= 'Alliance' selec ...

  7. Where is HttpContent.ReadAsAsync?

    It looks like it is an extension method (in System.Net.Http.Formatting): HttpContentExtensions Class ...

  8. 【错误解决】SVN常见错误及解决方式

    1.Error while creating module:org.apache.subversion.javahl.ClientException:Authorization failed svn: ...

  9. 2017 ACM/ICPC 新疆赛区 I 题 A Possible Tree 带权并查集

    传送门 题意:给定一棵带权树的形态, 但是并不知道每天条边的具体权重. 然后给m个信息, 信息格式为u v val, 表示在树上u 到 v 的路径上经过的边的权重的异或和为val, 问前面最多有多少个 ...

  10. C指针的一些知识

    原文:http://blog.csdn.net/soonfly/article/details/51131141 前言:复杂类型说明 要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何 ...