一、前言
书接上回,上次实现了springboot整合redis,在使用过程中就避免不了重复提交的场景。springboot整合redis_crazyK.的博客-CSDN博客
重复提交的场景:
- 用于用户误操作,多次点击表单提交按钮
- 由于网速等原因造成页面卡顿,用户重复刷新提交页面
- 恶用户如利用postman等工具重复恶意提交表单
为了防止以上情况的出现需要自定义一个注解来完成防止重复提交操作
二、实现
1.创建一个注解
/**
* 自定义注解防止表单重复提交
*/
@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeatSubmit {
int lockTime() default 5;
}
2.创建Http请求工具类,用于在切面时获取token使用
public class HttpContextUtils {
public static HttpServletRequest httpServletRequest(){
return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
}
}
3.项目中加入SpringAop依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
4.创建切面,将切点注册为自定义的注解,唯一表示采用接口url+token的形式,户每发起第一次添加请求,会经过界面,在切面获取信息后组装起来存入Redis,当用户后续发起请求时,首先判断Redis中是否缓存了这个key,如果缓存了,则证明已经提交,于是反馈给前端,如果不存在,证明没有提交,则存入Redis。
@Component
@Aspect
public class NoRepeatSubmitAspect {
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@Pointcut("@annotation(repeatSubmit)")
public void pointcutNoRepeat(NoRepeatSubmit repeatSubmit){};
@Around("pointcutNoRepeat(noRepeatSubmit)")
public Object doNoRepeat(ProceedingJoinPoint point, NoRepeatSubmit noRepeatSubmit) throws Throwable {
int i=noRepeatSubmit.lockTime();
HttpServletRequest httpServletRequest = HttpContextUtils.httpServletRequest();
String token = httpServletRequest.getHeader("token");
String url = httpServletRequest.getRequestURL().toString();
String sign = url+"/"+token;
Boolean key=redisTemplate.hasKey(sign);
if (key){
throw new Exception("请勿重复提交");
}
redisTemplate.opsForValue().set(sign,sign,i, TimeUnit.SECONDS);
return point.proceed();
}
}
三、测试
将我们自定义的注解加到对应方法上
先向redis中插入一条key为crazyk,value为csdn的数据
提交成功,然后在向redis中存入相同的数据后端会抛出我们在切面自定义的异常