欢迎访问宙启技术站
智能推送

SpringBoot+Redis怎么实现后端接口防重复提交校验

发布时间:2023-05-16 14:37:24

1. 概述

在日常开发中,为了防止用户重复提交同一个请求,我们需要实现接口防重复提交校验。本文将给出一种使用 SpringBoot Redis 实现后端接口防重复提交校验的方法。

2. 实现思路

我们使用 SpringBoot 创建一个简单的后端项目。当用户发送请求时,我们将用户的请求参数和请求时间戳作为 Redis 的 key,存储到 Redis 中,并设置一定时间过期,这段时间内用户无法进行相同请求。具体实现如下。

3. 代码实现

3.1 添加 Redis 依赖

在 pom.xml 文件中添加 Redis 依赖,我们使用的是 jedis 版本。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.8.1</version>
    </dependency>
</dependencies>

3.2 添加 Redis 配置

在 application.properties 文件中添加 Redis 配置项。

# Redis 配置
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456
spring.redis.database=0

3.3 编写防重复提交校验的注解

我们定义一个 @PreventReSubmit 注解,用来标记需要进行防重复提交校验的接口。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PreventReSubmit {
    /**
     * 重复提交时间间隔(毫秒)
     */
    long interval() default 5000L;
}

3.4 编写防重复提交校验的拦截器

我们编写一个拦截器 PreventReSubmitInterceptor,在用户请求进入控制器方法之前进行拦截。

@Component
public class PreventReSubmitInterceptor extends HandlerInterceptorAdapter {
    @Autowired
    private JedisPool jedisPool;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        Method method = ((HandlerMethod) handler).getMethod();
        PreventReSubmit annotation = method.getAnnotation(PreventReSubmit.class);
        if (annotation == null) {
            return true;
        }

        String key = getKey(request);
        try (Jedis jedis = jedisPool.getResource()) {
            String result = jedis.setex(key, (int) (annotation.interval() / 1000), "0");
            if (!"OK".equals(result)) {
                response.sendError(500, "请勿重复提交同一个请求");
                return false;
            }
        }

        return true;
    }

    /**
     * 获取 Redis key,key 由请求路径和请求参数、请求时间戳组成
     */
    private String getKey(HttpServletRequest request) {
        StringBuilder sb = new StringBuilder(request.getRequestURI());
        Map<String, String[]> map = request.getParameterMap();
        if (map != null && !map.isEmpty()) {
            sb.append("?");
            for (String key : map.keySet()) {
                sb.append(key).append("=").append(Arrays.toString(map.get(key))).append("&");
            }
            sb.deleteCharAt(sb.length() - 1);
        }
        sb.append("_").append(System.currentTimeMillis());

        return sb.toString();
    }
}

3.5 注册拦截器

我们在 WebMvcConfigurerAdapter 中注册编写的拦截器。

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
    @Autowired
    private PreventReSubmitInterceptor preventReSubmitInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(preventReSubmitInterceptor);
        super.addInterceptors(registry);
    }
}

3.6 使用注解进行防重复提交校验

我们在需要进行防重复提交校验的方法上添加 @PreventReSubmit 注解即可。

@PostMapping("/test")
@PreventReSubmit
public String test(@RequestParam String name) {
    return "hello " + name;
}

4. 总结

本文通过使用 SpringBoot Redis 实现后端接口防重复提交校验的方法,给出了一种简单易行的实现方案。在实际开发中,可以根据具体业务需求对此方案进行进一步优化和拓展。