思路也很簡單,用戶訪問某一接口一般都有唯一標識,前綴+唯一標識+uri存入redis,為了防止死鎖問題,一定要設置該key的有效期我這里是3秒,重復點擊間隔為1秒,用戶點擊沒有key則存入redis,如果存在則判斷時間是否小於間隔時間,小於則返回錯誤提示,大於則重新設置該key到redis。
上代碼!!!
import com.sjyf.gym.exception.BusinessException; import com.sjyf.gym.utils.HttpContextUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; 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.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.Objects; import java.util.concurrent.TimeUnit; @Slf4j @Aspect @Component public class RepeatSubmitAspect { private static final String PREFIX = "repeat:user:"; /** * 防重復點擊間隔時間(毫秒) */ private static final long REPEAT_TIME = 1000; @Resource private RedisTemplate redisTemplate; /** * 切入點 */ @Pointcut("execution(* com.sjyf.gym.*.controller.*.*.*(..))") public void repeat(){} /** * 方法執行前執行 */ @Before("repeat()") public void repeat(JoinPoint point) { // 獲取token String token = HttpContextUtils.getHttpServletRequest().getHeader("Authorization"); if(StringUtils.isBlank(token)){ return; } // 拼接 StringBuilder label = new StringBuilder(PREFIX + token + HttpContextUtils.getHttpServletRequest().getRequestURI()); // 判斷key是否存在 if(redisTemplate.hasKey(label.toString())){ operate(label.toString()); }else { set(label.toString()); } } private void operate(String label) { // 上次提交時間 Long lastTime = Long.valueOf(redisTemplate.opsForValue().get(label).toString()); if(Objects.isNull(lastTime)){ return; } if(System.currentTimeMillis() - lastTime < REPEAT_TIME){ throw new BusinessException("點擊的太快了啦,請慢一點!"); }else { // 限制間隔點擊時間已過,重新設置時間 set(label); } } // 設置key public void set(String label){ redisTemplate.opsForValue().set(label, System.currentTimeMillis(),3, TimeUnit.SECONDS); } }
