前言
关于恶意访问的锁在上一篇文章中实现了【(SpringBoot中如何使用注解方式拦截恶意访问的IP)[./259988aa]】
这里依旧使用Redis锁
,通过自定义注解
的方式进行拦截,方便重复调用使用。
Redis
的配置需要自行配置
后端代码
依赖引入 pom.xml和 yml配置文件中配置Redis
1 2 3 4 5
| <!-- redis 缓存操作 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| spring: redis: host: 127.0.0.1 port: 6379 database: 0 password: 123456 timeout: 10s lettuce: pool: min-idle: 0 max-idle: 8 max-active: 8 max-wait: -1ms
|
RedisTemplateConfig配置类
添加这个配置类,防止存Redis
的时候key
或value
乱码
拦截部分
自定义注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import java.lang.annotation.*;
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface PreventRepeatClick {
String name();
String key();
long time() default 3;
String msg() default "系统繁忙,请稍后再试!"; }
|
拦截恶意访问接口 - 逻辑处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| 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.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.lang.reflect.Field;
@Aspect @Component public class PreventRepeatClickAspect {
private final Logger logger = LoggerFactory.getLogger(PreventRepeatClickAspect.class);
@Autowired private RedissonClient redissonClient;
@Pointcut("@annotation(preventRepeatClick)") public void preventRepeatClickPointcut(PreventRepeatClick preventRepeatClick) {}
@Before("preventRepeatClickPointcut(preventRepeatClick)") public void handleRepeatClick(JoinPoint joinPoint, PreventRepeatClick preventRepeatClick) throws Throwable { String name = preventRepeatClick.name(); String key = preventRepeatClick.key(); long time = preventRepeatClick.time(); String msg = preventRepeatClick.msg(); Object[] args = joinPoint.getArgs(); Object keyValue = null; for (Object arg : args) { if (arg != null) { if (arg instanceof Integer || arg instanceof String) { keyValue = arg; break; } else { try { Field field = arg.getClass().getDeclaredField(key); field.setAccessible(true); keyValue = field.get(arg); break; } catch (NoSuchFieldException | IllegalAccessException e) { logger.error("关键参数缺失: {}", key); throw new IllegalArgumentException("关键参数缺失: " + key, e); } } } } if (keyValue == null) { logger.error("关键参数缺失"); throw new IllegalArgumentException("关键参数缺失"); } String lockKey = name + ":" + keyValue.toString(); RLock lock = redissonClient.getLock(lockKey); boolean lockAcquired = lock.tryLock(0, time, java.util.concurrent.TimeUnit.SECONDS); if (!lockAcquired) { throw new RuntimeException(msg); } } }
|
Controller接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; @Controller public class TestController {
@PreventRepeatClick(name = "RepeatClickLock:addUserInfo", key = "phone", time = 3, msg = "请勿重复提交") @ResponseBody @GetMapping("/addUserInfo) public String addUserInfo() { return “SUCCESS; } }
|
测试