Spring Cloud Getway整合Redisson分布式锁,微服务校验用户重复多次点击

相关文章

本文使用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后还需要对后面的参数截取去除,这一部分文章中没有详细描述截取过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值