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

相关文章

  • SpringBoot整合Redisson操作单节点Redis
  • SpringBoot整合Redisson操作集群redis

本文使用spring-cloud-getway在网关上校验用户是否重复多次点击同一功能

前言

关于redisson对单节点或者集群的redis操作在先前文章中都有描写,不再在本文中赘述。

引入redisson

和常规引入Redisson非常相似,需要根据自己的spring-boot版本引入对应的Redisson版本,但是不一样的是,如果是spring cloud getway,使用webflux的话,那么需要排除Redisson包内部的spring-boot-start-web

<dependency>
    <groupId>org.redissongroupId>
    <artifactId>redisson-spring-boot-starterartifactId>
    <version>3.14.0version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        exclusion>
        <exclusion>
            <groupId>org.redissongroupId>
            <artifactId>redisson-spring-data-23artifactId>
        exclusion>
    exclusions>
dependency>

<dependency>
    <groupId>org.redissongroupId>
    <artifactId>redisson-spring-data-22artifactId>
    <version>3.14.0version>
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后还需要对后面的参数截取去除,这一部分文章中没有详细描述截取过程。

你可能感兴趣的:(学习笔记,java,spring,getway,redisson)