当前位置 博文首页 > Monsterof的博客:Springboot框架防止前台重复提交(锁)

    Monsterof的博客:Springboot框架防止前台重复提交(锁)

    作者:[db:作者] 时间:2021-09-10 18:49

    Springboot–解决重复提交

    防止重复提交,主要是使用锁的形式来处理,如果是单机部署,可以使用本地缓存锁(Guava)即可。

    一、本地锁(Guava)

    1、导入依赖

    <!--本地 缓存锁 -->
    	<dependency>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-aop</artifactId>
    	</dependency>
    	<dependency>
    		<groupId>com.google.guava</groupId>
    		<artifactId>guava</artifactId>
    	</dependency>
    

    2、自定义锁注解

    package org.example.common.tool;
    
    import java.lang.annotation.*;
    
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    public @interface LocalLock {
    
    	String key() default "";
    	//过期时间,使用本地缓存可以忽略,如果使用redis做缓存就需要
    	int expire() default 5;
    }
    

    3、锁注解实现

    package org.example.common.tool;
    
    import com.google.common.cache.Cache;
    import com.google.common.cache.CacheBuilder;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springblade.core.tool.api.R;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.util.StringUtils;
    
    import java.lang.reflect.Method;
    import java.util.concurrent.TimeUnit;
    
    @Aspect
    @Configuration
    public class LockMethodInterceptor {
    
    	//定义缓存,设置最大缓存数及过期日期
    	private static final Cache<String,Object> CACHE = CacheBuilder.newBuilder().maximumSize(1000).expireAfterWrite(20, TimeUnit.SECONDS).build();
    
    	@Around("execution(public * *(..))  && @annotation(org.springblade.common.tool.LocalLock)")
    	public Object interceptor(ProceedingJoinPoint joinPoint){
    		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    		Method method = signature.getMethod();
    		LocalLock localLock = method.getAnnotation(LocalLock.class);
    		String key = getKey(localLock.key(),joinPoint.getArgs());
    		if(!StringUtils.isEmpty(key)){
    			if(CACHE.getIfPresent(key) != null){
    				return R.fail("请勿重复请求!");
    			}
    			CACHE.put(key,key);
    		}
    		try{
    			return joinPoint.proceed();
    		}catch (Throwable throwable){
    			throw new RuntimeException("服务器异常!");
    		}finally {
    
    		}
    	}
    
    	private String getKey(String keyExpress, Object[] args){
    		for (int i = 0; i < args.length; i++) {
    			keyExpress = keyExpress.replace("arg[" + i + "]", args[i].toString());
    		}
    		return keyExpress;
    	}
    
    }
    

    4、Controller层

    	@ResponseBody
        @ApiOperation(value="防重复提交验证测试")
        @LocalLock(key = "localLock:test:arg[0]")
        @PostMapping(value = "/localLock", consumes = {"application/json"})
        public String localLock(String name){
            return "返回成功!";
        }
    

    5、测试
    第一次请求
    重复请求

    6、结束语

    希望能帮助大家,谢谢支持!

    cs
    下一篇:没有了