首页 > 文章列表 > Java如何限制前端重复请求

Java如何限制前端重复请求

java
383 2023-05-05

Java如何限制前端重复请求

背景及用途

前端页面出现卡顿,用户反复点击操作按钮,导致后台接口短时间内多次提交

实现步骤

设置切面,增加注解,导致在规定时间内该接口不可重复调用

设置一个接口 NoRepeatSubmit

import java.lang.annotation.*;

/**

 * xzj_2022_8_2

 * 重复请求限制切面

 */

@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上

@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行

@Documented //生成文档

public @interface NoRepeatSubmit {

    String name() default "name:";

}

实现类

import java.lang.annotation.*;

/**

 * xzj_2022_8_2

 * 重复请求限制切面

 */

@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上

@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行

@Documented //生成文档

public @interface NoRepeatSubmit {

    String name() default "name:";

}

使用

    @GetMapping(value = "/test")

    @NoRepeatSubmit

    public void test() {

        System.out.println("test");

        }

补充:下面看下java防止前端重复提交

JAVA利用自定义本地锁解决重复提交的问题

1.引入jar包

<dependency>

            <groupId>com.google.guava</groupId>

            <artifactId>guava</artifactId>

            <version>31.1-jre</version>

        </dependency>

2.自定义本地锁

package com.hzt.listener;

import java.lang.annotation.*;

/**

 * 自定义-控制重复提交锁

 */

@Target(ElementType.METHOD)     //作用于方法

@Retention(RetentionPolicy.RUNTIME)     //运行时有效

@Documented

@Inherited

public @interface LocalLock {



    String key() default "";

}

3.自定义注解切面 (aop拦截器实现)

import com.google.common.cache.Cache;

import com.google.common.cache.CacheBuilder;

import org.apache.commons.lang3.StringUtils;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.context.annotation.Configuration;



import java.util.concurrent.TimeUnit;



/**

 * @Desc: 自定义注解拦截器

 * @Author: zmk

 * @Date: 2022/4/2

 */

@Aspect

@Configuration

public class LockMethodInterceptor {

    private final Logger log = LoggerFactory.getLogger(LockMethodInterceptor.class);





    private static final Cache<String, Object> CACHES = CacheBuilder.newBuilder()

            //最大缓存数

            .maximumSize(1000)

            //设置过期时间

            .expireAfterWrite(3, TimeUnit.SECONDS)

            .build();







    @Around(value = "@annotation(localLock)")

    public Object interceptor (ProceedingJoinPoint point, LocalLock localLock) {



        //localLock.key() 这个是获取controller的key属性, point.getArgs()获取key的值

        String key = getKey(localLock.key(), point.getArgs());

        if (StringUtils.isNotBlank(key)) {

            if (CACHES.getIfPresent(key) != null) {

                throw new RuntimeException("请勿重复提交");

            }

            //如果是第一次请求, 将key放入缓存

            CACHES.put(key, key);

        }



        try {

            return point.proceed();

        } catch (Throwable throwable) {

            throw new RuntimeException("服务器异常");

        } finally {

            //标记为无效

//            CACHES.invalidate(key);

        }



    }

    

    /**

     *

     * key 生成策略

     * @param key   key表达式

     * @param args  参数

     * @return  生成的key

     */

    private String getKey(String key, Object[] args) {

        for (int i = 0; i < args.length; i++) {

            key = key.replace("arg[" + i + "]", args[i].toString());

        }

        return key;

    }

4.定义controller接口

	@GetMapping("/query")

    @LocalLock(key = "param:arg[0]")

    public String query (@RequestParam("abc") String abc) {

        return "ok";

    }

第一次调用结果:

第二次调用结果: