1.思路
当请求的时候,直接根据 token(或者其他标识) 请求信息(自定义)= 唯一的 key 然后把这个 key 存储在 cache 中 借助 guava 的 key 过期,redis 的自动过期、数据库的过期
2.操作流程
1.获取唯一标识符(例如在登录时返回的token) 2.发起请求(携带token进行访问) 3.在进入请求之前进行处理 3.1 根据token获取缓存中的数据 3.2 判断数据是否存在,如果不存在访问则放行,存在数据则终止请求 3.3 放行后把访问的令牌和访问路径放入缓存中
3.代码
代码语言:javascript复制依赖库
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.6.8</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
代码语言:javascript复制1.创建注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RepeatSubmit {
/**
* 重复提交间隔时间
*/
int time() default 3000;
String msg() default "请勿重复提交";
}
代码语言:javascript复制创建访问的资源路径
@RestController
@RequestMapping("/order")
public class OrderController {
@GetMapping("/login")
public String login(String username, String password) {
Assert.isTrue("admin".equals(username) && "admin".equals(password), "用户名或密码错误");
return UUID.randomUUID().toString();
}
@RepeatSubmit(time = 5000)
@GetMapping("/createOrder")
public String createOrder() {
return "order:" UUID.randomUUID();
}
}
代码语言:javascript复制创建AOP切面类
@Slf4j
@Component
@Aspect
public class RepeatSubmitAspect {
private static final String TOKEN = "token";
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Around("@annotation(repeatSubmit)")
private Object doAround(ProceedingJoinPoint joinPoint, RepeatSubmit repeatSubmit) {
HttpServletRequest request = Objects.requireNonNull(getRequestAttributes()).getRequest();
// 获取访问路径
String uri = request.getRequestURI();
// 获取唯一标识符
String token = request.getParameter(TOKEN);
//获取缓存中的数据
String value = redisTemplate.opsForValue().get(token);
//判断缓存中是否存在
if (uri.equals(value)) {
return repeatSubmit.msg();
} else {
//不存在,放行请求,并设置缓存
redisTemplate.opsForValue().set(token, uri, repeatSubmit.time(), TimeUnit.MILLISECONDS);
}
Object proceed = null;
try {
proceed = joinPoint.proceed();
} catch (Throwable e) {
throw new RuntimeException(e);
}
return proceed;
}
public static ServletRequestAttributes getRequestAttributes() {
try {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return (ServletRequestAttributes) attributes;
} catch (Exception e) {
return null;
}
}
}