Java骨灰级码农 2024-06-04 09:55 采纳率: 100%
浏览 39
已结题

SpringBoot接口防抖(防重复提交)的一些实现方案

SpringBoot接口防抖(防重复提交)的一些实现方案
SpringBoot接口防抖(防重复提交)的一些实现方案
SpringBoot接口防抖(防重复提交)的一些实现方案

  • 写回答

2条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-06-04 09:55
    关注

    引自免费微信小程序:皆我百晓生

    在Spring Boot应用中实现接口防抖(防止重复提交)可以通过多种方式来实现。这里提供三种常见的实现方案:基于Redis、基于数据库和基于Spring Cloud Gateway。

    1. 基于Redis 利用Redis的有序集合(Sorted Set)特性来存储请求。当一个新的请求到达时,检查该请求是否已经在有序集合中存在,如果不存在,则添加并设置过期时间,否则忽略该请求。

    首先,确保已经添加了Redis依赖,并配置Redis连接。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    

    然后创建一个配置类,用于配置RedisTemplate:

    @Configuration
    public class RedisConfig {
    
        @Bean
        public LettuceConnectionFactory redisConnectionFactory() {
            return new LettuceConnectionFactory();
        }
    
        @Bean
        public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
            RedisTemplate<String, String> template = new RedisTemplate<>();
            template.setConnectionFactory(factory);
            Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
            ObjectMapper om = new ObjectMapper();
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            jackson2JsonRedisSerializer.setObjectMapper(om);
            template.setValueSerializer(jackson2JsonRedisSerializer);
            template.afterPropertiesSet();
            return template;
        }
    }
    

    接下来,在控制器方法上添加注解,使用AOP进行拦截处理:

    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class DuplicateRequestInterceptor {
    
        private static final String DUPLICATE_REQUEST_KEY_PATTERN = "duplicate_request:%s";
    
        private final StringRedisTemplate stringRedisTemplate;
    
        @Autowired
        public DuplicateRequestInterceptor(StringRedisTemplate stringRedisTemplate) {
            this.stringRedisTemplate = stringRedisTemplate;
        }
    
        @Around("execution(* com.example.yourpackage.controller.YourController.yourMethod(..))")
        public Object preventDuplicateRequests(ProceedingJoinPoint joinPoint) throws Throwable {
            // 获取请求参数,作为唯一标识
            String requestHash = generateRequestHash(joinPoint.getArgs());
            
            long score = System.currentTimeMillis();
    
            // 添加请求到有序集合,如果已存在则返回0
            if (stringRedisTemplate.opsForZSet().add(DUPLICATE_REQUEST_KEY_PATTERN, requestHash, score) == 0) {
                throw new DuplicateRequestException("Duplicate request detected");
            }
    
            // 执行业务逻辑
            return joinPoint.proceed();
        }
    
        private String generateRequestHash(Object[] args) {
            // 根据实际需求生成请求哈希,可以考虑将所有重要参数组合成字符串并进行哈希
            StringBuilder hashBuilder = new StringBuilder();
            for (Object arg : args) {
                hashBuilder.append(arg.toString()).append(",");
            }
            return hashBuilder.toString().hashCode() + "";
        }
    }
    
    1. 基于数据库 使用数据库的唯一索引来防止重复插入。每次发送请求时,先查询数据库,如果数据已存在则忽略请求,否则执行操作并插入数据。

    2. 基于Spring Cloud Gateway 如果你的应用使用了Spring Cloud Gateway,可以在网关层实现防抖。可以编写一个GatewayFilterFactory,实现对请求的拦截和判断。

    import org.springframework.cloud.gateway.filter.GatewayFilter;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.http.server.reactive.ServerHttpRequest;
    import org.springframework.web.server.ServerWebExchange;
    
    public class DuplicateRequestGatewayFilterFactory implements GatewayFilterFactory<DuplicateRequestGatewayFilterFactory.Config> {
    
        @Override
        public GatewayFilter apply(Config config) {
            return (exchange, chain) -> {
                ServerHttpRequest request = exchange.getRequest();
                
                // 获取请求参数,作为唯一标识
                String requestHash = generateRequestHash(request);
    
                // 检查请求是否已在数据库中
                boolean isDuplicate = checkDuplicateInDatabase(requestHash);
    
                if (isDuplicate) {
                    throw new DuplicateRequestException("Duplicate request detected");
                }
    
                return chain.filter(exchange);
            };
        }
    
        private String generateRequestHash(ServerHttpRequest request) {
            // 实现根据请求头或请求体生成哈希的方法
        }
    
        private boolean checkDuplicateInDatabase(String requestHash) {
            // 在数据库中检查请求是否存在
        }
    
        public static class Config {}
    }
    

    别忘了在Spring Cloud Gateway的配置文件中注册这个过滤器。

    这些方法都可以有效地防止重复提交,具体选择哪种取决于你的项目需求和技术栈。注意,无论选择哪种方案,都需要考虑幂等性以及如何处理并发场景下的竞态条件。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 6月12日
  • 已采纳回答 6月4日
  • 创建了问题 6月4日

悬赏问题

  • ¥15 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题
  • ¥15 如何用Python爬取各高校教师公开的教育和工作经历
  • ¥15 TLE9879QXA40 电机驱动
  • ¥20 对于工程问题的非线性数学模型进行线性化
  • ¥15 Mirare PLUS 进行密钥认证?(详解)
  • ¥15 物体双站RCS和其组成阵列后的双站RCS关系验证
  • ¥20 想用ollama做一个自己的AI数据库
  • ¥15 关于qualoth编辑及缝合服装领子的问题解决方案探寻
  • ¥15 请问怎么才能复现这样的图呀