后端--防重复提交策略方法

本文探讨了防止后端重复提交的重要性,包括用户误操作、网络延迟和恶意攻击等因素可能导致的数据重复和服务器负载增加。解决方案包括在数据库层面设置唯一键约束以及使用AOP自定义切入实现,通过Redis存储临时标识来阻止重复提交。具体实现中,自定义了防止重复提交的注解,并在AOP切面中检查Redis中的key来拦截重复请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

后端–防重复提交策略方法

原因:

前台操作的抖动,快速操作,网络通信或者后端响应慢,都会增加后端重复处理的概率。
情形

  1. 由于用户误操作,多次点击表单提交按钮。
  2. 由于网速等原因造成页面卡顿,用户重复刷新提交页面。
  3. 黑客或恶意用户使用postman等工具重复恶意提交表单(攻击网站)。
  4. 这些情况都会导致表单重复提交,造成数据重复,增加服务器负载,严重甚至会造成服务器宕机。因此有效防止表单重复提交有一定的必要性。

解决方案:

一:给数据库增加唯一键约束
navicat在这里插入图片描述
这种方法需要在代码中加入捕捉插入数据异常:

 try {
	            // insert
	        } catch (DuplicateKeyException e) {
	            logger.error("user already exist");
	        }

二:使用AOP自定义切入实现
实现原理:

1.自定义防止重复提交标记(@AvoidRepeatableCommit)。   
2.对需要防止重复提交的Congtroller里的mapping方法加上该注解。   
3.新增Aspect切入点,为@AvoidRepeatableCommit加入切入点。 
4.每次提交表单时,Aspect都会保存当前key到reids(须设置过期时间)。   
5.重复提交时Aspect会判断当前redis是否有该key,若有则拦截。
/**
		 * 避免重复提交
		 */
		@Target(ElementType.METHOD)
		@Retention(RetentionPolicy.RUNTIME)
		public @interface AvoidRepeatableCommit {
		
		    /**
		     * 指定时间内不可重复提交,单位秒
		     * @return
		     */
		    long timeout()  default 3 ;
		
		}
/**
		 * 重复提交aop 
		 */
		@Aspect
		@Component
		public class AvoidRepeatableCommitAspect {
		
		    @Autowired
		    private RedisTemplate redisTemplate;
		
		    /**
		     * @param point
		     */
		    @Around("@annotation(com.xwolf.boot.annotation.AvoidRepeatableCommit)")
		    public Object around(ProceedingJoinPoint point) throws Throwable {
		
		        HttpServletRequest request  = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();
		        String ip = IPUtil.getIP(request);
		        //获取注解
		        MethodSignature signature = (MethodSignature) point.getSignature();
		        Method method = signature.getMethod();
		        //目标类、方法
		        String className = method.getDeclaringClass().getName();
		        String name = method.getName();
		        String ipKey = String.format("%s#%s",className,name);
		        int hashCode = Math.abs(ipKey.hashCode());
		        String key = String.format("%s_%d",ip,hashCode);
		        log.info("ipKey={},hashCode={},key={}",ipKey,hashCode,key);
		        AvoidRepeatableCommit avoidRepeatableCommit =  method.getAnnotation(AvoidRepeatableCommit.class);
		        long timeout = avoidRepeatableCommit.timeout();
		        if (timeout < 0){
                                //过期时间5分钟
		            timeout = 60*5;
		        }
		        String value = (String) redisTemplate.opsForValue().get(key);
		        if (StringUtils.isNotBlank(value)){
		            return "请勿重复提交";
		        }
		        redisTemplate.opsForValue().set(key, UUIDUtil.uuid(),timeout,TimeUnit.MILLISECONDS);
		        //执行方法
		        Object object = point.proceed();
		        return object;
		    }
		
		}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值