Java自定义注解实现防止接口重复访问(限流)

举报
i进击的攻城狮 发表于 2022/06/27 21:23:01 2022/06/27
【摘要】 ​ 项目场景:有一些场景,例如申请提交之后几秒内需要防止用户重复提交,我们后端通过自定义注解实现这一功能需要的pom依赖:在编写项目之前,如果要用自定义注解实现这一功能,需要导入spring aop,redis依赖等<!-- spring aop依赖--> <dependency> <groupId>org.springframework.b...

 项目场景:

有一些场景,例如申请提交之后几秒内需要防止用户重复提交,我们后端通过自定义注解实现这一功能



需要的pom依赖:

在编写项目之前,如果要用自定义注解实现这一功能,需要导入spring aop,redis依赖等

<!--        spring aop依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>

<!--        工具类依赖-->
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>

<!--        reids依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>


实现:

1、新建一个自定义注解,定义变量

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LimitAccessTimes {
    /**
     * 指定时间内不可重复提交,单位:s
     *
     * @return
     */
    long timeout() default 3;
}

··2、定义切面实现类

@Aspect
@Component
@Slf4j
public class LimitAccessTimesAspect {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Before("@annotation(customannotationdemo.customannotationdemo.annotation.LimitAccessTimes)")
    public void repeatSumbitIntercept(JoinPoint joinPoint)  throws Exception{
        // userTicket + 类名 + 方法 + timeout
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Cookie[] cookieList = request.getCookies();
        String userTicket = null;
        for (Cookie cookie : cookieList) {
            if (cookie.getName().equals("userTicket")) {
                userTicket = cookie.getValue();
                break;
            }
        }
        //获取当前切面所设置的方法的类名、方法名
        String className = joinPoint.getTarget().getClass().getName();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getName();

        // 获取配置的过期时间
        LimitAccessTimes annotation = method.getAnnotation(LimitAccessTimes.class);
        long timeout = annotation.timeout();

        String key = userTicket + ":" + className + ":" + methodName + ":" + timeout + "s";
        log.info(" --- >> 防重提交:key -- {}", key);
        // 判断是否已经超过重复提交的限制时间
        String value = redisTemplate.opsForValue().get(key);
        if (StringUtils.isNotBlank(value)) { //如果不为空,说明redis设置的禁止访问时间未过期,抛出异常,禁止访问
            String messge = MessageFormat.format("请勿在{0}s内重复提交", timeout);
            throw new Exception(messge);
        }
        redisTemplate.opsForValue().set(key, key, timeout);
    }


}

实现思路

在段代码,流程是在执行接口方法前(加上注解的方法),获取用户的userTicker和访问的类和方法,将这几个参数拼接组成一个字符串,然后查询redis,如果没有结果,说明是第一次访问,把这个字符串写入redis,设置过期时间;之后在为过期的时候在访问,抛出异常,后续可以定义一个全局异常捕获,把异常信息抛出给前端

只需要在需要防止重复访问的方法上新增注解,非常方便

编辑


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。