相关文章
本文使用spring-cloud-getway在网关上校验用户是否重复多次点击同一功能
前言
关于redisson对单节点或者集群的redis操作在先前文章中都有描写,不再在本文中赘述。
引入redisson
和常规引入Redisson
非常相似,需要根据自己的spring-boot
版本引入对应的Redisson
版本,但是不一样的是,如果是spring cloud getway
,使用webflux
的话,那么需要排除Redisson
包内部的spring-boot-start-web
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.14.0</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
<exclusion>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-data-23</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-data-22</artifactId>
<version>3.14.0</version>
</dependency>
添加拦截器
以下代码为缩略版代码,非完全代码内容
public class MyFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//此处锁的名称为用户的id加上用户访问的路径,以此来限定同一用户对同一请求的限制
String lockName = map.get("userId").toString()+exchange.getRequest().getURI().getPath();
RLock rLock = redissonClient.getLock(lockName);
try {
boolean res = rLock.tryLock(0, TimeUnit.SECONDS);
if(res) {
// todo something
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
// unlock
rLock.forceUnlock();
}));
} else {
//返回自定义信息
return bufferFactory.wrap("请勿重复点击");
}
}catch (Exception e) {
e.printStackTrace();
//返回自定义的信息,或者接着抛出异常都可以
return bufferFactory.wrap("xxx");
}
}
}
其中需要注意的是在webflux
中,一个请求的接受和返回是异步的,所以我们的请求接受时和返回时是不同的线程在操作,所以我在解锁时使用的方法是forceUnlock()
强制解锁,如果是普通的解锁方式会抛出一样,因为锁的规范中,需要上锁的人才能拥有解锁的资格,如果是不同的线程加锁解锁,则违反这一规定。
还有,文章中的锁命名是通过用户id和访问的路由拼接的,但是访问的路由可能带有参数就会出现?xxx=xxx
这样的参数后缀,如果需要无数这些后缀,同一接口不同参数的多次访问也要控制的话,那么exchange.getRequest().getURI().getPath()
获取到url后还需要对后面的参数截取去除,这一部分文章中没有详细描述截取过程。