说明:实际开发中,我们在前端页面上点击了一个按钮,访问了一个接口,这时因为网络波动或者其他原因,页面上没有反应,用户可能会在短时间内再次点击一次或者用户以为没有点到,很快的又点了一次。导致短时间内发送了两个请求到后台,可能会导致数据重复添加。
为了避免短时间内对一个接口访问,我们可以通过AOP+自定义注解+Redis的方式,在接口上加一个自定义注解,然后通过AOP的前置通知,在Redis中存入一个有效期的值,当访问接口时这个值还未过期,则抛出异常,以此来避免短时间内对接口的方法。
实现
第一步:创建一个自定义注解,设置两个属性,一个是key,一个是这个key在Redis中的有效时间;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LimitAccess {
String key();
int times();
}
第二步:创建对应的Aspect;
import com.hezy.annotation.LimitAccess;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
@Aspect
public class LimitAspect {
@Autowired
private RedisTemplate redisTemplate;
@Pointcut("@annotation(com.hezy.annotation.LimitAccess)")
public void pt(){};
@Around("pt()")
public Object aopAround(ProceedingJoinPoint pjp) throws Throwable {
Signature signature = pjp.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
LimitAccess limitAccess = methodSignature.getMethod().getAnnotation(LimitAccess.class);
int limit = limitAccess.times();
String key = limitAccess.key();
Object o = redisTemplate.opsForValue().get(key);
if (o == null) {
redisTemplate.opsForValue().set(key, "", limit, TimeUnit.SECONDS);
return pjp.proceed();
} else {
throw new RuntimeException("访问过于频繁");
}
}
}
第三步:在需要限制的接口上,加上这个注解,并设置key和限制访问时间,如下这个这个接口,设置key为set,实际开发中可以设置一个随机值,或者按照规则自定义设置,times为限制访问时间;
@GetMapping("/limit")
@LimitAccess(key = "limit", times = 10)
public String limit() {
return "success";
}
演示
启动项目,访问该接口;
(首次访问,没得问题,同时在Redis中存入值)

(短时间内,连续访问,因为Redis中值未过期)


(10秒之后再访问,又可以了,Redis中的值过期了)

以上就是使用Redis实现接口防抖,避免短时间内连续访问接口。实际开发中,可以将异常设置为自定义异常。