返回
SpringBoot自定义注解+AOP防止重复提交(保姆级教程,建议收藏)
后端
2023-12-08 12:02:24
前言
在实际开发中,我们经常会遇到这样的场景:用户连续点击按钮,导致后端接口被重复调用,从而产生重复的数据。这不仅会给数据库带来压力,还会给业务逻辑带来混乱。为了防止这种情况的发生,我们需要对接口进行防重复提交处理。
重复提交产生的原因
重复提交产生的原因有很多,主要有以下几种:
- 网络延迟: 在网络延迟的情况下,用户可能会在一段时间内连续点击按钮,导致后端接口被重复调用。
- 页面卡顿: 如果页面的加载速度较慢,用户可能会在页面卡顿的情况下连续点击按钮,导致后端接口被重复调用。
- 浏览器缓存: 如果浏览器的缓存策略不当,可能会导致用户在刷新页面后再次提交表单,从而导致后端接口被重复调用。
- 恶意攻击: 恶意攻击者可能会利用工具或脚本对接口进行重复提交攻击,从而导致后端接口被重复调用。
SpringBoot如何防止重复提交
SpringBoot提供了多种方法来防止重复提交,主要有以下几种:
- 分布式锁: 使用分布式锁可以保证在同一时刻只有一个请求能够访问资源,从而防止重复提交。
- 乐观锁: 乐观锁通过在数据表中添加一个版本号字段来实现并发控制,从而防止重复提交。
- Idempotency: Idempotency是指接口在被多次调用时,其结果是一致的。通过实现接口的Idempotency,可以防止重复提交。
自定义注解+AOP实现防止重复提交
在SpringBoot中,我们可以通过自定义注解+AOP的方式来实现接口的防重复提交。具体步骤如下:
- 定义自定义注解
@PreventRepeatSubmit
:
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PreventRepeatSubmit {
// 过期时间,单位:秒
long expireTime() default 60;
}
- 定义AOP切面:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.UUID;
@Aspect
@Component
public class PreventRepeatSubmitAspect {
@Pointcut("@annotation(com.example.demo.annotation.PreventRepeatSubmit)")
public void pointcut() {
}
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String token = request.getHeader("token");
if (token == null) {
throw new RuntimeException("请求头中没有token");
}
// 从缓存中获取该token对应的过期时间
long expireTime = redisTemplate.getExpire(token);
if (expireTime <= 0) {
throw new RuntimeException("token已过期");
}
// 生成新的token
String newToken = UUID.randomUUID().toString();
// 将新的token和过期时间放入缓存
redisTemplate.opsForValue().set(newToken, expireTime, expireTime, TimeUnit.SECONDS);
// 将新的token放入请求头中
request.setAttribute("token", newToken);
}
}
- 在需要防止重复提交的接口上添加
@PreventRepeatSubmit
注解:
@RestController
@RequestMapping("/api")
public class TestController {
@PreventRepeatSubmit
@PostMapping("/test")
public String test() {
// 业务逻辑
return "success";
}
}
总结
通过自定义注解+AOP的方式,我们可以轻松实现SpringBoot接口的防重复提交。这种方式简单易用,而且可以与其他防重复提交方式结合使用,从而实现更安全的防重复提交机制。