@interface [SpringMVC+redis]自定义aop注解实现控制器访问次数限制

我们需要根据IP去限制用户单位时间的访问次数,防止刷手机验证码,屏蔽注册机等,使用注解就非常灵活了

1 定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented//最高优先级
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface RequestLimit {
    /**
     *
     * 允许访问的次数,默认值MAX_VALUE
     */
    int count() default Integer.MAX_VALUE;

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

 2 实现注解

@Aspect
@Component
public class RequestLimitContract {
    private static final Logger logger = LoggerFactory.getLogger("RequestLimitLogger");
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Before("within(@org.springframework.stereotype.Controller *) && @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参数");
            }
            String ip = HttpRequestUtil.getIpAddr(request);
            String url = request.getRequestURL().toString();
            String key = "req_limit_".concat(url).concat(ip);
            long count = redisTemplate.opsForValue().increment(key, 1);
            if (count == 1) {
                redisTemplate.expire(key, limit.time(), TimeUnit.MILLISECONDS);
            }
            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);
        }
    }
}

3 自定义Exception

public class RequestLimitException extends Exception {
    private static final long serialVersionUID = 1364225358754654702L;

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

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

}

4 在Controller中使用

@RequestLimit(count=100,time=60000)
@RequestMapping("/test")
public String test(HttpServletRequest request, ModelMap modelMap) {
    //TODO
 }

我使用了redis缓存访问次数,并且设置自增1,其实用静态map也可以。

原文地址:https://www.cnblogs.com/zhoading/p/12199762.html

时间: 2025-01-11 12:34:14

@interface [SpringMVC+redis]自定义aop注解实现控制器访问次数限制的相关文章

[SpringMVC]自定义注解实现控制器访问次数限制

我们需要根据IP去限制用户单位时间的访问次数,防止刷手机验证码,屏蔽注册机等,使用注解就非常灵活了 1 定义注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented//最高优先级 @Order(Ordered.HIGHEST_PRECEDENCE) public @interface RequestLimit { /** * * 允许访问的次数,默认值MAX_VALUE */ int count(

SpringMVC中的常用注解

RequestParam 作用: 用于  将请求参数区数据  映射到  功能处理方法的参数上. 属性: value  请求参数中的名称 required   请求参数中是否必须提供此参数. 默认值: true   表示必须提供, 如果不提供将报错 使用示例: jsp代码: <!-- requestParams 注解的使用 --> <a href="springmvc/useRequestParam?name=test">requestParam 注解</a

Spring+SpringMVC+Mybatis 利用AOP自定义注解实现可配置日志快照记录

目的: 需要对一些事物的操作进行日志记录,如果在service内进行记录,大量的代码重复,并且维护比较麻烦.所以采用AOP的方式对service进行拦截.使用自定义注解的目的则是判断是否需要记录日志和传递额外的信息. 方式 本次解决方案十分感谢博主-跳刀的兔子的博文 本文绝大部分参考与本文,略有不同,所以做一些整理,博主的文章更详细一些. 1.首先新建自定义注解 @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @

自定义日志注解 + AOP实现记录操作日志

需求:系统中经常需要记录员工的操作日志和用户的活动日志,简单的做法在每个需要的方法中进行日志保存操作, 但这样对业务代码入侵性太大,下面就结合AOP和自定义日志注解实现更方便的日志记录 首先看下一个简单的操作日志表 action_log id subject(日志主题) content(日志内容) create_by create_time 日志主题可以用下面的枚举类来实现 package cn.bounter.common.model; /** * 应用日志主题枚举类 * @author si

springmvc注解式控制器简介

一.Spring2.5之前,我们都是通过实现Controller接口或其实现来定义我们的处理器类.已经@Deprecated. 二.Spring2.5引入注解式处理器支持,通过@Controller 和 @RequestMapping注解定义我们的处理器类.并且提供了一组强大的注解: 需要通过处理器映射DefaultAnnotationHandlerMapping和处理器适配器AnnotationMethodHandlerAdapter来开启支持@Controller 和@RequestMapp

springMVC基于注解的控制器

springMVC基于注解的控制器的优点有两个: 1.控制器可以处理多个动作,这就允许将相关操作写在一个类中. 2.控制器的请求映射不需要存储在配置文件中.使用requestMapping注释类型,可以对一个方法进行请求处理. 接下来介绍两个最重要的注释类型: 一.controller注释类型 这种注释类型用于指示Spring类的实例是一个实例: import org.springframework.stereotype; public class CustemerController{ //m

aop注解 自定义切面的注解写法

spring.xml中 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.spr

Spring学习笔记-springMVC基于注解的控制器(基本概念)

在spring2.5以前的版本中,实现一个mvc的Controller的唯一方法就是实现Controller接口,一个控制器只能响应一个客户端请求,在2.5以后的版本中,spring引入了注解,利用注解简化配置文件,利用注解实现bean的声明和依赖注入(DI),注解也同样被引入到spring的web模块springMVC中. 使用基于注解的控制器有两个优点 第一:一个控制器可以处理多个动作,而不是像以前那样一个控制器只能处理一个请求 第二:省略的在配置文件中对bean的声明和依赖注入,显著提高开

SpringMVC入门之注解式控制器

上面一篇写的是配置式的控制器现在已经不推荐使用了,其实注解式控制器和它的差不多只不过 更简洁而已! 1.还是在web.xml中进行配置DispatcherServlet <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-para