欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 旅游 > springBoot 限制重复提交

springBoot 限制重复提交

2025/4/22 22:26:59 来源:https://blog.csdn.net/Gemini1995/article/details/141686692  浏览:    关键词:springBoot 限制重复提交

在使用 AOP 和 Redis 结合的方式来限制不同用户短时间内不可重复调用相同接口时,可以通过在 Redis 中存储用户请求的唯一标识来实现。每次用户请求某个接口时,通过用户ID和接口的唯一标识符组合生成一个键,判断该键是否存在于 Redis 中,从而决定是否处理该请求。

下面是一个基于 Spring AOP 和 Redis 的优化实现。

1. 定义自定义注解

首先,定义一个自定义注解 PreventDuplicateSubmit,用于标记需要限制重复提交的接口。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PreventDuplicateSubmit {long timeout() default 5000; // 超时时间,单位毫秒
}

2. 创建 AOP 切面类

通过 AOP 来拦截带有 PreventDuplicateSubmit 注解的方法,使用 Redis 来检查和控制请求的重复提交。

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.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;@Aspect
@Component
public class PreventDuplicateSubmitAspect {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Around("@annotation(preventDuplicateSubmit)")public Object preventDuplicateSubmit(ProceedingJoinPoint joinPoint, PreventDuplicateSubmit preventDuplicateSubmit) throws Throwable {// 获取用户ID或其他唯一标识String userId = getCurrentUserId(); // 需要实现获取当前用户ID的方法String methodName = joinPoint.getSignature().toShortString();String redisKey = "duplicate_submit:" + userId + ":" + methodName;// 尝试在Redis中设置键,使用SETNX实现锁Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(redisKey, "1", preventDuplicateSubmit.timeout(), TimeUnit.MILLISECONDS);if (Boolean.FALSE.equals(success)) {return new ResponseEntity<>("重复提交", HttpStatus.BAD_REQUEST);}try {// 执行被拦截的方法return joinPoint.proceed();} finally {// 可选:清理redisKey,取决于业务场景// stringRedisTemplate.delete(redisKey);}}// 获取当前用户ID的实现,可以根据具体需求获取private String getCurrentUserId() {// 这里假设使用Spring Security的上下文获取当前用户ID// return SecurityContextHolder.getContext().getAuthentication().getName();// 或者从请求上下文中获取,如:从HttpServletRequest中获取token解析用户IDreturn "testUserId"; // 示例返回,实际应根据项目情况实现}
}

3. 在控制器中使用自定义注解

在需要限制重复提交的接口上添加 @PreventDuplicateSubmit 注解。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class MyController {@PreventDuplicateSubmit(timeout = 10000) // 设置10秒内不可重复提交@GetMapping("/submit")public String handleSubmit() {// 处理逻辑return "提交成功";}
}

4. 配置 Redis

确保 Redis 配置正确,Spring Boot 项目中可以在 application.propertiesapplication.yml 中进行配置:

spring:redis:host: localhostport: 6379# 可根据实际情况配置其他参数,如密码、连接池配置等

总结

  • 注解:定义了一个 @PreventDuplicateSubmit 注解,用于标记需要限制重复提交的方法,并指定超时时间。
  • AOP 切面:使用 AOP 拦截带有该注解的方法,通过 Redis 存储用户请求的唯一标识符来控制短时间内的重复提交。使用 setIfAbsent 实现分布式锁,避免多实例环境下的并发问题。
  • Redis 维护:在请求处理后,如果不需要长期保持,可以选择性地删除 Redis 中的键。
  • 用户标识:需要实现获取当前用户唯一标识的方法,可以基于安全框架或其他认证方式。

这样做不仅可以有效地限制重复提交,还可以应对分布式部署的场景,并且易于扩展和维护。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词