自定义注解+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);
}