【基于SpringBoo防止接口重复提交代码示例】

468 阅读2分钟

基于Spring Boot防止接口重复提交代码示例

在现代Web应用中,防止接口重复提交是一个常见的需求,尤其是在处理表单提交或敏感操作时。本文将介绍几种在Spring Boot中实现接口防重复提交的方法,并提供相应的代码示例。

1. 使用Token机制

1.1 引入Redis依赖

首先,需要在项目的pom.xml文件中添加Redis依赖:

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

1.2 生成Token

在Controller中生成Token并存储在Redis中:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import java.util.UUID;

@RestController
public class TokenController {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @GetMapping("/formByRedis")
    public ModelAndView showFormByRedis() {
        ModelAndView form = new ModelAndView("form");
        String token = UUID.randomUUID().toString();
        // 设置过期时间为5分钟
        redisTemplate.opsForValue().set(token, token, 5, TimeUnit.MINUTES);
        form.addObject("token", token);
        return form;
    }
}

1.3 传递Token

在表单中添加隐藏字段来传递Token:

<form action="/base/submitByRedis" method="post">
    <input type="hidden" name="token" th:value="${token}">
    <!-- 其他表单字段 -->
    <button type="submit">Submit</button>
</form>

1.4 验证Token

在Controller中验证Token:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

@PostMapping("/submitByRedis")
public String handleFormByRedis(@RequestParam String token) {
    String redisToken = redisTemplate.opsForValue().get(token);
    if (redisToken == null) {
        throw new RuntimeException("Duplicate submit detected");
    }
    // 删除Token
    redisTemplate.delete(token);
    // 处理表单数据
    return "success";
}

2. 使用Spring AOP

Spring AOP可以用来实现切面编程,从而在多个方法中复用防重复提交的逻辑。

2.1 创建切面

创建一个切面类DuplicateSubmitAspect

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DuplicateSubmitAspect {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Around("@annotation(preventDuplicateSubmit)")
    public Object around(ProceedingJoinPoint joinPoint, PreventDuplicateSubmit preventDuplicateSubmit) throws Throwable {
        StringBuilder key = new StringBuilder();
        // 获取class
        String simpleName = joinPoint.getTarget().getClass().getSimpleName();
        key.append(simpleName);
        // 获取请求方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getName();
        key.append(":").append(methodName);
        // 获取请求参数
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            key.append(":").append(arg.toString());
        }
        // 判断是否已经请求过
        if (redisTemplate.hasKey(key.toString())) {
            throw new RuntimeException("请勿重复提交");
        }
        // 标记请求已经处理过
        redisTemplate.opsForValue().set(key.toString(), "1", preventDuplicateSubmit.expireSeconds(), TimeUnit.SECONDS);
        return joinPoint.proceed();
    }
}

2.2 使用注解

在Controller方法上使用@PreventDuplicateSubmit注解:

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AnnotationController {

    @PostMapping("/submitByAnnotation")
    @PreventDuplicateSubmit
    public String handleFormByAnnotation(@RequestParam String param) {
        // 处理表单数据
        return "success";
    }
}

3. 总结

本文介绍了两种在Spring Boot中实现接口防重复提交的方法:使用Token机制和使用Spring AOP。每种方法都有其适用场景和优缺点,可以根据实际需求选择合适的方法。通过这些方法,可以有效防止用户重复提交表单,提高系统的稳定性和用户体验。