Sping boot AOP防重复提交

本文介绍了一种自定义的防止重复提交的AOP实现,通过在Controller方法上添加@AvoidRepeatableCommitAspect注解,利用Redis进行临时存储来避免重复提交。在AOP切面中,当检测到相同key的存在时,将阻止请求的执行,从而实现重复提交的防护。此外,还展示了相关XML配置和实际的注解使用示例。
摘要由CSDN通过智能技术生成

实现原理

  1. 自定义防止重复提交标记(@AvoidRepeatableCommitAspect)。
  2. 对需要防止重复提交的Congtroller里的mapping方法加上该注解。
  3. 新增Aspect切入点,为@AvoidRepeatableCommitAspect加入切入点。
  4. 每次提交表单时,Aspect都会保存当前key到reids(须设置过期时间)。
  5. 重复提交时Aspect会判断当前redis是否有该key,若有则拦截。

代码

AvoidRepeatableCommitAspect代码


import java.lang.annotation.*;

/**
 * 权限注解 用于放置表达重复提交
 *	该方法会从 request中取 avoidRepeatableValue 的 值 
 *	该值 未判断是否为重复提交的判断因素 当不同方法为统一逻辑时 
 *	使用 avoidRepeatableValue 判断
 *	如果防止同一方法重复 则 avoidRepeatableValue 可不传 以sissionId为唯一判断值
 *	key为方法值 当两方法为同一逻辑时 判断是否重复提交两方法 key值必填 为判断索引值
 *	如果防止同一方法重复 则 key可以不传 以方法地址+方法名 做唯一判断值  
 * @example @AvoidRepeatableCommitAspect

 */
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface AvoidRepeatableCommitAspect {
    String value() default "";
}
AvoidRepeatableCommitAspectAop代码


import cn.stylefeng.roses.core.util.HttpContext;
import cn.stylefeng.roses.kernel.model.exception.ServiceException;
import com.alibaba.druid.util.StringUtils;
import ....annotion.AvoidRepeatableCommitAspect;
import ....constant.cache.Cache;
import ....exception.BizExceptionEnum;
import ...util.CacheUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * 防止重复提交的aop
 */
@Aspect
@Component
@Order(200)
public class AvoidRepeatableCommitAspectAop {


    @Pointcut(value = "@annotation(com.mifu.core.common.annotion.AvoidRepeatableCommitAspect)")
    private void avoidRepeatableCommitAspect() {

    }

    @Around("avoidRepeatableCommitAspect()")
    public Object doAvoidRepeatableCommitAspect(ProceedingJoinPoint point) throws Throwable {
    	//获取拦截的方法名
        Signature sig = point.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Object target = point.getTarget();
        Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
        String methodName = currentMethod.getDeclaringClass().getName()+"."+currentMethod.getName();
        //获取操作key及value
        AvoidRepeatableCommitAspect avoidRepeatableCommitAspect = currentMethod.getAnnotation(AvoidRepeatableCommitAspect.class);
        String key = avoidRepeatableCommitAspect.value();
        
        //如果传的KEY值不存在 取该方法名判断
        if(StringUtils.isEmpty(key)){
        	key = methodName;
        }
        
        String value = "";
        
        Map<String, String> ht =  HttpContext.getRequestParameters();
        
        //如果传的avoidRepeatableValue值不存在 等于未做多方法防重提交判断 使用session做防重判断
        if(ht!=null && ht.get("avoidRepeatableValue") != null && !StringUtils.isEmpty(ht.get("avoidRepeatableValue").toString())){
        	value = ht.get("avoidRepeatableValue").toString();
        }else{
        	value = HttpContext.getRequest().getSession().getId();
        }
        
        String result = key + "-" + value;
        
        //缓存查询返回值
        Object reslt;
        
        //------------------判断该值是否存在Map中------------------------------
        try {
        	reslt = CacheUtil.get(Cache.REPEATSSUBMIT, result);
		} catch (Exception e) {
			e.printStackTrace();
			return point.proceed();
		}
        
        
        
        if(reslt != null){
        	//如果存在 抛出重复提交异常
        	throw new ServiceException(BizExceptionEnum.REPEATABLE_COMMIT);
        }else{
        	try {
        		CacheUtil.put(Cache.REPEATSSUBMIT, result, "success");
        	}catch (Exception e) {
				e.printStackTrace();
			}
        	return point.proceed();
        }    
        
    }

}

.xml代码

 <!-- 防重复提交变量:5秒过期-->
    <cache name="REPEATSSUBMIT"
           maxElementsInMemory="50000"
           eternal="false"
           clearOnFlush="true"
           overflowToDisk="false"
           timeToIdleSeconds="3"
           timeToLiveSeconds="6"
           diskSpoolBufferSizeMB="1024"
           maxElementsOnDisk="100000"
           diskPersistent="false"
           diskExpiryThreadIntervalSeconds="120"
           memoryStoreEvictionPolicy="LFU"
           transactionalMode="off">
    </cache>

调用

@AvoidRepeatableCommitAspect(value = "..")
"avoidRepeatableValue":"...",

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值