为甚么要处理重复提交呢?
1. 客户端的抖动,用户误操作,网络通信或者服务器响应慢,都有可能会造成服务器重复处理请求。
2. 为了防止用户重复提交操作,除了从前端控制,后台也需要做控制。
3. 因为前端的限制不能解决彻底[有时候通过一定的手段可以绕过去]。
4. 接口实现上,通常要求幂等性,保证多次重复提交只有一次有效。简单说,针对同一笔交易,多次请求它的结果应该是一致的。
实现:
1. 定义防重复提交注解
/**
* Created with IntelliJ IDEA.
* @Author: zhaoxn
* @Date: 2022/11/14/22:43
* @Description:方法重复提交注解 默认2s内不允许重复调用
* 也可以支持注解里添加属性,自定义时间间隔,单位(s)
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeatSubmit {
//超时时间 2s
long expireSecond() default 2;
}
2. 定义切面逻辑 ,针对加了NoRepeatSubmit注解的方法,做防重复提交判断。
/**
* Created with IntelliJ IDEA.
* @Author: zhaoxn
* @Date: 2022/11/14/22:48
* @Description:防重复提交切面
*/
@Aspect
@Slf4j
@Component
@Order(-999)
public class NoRepeatSubmitAspect {
@Autowired
private RedisTemplate redisTemplate;
//定义防重复提交key
public static final String NO_REPEAT_SUBMIT_KEY = "common:noRepeatSubmit:";
@Around("@annotation(noRepeatSubmit)")
public Object around(ProceedingJoinPoint pj,NoRepeatSubmit noRepeatSubmit) throws Throwable {
Object[] args = pj.getArgs();
String phoneSeries = "3WEPROI2947SDF2340ASDFS4928034"; //这里是假设从args中获取得到客户端送过来的设备唯一标识,实际需要根据场景自定义
MethodSignature msig = (MethodSignature) pj.getSignature();
String mName = pj.getTarget().getClass().getMethod(msig.getName(), msig.getParameterTypes()).getName();
if(StringUtils.isNotEmpty(phoneSeries)){ //这里有可能设备号是空的,比如是三方系统过来的请求
Boolean hasKey = redisTemplate.hasKey(NO_REPEAT_SUBMIT_KEY + phoneSeries);
if(null != hasKey && hasKey){
throw new RuntimeException("您的操作过于频道,请稍等一会!!!");//这里实际应该抛出的是业务异常返给客户端
}
redisTemplate.opsForValue().set(NO_REPEAT_SUBMIT_KEY + phoneSeries,"NO_REPEAT_SUBMIT_KEY",noRepeatSubmit.expireSecond(), TimeUnit.SECONDS);
}else{
log.warn("当前方法:{}未获取到对应的设备序列号",mName);
}
return pj.proceed();
}
}
3. 完结