欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

自定义注解+AOP实现限制访问时间长度、最多访问次数

程序员文章站 2022-04-25 20:09:15
...

1 自定义注解

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

import java.lang.annotation.*;

/**
 * 自定义注解限制访问时间长度,最多访问次数
 * Target 注解的作用目标
 * Documented 说明该注解将被包含在javadoc中
 * Order 最高优先级
 *
 * @author gaorimao
 * @date 2021-04-29
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface RequestTimes {
    //单位时间允许访问次数,默认值是3
    int count() default 3;

    //设置单位时间为1秒钟,即默认值1秒钟,1000 为毫秒。
    long time() default  1000;
}

2 AOP实现

import com.grm.annotation.RequestTimes;
import com.grm.enums.ErrorEnum;
import com.grm.exception.BusinessException;
import com.grm.util.IpUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.concurrent.TimeUnit;

/**
 * 限制访问时间长度最多访问次数
 *
 * @author gaorimao
 * @date 2021-04-29
 */
@Aspect
@Component
@Slf4j
public class RequestTimesAop {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private HttpServletRequest request;

    //切面范围
    @Pointcut("execution(* com.grm.controller..*.*(..))")
    public void webPointCut() {
    }

    /**
     * JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.
     */
    @Before("webPointCut() && @annotation(times)")
    public void ifOverTimes(final JoinPoint joinPoint, RequestTimes times) {
        try {
            String ip = IpUtils.getIpAddr(request);
            String url = request.getRequestURL().toString();
            String key = "ifOvertimes".concat(url).concat(ip);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //访问次数加一,increment(K key, double delta),以增量的方式将double值存储在变量中。
            int count = redisTemplate.opsForValue().increment(key, 1).intValue();
            //如果是第一次,则设置过期时间
            if (count == 1) {
                redisTemplate.expire(key, times.time(), TimeUnit.MILLISECONDS);
            }
            if (count > times.count()) {
                request.setAttribute("ifOvertimes", "true");
                throw new BusinessException(ErrorEnum.OVER_REQUEST_COUNT_ERROR);
            }
        } catch (Exception e) {
            log.error("[overTimes] over requestCount error :{}", e.getMessage());
        }
    }
}

3 测试

@RequestTimes(count = 3, time = 60000)
@GetMapping("/test")
public Result test(HttpServletRequest request) {
    String ipAddr = IpUtils.getIpAddr(request);
    return Result.success(ipAddr);
}

相关标签: # 6 框架